kerneltest/f32test/bench/t_trimbm.cpp
changeset 287 ddfd5aa0d58f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/bench/t_trimbm.cpp	Mon Oct 11 19:11:06 2010 +0100
@@ -0,0 +1,875 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32test/bench/t_fsysbm.cpp
+//
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <f32file.h>
+#include <e32test.h>
+#include <e32hal.h>
+#include <hal.h>
+#include <e32math.h>
+#include <e32ldr.h>
+#include <e32ldr_private.h>
+#include "t_server.h"
+#include "../../e32test/mmu/d_sharedchunk.h"
+#include "../../e32utils/pccd/d_mmcif.h"
+
+#define SYMBIAN_TEST_EXTENDED_BUFFER_SIZES	// test using a greater number of buffer sizes
+
+RTest test(_L("eMMC 4.4 TRIM Benchmark"));
+
+static const TUint K1K = 1024;								// 1K
+static const TUint K1M = K1K * K1K  ;						// 1M
+static const TUint K2M = 2 * K1M;						    // 2M
+
+
+#if defined(__WINS__)
+static TInt KMaxFileSize = 256 * K1K;					// 256K
+#else
+static TInt KMaxFileSize = K2M;							// 2M
+#endif
+
+const TTimeIntervalMicroSeconds32 KFloatingPointTestTime = 10000000;	// 10 seconds
+
+static TPtr8 DataBuf(NULL, KMaxFileSize,KMaxFileSize);
+
+static RSharedChunkLdd Ldd;
+static RChunk TheChunk;
+
+GLDEF_D	RFs TheFs;
+GLDEF_D TFileName gSessionPath;
+GLDEF_D TChar gDriveToTest;
+
+static RMmcCntrlIf iDriver;
+static TInt iStack = 0;
+static TInt iCard = 0;
+static TBool iDriverOpen = EFalse;
+
+enum TPanic {ECreatingConsole,ELoaderCheck,ELoadingMmcDriver,EStartingMmcDriver};
+
+LOCAL_C void Panic(TPanic aPanic)
+//
+// Panic
+//
+	{
+	User::Panic(_L("MMCTEST"),aPanic);
+	}
+	
+
+static RFile File;
+
+static TInt gFastCounterFreq;
+
+const TUint KMMCExtendedCSDLength=512;
+class TExtendedCSD
+	{
+public:
+	enum TExtCSDAccessBits {ECmdSet, ESetBits, EClearBits, EWriteByte};
+	enum TExtCSDModesFieldIndex 
+		{
+		ECmdSetIndex = 191, 
+		ECmdSetRevIndex = 189, 
+		EPowerClassIndex = 187,
+		EHighSpeedInterfaceTimingIndex = 185,
+		EBusWidthModeIndex = 183
+		};
+	enum TExtCSDBusWidths
+		{
+		EExtCsdBusWidth1 = 0x00,
+		EExtCsdBusWidth4 = 0x01,
+		EExtCsdBusWidth8 = 0x02
+		};
+	enum TCardTypes
+		{
+		EHighSpeedCard26Mhz = 0x01,
+		EHighSpeedCard52Mhz = 0x02
+		};
+public:
+	inline TExtendedCSD();				// Default constructor
+	inline TExtendedCSD(const TUint8*);
+	inline TExtendedCSD& operator=(const TExtendedCSD&);
+	inline TExtendedCSD& operator=(const TUint8*);
+	inline TUint8 At(TUint anIndex) const;	// Byte from CSD at anIndex
+public:
+	inline TUint SupportedCmdSet() const;
+	inline TUint MinPerfWrite8Bit52Mhz() const;
+	inline TUint MinPerfRead8Bit52Mhz() const;
+	inline TUint MinPerfWrite8Bit26Mhz_4Bit52Mhz() const;
+	inline TUint MinPerfRead8Bit26Mhz_4Bit52Mhz() const;
+	inline TUint MinPerfWrite4Bit26Mhz() const;
+	inline TUint MinPerfRead4Bit26Mhz() const;
+	inline TUint PowerClass26Mhz360V() const;
+	inline TUint PowerClass52Mhz360V() const;
+	inline TUint PowerClass26Mhz195V() const;
+	inline TUint PowerClass52Mhz195V() const;
+	inline TUint CardType() const;
+	inline TUint CSDStructureVer() const;
+	inline TUint ExtendedCSDRev() const;
+	inline TUint CmdSet() const;
+	inline TUint CmdSetRev() const;
+	inline TUint PowerClass() const;
+	inline TUint HighSpeedTiming() const;
+	inline TUint BusWidth() const;
+	
+	inline TUint TrimMultiplier() const;
+	inline TUint SecureFeatureSupport() const;
+	inline TUint SecureEraseMultiplier() const;
+	inline TUint SecureTrimMultiplier() const;
+
+private:
+	/**< @internalComponent little endian 512 byte field representing extended CSD	*/
+	TUint8 iData[KMMCExtendedCSDLength];
+	};
+
+inline TExtendedCSD::TExtendedCSD()	// Default constructor
+	{}				
+inline TExtendedCSD::TExtendedCSD(const TUint8* aPtr)
+	{memcpy(&iData[0], aPtr, KMMCExtendedCSDLength);}
+inline TExtendedCSD& TExtendedCSD::operator=(const TExtendedCSD& aCSD)
+	{memcpy(&iData[0], &aCSD.iData[0], KMMCExtendedCSDLength); return(*this);}
+inline TExtendedCSD& TExtendedCSD::operator=(const TUint8* aPtr)
+	{memcpy(&iData[0], aPtr, KMMCExtendedCSDLength); return(*this);}
+// field accessors.  
+// "Properties Segment" of Extended CSD - i.e. read-only fields
+inline TUint TExtendedCSD::SupportedCmdSet() const {return iData[504];}
+inline TUint TExtendedCSD::MinPerfWrite8Bit52Mhz() const {return iData[210];}
+inline TUint TExtendedCSD::MinPerfRead8Bit52Mhz() const {return iData[209];}
+inline TUint TExtendedCSD::MinPerfWrite8Bit26Mhz_4Bit52Mhz() const {return iData[208];}
+inline TUint TExtendedCSD::MinPerfRead8Bit26Mhz_4Bit52Mhz() const {return iData[207];}
+inline TUint TExtendedCSD::MinPerfWrite4Bit26Mhz() const {return iData[206];}
+inline TUint TExtendedCSD::MinPerfRead4Bit26Mhz() const {return iData[205];}
+inline TUint TExtendedCSD::PowerClass26Mhz360V() const {return iData[203];}
+inline TUint TExtendedCSD::PowerClass52Mhz360V() const {return iData[202];}
+inline TUint TExtendedCSD::PowerClass26Mhz195V() const {return iData[201];}
+inline TUint TExtendedCSD::PowerClass52Mhz195V() const {return iData[200];}
+inline TUint TExtendedCSD::CardType() const {return iData[196];}
+inline TUint TExtendedCSD::CSDStructureVer() const {return iData[194];}
+inline TUint TExtendedCSD::ExtendedCSDRev() const {return iData[192];}
+
+inline TUint TExtendedCSD::TrimMultiplier() const {return iData[232]; }
+inline TUint TExtendedCSD::SecureFeatureSupport() const {return iData[231]; }
+inline TUint TExtendedCSD::SecureEraseMultiplier() const {return iData[230]; }
+inline TUint TExtendedCSD::SecureTrimMultiplier() const {return iData[229]; }
+    
+    
+// "Modes Segment" of Extended CSD - i.e. modifiable fields
+inline TUint TExtendedCSD::CmdSet() const {return iData[191];}
+inline TUint TExtendedCSD::CmdSetRev() const {return iData[189];}
+inline TUint TExtendedCSD::PowerClass() const {return iData[187];}
+inline TUint TExtendedCSD::HighSpeedTiming() const {return iData[185];}
+typedef TPckg<TExtendedCSD> TExtendedCSDPckg;
+
+static TExtendedCSD extCSD;
+
+GLDEF_C TInt CurrentDrive()
+//
+// Return the current drive number
+//
+	{
+
+	TInt driveNum;
+	TInt r=TheFs.CharToDrive(gSessionPath[0],driveNum);
+	test_KErrNone(r);
+	return(driveNum);
+	}
+
+GLDEF_C void Format(TInt aDrive)
+//
+// Format current drive
+//
+	{
+
+	TUint initTicks = User::FastCounter();
+    TUint finalTicks = 0;
+    
+	TBuf<4> driveBuf=_L("?:\\");
+	driveBuf[0]=(TText)(aDrive+'A');
+	RFormat format;
+	TInt count;
+	    
+	TInt r=format.Open(TheFs,driveBuf, EFullFormat,count);  // EQuickFormat
+	test_KErrNone(r);
+	while(count)
+		{
+		TInt r=format.Next(count);
+		test_KErrNone(r);
+		}
+	format.Close();
+	
+	finalTicks = User::FastCounter();
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;   
+	
+	TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to format %d ms)\n"), timeTakenInMs); 
+	}
+
+
+
+static TInt getExtendedCSD()
+	{
+
+	if (!iDriverOpen)
+		return(KErrNotSupported);
+
+
+	// Power the stack down & up to make sure the CardInfo is up to date
+	iDriver.Reset();
+	User::After(1000); 
+	iDriver.PwrDownStack();
+	User::After(1000); 
+	TRequestStatus status;
+	iDriver.PwrUpAndInitStack(status);
+	User::WaitForRequest(status);
+    TInt err;
+	if ((err=status.Int())!=KErrNone)
+		{
+		test.Printf(_L("Error Powering Stack"),err);
+		return(err);
+		}
+	iDriver.SelectCard(iCard);
+
+	// Get the CSD first to check whether the ExtCSD is supported
+	TMmcCardInfo ci;
+	if ((err = iDriver.CardInfo(ci))!=KErrNone)
+        {
+		test.Printf(_L("Error getting card info"),err);
+        return(err);
+        }
+	//test.Printf(_L("CSD Spec version: %u\n"), ci.iSpecVers);
+
+	if (ci.iSpecVers < 4) 
+		{
+		test.Printf(_L("Error: Extended CSD not supported\n"));
+		return KErrNotSupported;
+		}
+
+	TExtendedCSDPckg extCSDPckg(extCSD);
+
+	iDriver.ReadExtCSD(status, extCSDPckg);
+
+	User::WaitForRequest(status);
+
+	if (status.Int() != KErrNone)
+        {
+		test.Printf(_L("Error getting Extended CSD\n"));
+        return(KErrGeneral);
+        }
+    return err;
+    }
+
+
+static TUint GetSecEraseMultValue(void)
+    {
+        TUint retVal = 0;
+        
+        getExtendedCSD();
+        retVal = extCSD.SecureEraseMultiplier();
+        
+        return retVal;
+    }
+
+static TUint GetSecTrimMultValue(void)
+    {
+        TUint retVal = 0;
+        
+        getExtendedCSD();
+        retVal = extCSD.SecureTrimMultiplier();
+        
+        return retVal;
+    }
+
+static TUint GetTrimMultValue(void)
+    {
+        TUint retVal = 0;
+        
+        getExtendedCSD();
+        retVal = extCSD.TrimMultiplier();
+        
+        return retVal;
+    }
+
+static TInt64 DiskSize(TInt aDrive)
+//
+//
+//
+	{
+	TVolumeInfo v;
+	TInt r=TheFs.Volume(v,aDrive);
+	test_KErrNone(r);
+	return(v.iSize);
+	}
+
+static TInt CalcEntries(TInt64 aDiskSize, TUint& aEntrySize)
+    {
+
+    aEntrySize = KMaxFileSize;    
+    TInt numFiles = (TInt)(aDiskSize / aEntrySize);
+    
+    while ( numFiles > 1000 )
+        {
+          aEntrySize = aEntrySize << 2 ;
+          numFiles = (TUint)(aDiskSize / aEntrySize);
+        }    
+    return numFiles;
+        
+    }
+
+static void WriteFull(TInt aDrive)
+    {
+    TInt64 diskSize = DiskSize(aDrive);
+    
+	RFile f;
+    TUint initTicks = 0;
+    TUint finalTicks = 0;
+
+	TFileName sessionPath;
+	TInt r=TheFs.SessionPath(sessionPath);
+	test_KErrNone(r);
+	TBuf8<8> WriteData =_L8("Wibbleuy");
+	
+	r=TheFs.MkDirAll(gSessionPath);
+	
+	
+    TUint entrySize = KMaxFileSize;
+    TInt numFiles = CalcEntries(diskSize, entrySize);
+    test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; 
+    test.Printf(_L("Create %d entries\n"),numFiles);
+    
+    test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    initTicks = User::FastCounter();
+    
+    for( TInt i = 0; i < numFiles; ++i)
+        {
+
+		test.Printf(_L("Create FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) );
+		TFileName baseName= gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(i);
+		r=f.Replace(TheFs,baseName,EFileWrite);
+		test_KErrNone(r);
+		r = f.SetSize(entrySize);
+		if( r == KErrDiskFull)
+		    {
+		        numFiles = i;
+		        break;
+		    }
+		test_Value(r, r == KErrNone || r==KErrDiskFull);
+		r=f.Write((entrySize-30),WriteData);
+		test_KErrNone(r);
+		f.Flush();
+		f.Close();
+		}
+
+    test.Printf(_L("\nTRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    
+	test.Printf(_L("Test all entries have been created successfully\n"));
+	TBuf8<8> ReadData;
+	TInt Size=0;
+	for (TInt j=0; j < numFiles; j++)
+		{
+		
+        test.Printf(_L("Check FILE%d\t(%3d%%)\r"), j, (100*j/numFiles) );
+		TFileName baseName = gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(j);
+
+		TInt r=f.Open(TheFs,baseName,EFileRead);
+		if (r!=KErrNone)
+			{
+			test_Value(r, r == KErrNotFound && j==numFiles);
+			return;
+			}
+		ReadData.FillZ();
+		r=f.Read((entrySize-30),ReadData);
+		test_KErrNone(r);
+		test(f.Size(Size)==KErrNone);
+		test(entrySize == (TUint)Size);
+		test(ReadData==WriteData);
+		f.Close();
+		}
+		
+	finalTicks = User::FastCounter();
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;    
+   
+    TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to create %d entries = %d ms (%d ms/entry)\n"), numFiles, timeTakenInMs, timeTakenInMs/numFiles );     
+	test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    }
+
+static void ReWriteHalf(TInt aDrive)
+    {
+    TInt64 diskSize = DiskSize(aDrive);
+    
+    RFile f;
+    TUint initTicks = 0;
+    TUint finalTicks = 0;
+
+	TFileName sessionPath;
+	TInt r=TheFs.SessionPath(sessionPath);
+	test_KErrNone(r);
+	TBuf8<8> WriteData =_L8("Wibbleuy");
+	
+	r=TheFs.MkDirAll(gSessionPath);
+	
+	
+    TUint entrySize = KMaxFileSize;
+    TInt numFiles = CalcEntries(diskSize, entrySize);
+    test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; 
+    test.Printf(_L("Create %d entries\n"),numFiles/2);
+    
+    test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    initTicks = User::FastCounter();
+    
+    for( TInt i = 0; i < numFiles; i += 2)
+        {
+
+        test.Printf(_L("Create FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) );
+		TFileName baseName= gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(i);
+		r=f.Replace(TheFs,baseName,EFileWrite);
+		test_KErrNone(r);
+		r = f.SetSize(entrySize);
+		if( r == KErrDiskFull)
+		    {
+		        numFiles = i;
+		        break;
+		    }
+		test_Value(r, r == KErrNone || r==KErrDiskFull);
+		r=f.Write((entrySize-30),WriteData);
+		test_KErrNone(r);
+		f.Flush();
+		f.Close();
+		}
+
+    test.Printf(_L("\nTRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    
+	test.Printf(_L("Test all entries have been created successfully\n"));
+	TBuf8<8> ReadData;
+	TInt Size=0;
+	for (TInt j=0; j < numFiles; j += 2)
+		{
+		
+        test.Printf(_L("Check FILE%d\t(%3d%%)\r"), j, (100*j/numFiles) );
+		TFileName baseName = gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(j);
+
+		TInt r=f.Open(TheFs,baseName,EFileRead);
+		if (r!=KErrNone)
+			{
+			test_Value(r, r == KErrNotFound && j==numFiles);
+			return;
+			}
+		ReadData.FillZ();
+		r=f.Read((entrySize-30),ReadData);
+		test_KErrNone(r);
+		test(f.Size(Size)==KErrNone);
+		test(entrySize == (TUint)Size);
+		test(ReadData==WriteData);
+		f.Close();
+		}
+		
+	finalTicks = User::FastCounter();
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;    
+   
+    TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to create %d entries = %d ms (%d ms/entry)\n"), numFiles/2, timeTakenInMs, timeTakenInMs/numFiles/2 );     
+	test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    }
+
+
+
+static void DeleteAll(TInt aDrive)
+    {
+    TInt64 diskSize = DiskSize(aDrive);
+    
+    TUint initTicks = 0;
+    TUint finalTicks = 0;
+
+	TFileName sessionPath;
+	TInt r=TheFs.SessionPath(sessionPath);
+	test_KErrNone(r);
+
+    TUint entrySize = KMaxFileSize;
+    TInt numFiles = CalcEntries(diskSize, entrySize);
+    test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; 
+    test.Printf(_L("Delete %d entries\n"),numFiles);
+    
+    test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    
+    initTicks = User::FastCounter();
+    
+    for( TInt i = 2; i < numFiles; ++i)
+        {
+        test.Printf(_L("Delete FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) );
+		TFileName baseName = gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(i);
+		TInt r=TheFs.Delete(baseName);
+		test_Value(r, r == KErrNotFound || r == KErrNone);
+		}
+		
+	finalTicks = User::FastCounter();
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;   
+	
+	TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to delete %d entries = %d ms (%d ms/entry)\n"), numFiles, timeTakenInMs, timeTakenInMs/numFiles); 
+	test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    }
+
+static void DeleteHalf(TInt aDrive)
+    {
+    TInt64 diskSize = DiskSize(aDrive);
+    
+    TUint initTicks = 0;
+    TUint finalTicks = 0;
+
+	TFileName sessionPath;
+	TInt r=TheFs.SessionPath(sessionPath);
+	test_KErrNone(r);
+
+    TUint entrySize = KMaxFileSize;
+    TInt numFiles = CalcEntries(diskSize, entrySize);
+    test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; 
+    test.Printf(_L("Delete %d entries\n"),numFiles/2);
+    
+    test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    
+    initTicks = User::FastCounter();
+    
+    for( TInt i = 0; i < numFiles; i +=2)
+        {
+        test.Printf(_L("Delete FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) );
+		TFileName baseName = gSessionPath;
+		baseName.Append(_L("FILE"));
+		baseName.AppendNum(i);
+		TInt r=TheFs.Delete(baseName);
+		test_Value(r, r == KErrNotFound || r == KErrNone);
+		}
+		
+	finalTicks = User::FastCounter();
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;   
+	
+	TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to delete %d entries = %d ms (%d ms/entry)\n"), numFiles/2, timeTakenInMs, timeTakenInMs/numFiles/2); 
+	test.Printf(_L("TRIM_MULT     :%d\n"), GetTrimMultValue());
+    test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue());
+    test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue());
+    }
+
+
+static void WaitUntilTrimDone()
+    {
+     
+    TUint initTicks = User::FastCounter();
+    TUint finalTicks = 0;
+
+#define READ_TO_KEEP_CARD_ON
+#ifdef READ_TO_KEEP_CARD_ON
+
+    const TInt readSize = 4096;
+    const TInt timeToRead = 30;
+
+	test.Printf(_L("Read a file for %d sec to keep card power on\n"), timeToRead );
+	TBuf8<4096> ReadData;
+		
+	RTimer timer;
+	timer.CreateLocal();
+	TRequestStatus reqStat;
+
+    //test.Printf(_L("Timer started.\n"));
+
+	TFileName baseName = gSessionPath;
+	baseName.Append(_L("FILE1"));
+
+    RFile f;
+	TInt r=f.Open(TheFs,baseName,EFileRead);
+	if (r!=KErrNone)
+		{
+		return;
+		}
+	TInt alreadyRead = 0;
+	TInt fileSize;
+	test(f.Size(fileSize)==KErrNone);
+	
+	//test.Printf(_L("File size:%d.\n"), fileSize);
+	
+	timer.After(reqStat, timeToRead*1000000); // After 30 secs
+	
+	while( reqStat==KRequestPending )
+	    {   
+    
+	    test.Printf(_L("Read pos:%d\r"), alreadyRead );
+	    ReadData.FillZ();
+	    r=f.Read(readSize,ReadData);
+	    
+	    test_KErrNone(r);
+        alreadyRead += readSize;
+        if( alreadyRead == fileSize)
+            {
+             alreadyRead = 0;
+		     f.Seek(ESeekStart, alreadyRead);
+            }
+        User::After(1000);        // 1 ms
+	    }
+    
+    timer.Close();
+    
+	f.Close();
+	
+    test.Printf(_L("\n"));
+
+#else
+
+    TInt trimMult = GetTrimMultValue(); // Get TRIM_MULT value from eMMC Extended CSD
+    test.Printf(_L("TRIM_MULT:%d\r"), trimMult);
+    while( trimMult-- > 0  )
+        {
+        // Wait for a while
+        User::After(300000);        // TRIM Timeout = 300ms x TRIM_MULT
+        test.Printf(_L("TRIM_MULT:%d\r"), trimMult);
+        TInt trim = GetTrimMultValue();
+        }
+
+#endif
+        
+    finalTicks = User::FastCounter(); 
+	TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ;   
+	
+	TInt timeTakenInMs = I64LOW(duration.Int64() / 1000);
+	test.Printf(_L("Time taken to TRIM done = %d ms\n"), timeTakenInMs); 
+    }
+
+
+
+void doExit()
+    {
+    iDriver.Close();
+
+    User::FreeLogicalDevice(_L("MmcIf"));
+        
+	test.End();
+	test.Close();
+        
+    }
+
+GLDEF_C void CallTestsL(void)
+//
+// Call all tests
+//
+	{
+
+	test.Next(gSessionPath);
+
+    TInt err;
+	err=User::LoadLogicalDevice(_L("D_MMCIF"));
+	__ASSERT_ALWAYS((err==KErrNone||err==KErrAlreadyExists),Panic(ELoadingMmcDriver));
+    test.Printf(_L("MMCIF driver loaded\n"));
+
+
+    iDriver.Close();
+	TInt r=iDriver.Open(iStack,iDriver.VersionRequired());
+	iDriverOpen=(r==KErrNone)?(TBool)ETrue:(TBool)EFalse;
+	test.Printf(_L("iDriverOpen %d\n"), iDriverOpen);    
+	if( !iDriverOpen )
+	    {
+	    doExit();   
+	    return;
+	    }
+
+    test.Next(_L("Get extended CSD"));
+    r = getExtendedCSD();
+
+    if( r != KErrNone )
+        {
+        test.Next(_L("Extended CSD doesn't exists. Exit."));    
+        doExit();
+        return;    
+        }    
+
+    if( extCSD.ExtendedCSDRev() < 5 )
+        {
+        test.Next(_L("TRIM feature doesn't exists. Exit!"));
+        }
+
+
+	r = HAL::Get(HAL::EFastCounterFrequency, gFastCounterFreq);
+	test_KErrNone(r);
+	test.Printf(_L("HAL::EFastCounterFrequency %d\n"), gFastCounterFreq);
+
+
+    TInt currentDrive = CurrentDrive();
+  	
+  	//  1. Format drive
+    test.Next(_L("Format drive"));
+    Format(currentDrive);
+        
+    //  2. Set TRIM off
+    //test.Next(_L("Set TRIM off"));
+    
+    
+    //  3. Write full with files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    //  4. Delete all files and measure elapsed time
+    test.Next(_L("Delete all files"));
+    DeleteAll(currentDrive);
+    
+    //  5. Rewrite all (or a set of) files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    //  6. Format drive
+    test.Next(_L("Format drive"));
+    Format(currentDrive);
+    
+    //  7. Set TRIM on
+    //test.Next(_L("Set TRIM on"));
+    
+    //  8. Write full with files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    //  9. Delete all files and measure elapsed time
+    test.Next(_L("Delete all files"));
+    DeleteAll(currentDrive);
+    
+    // 10. Wait for a while (give time to eMMC to do its TRIM job)
+    test.Next(_L("Wait for TRIM done"));
+    WaitUntilTrimDone();
+    
+    // 11. Rewrite all (or same set of) files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    // 12. Format drive
+    test.Next(_L("Format drive"));
+    Format(currentDrive);
+
+    // 13. Write full with files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    // 14. Delete half of files and measure elapsed time
+    test.Next(_L("Delete half of files"));
+    DeleteHalf(currentDrive);
+    
+    // 15. Re-write half of files and measure elapsed time
+    test.Next(_L("Re-write half"));
+    ReWriteHalf(currentDrive);    
+
+
+    // 16. Format drive
+    test.Next(_L("Format drive"));
+    Format(currentDrive);
+
+    // 17. Write full with files and measure elapsed time
+    test.Next(_L("Write full"));
+    WriteFull(currentDrive);    
+    
+    // 18. Delete half of files and measure elapsed time
+    test.Next(_L("Delete half of files"));
+    DeleteHalf(currentDrive);
+    
+    // 19. Wait for a while (give time to eMMC to do its TRIM job)
+    test.Next(_L("Wait for TRIM done"));
+    WaitUntilTrimDone();
+    
+    // 20. Re-write half of files and measure elapsed time
+    test.Next(_L("Re-write half"));
+    ReWriteHalf(currentDrive);    
+    
+    // 21. Format drive
+    test.Next(_L("Format drive"));
+    Format(currentDrive);
+
+    doExit();
+
+    return;
+	}
+
+GLDEF_C TInt E32Main()
+    {
+    TInt r=TheFs.Connect();
+	test_KErrNone(r);
+
+    test.Title();
+	test.Start(_L("Start Benchmarking ..."));
+	
+    TInt theDrive;
+    gDriveToTest='E';		
+	r=TheFs.CharToDrive(gDriveToTest,theDrive);
+	test_KErrNone(r);
+    
+    gSessionPath=_L("?:\\TRIMTEST\\");
+	TChar driveLetter;
+	r=TheFs.DriveToChar(theDrive,driveLetter);
+	test_KErrNone(r);
+	gSessionPath[0]=(TText)driveLetter;
+	r=TheFs.SetSessionPath(gSessionPath);
+	test_KErrNone(r);
+
+    r=TheFs.MkDirAll(gSessionPath);
+	if(r == KErrCorrupt)
+		{
+		test.Printf(_L("Attempting to create directory \'%S\' failed, KErrCorrupt\n"), &gSessionPath);
+		test.Printf(_L("This could be caused by a previous failing test, or a test media defect\n"));
+		test.Printf(_L("Formatting drive, retrying MkDirall\nShould subsequent tests fail with KErrCorrupt (%d) as well, replace test medium !\n"),
+			r);
+		Format(theDrive);
+		r=TheFs.MkDirAll(gSessionPath);
+		test_KErrNone(r);
+		}
+	else if (r == KErrNotReady)
+		{
+		TDriveInfo d;
+		r=TheFs.Drive(d, theDrive);
+		test_KErrNone(r);
+		if (d.iType == EMediaNotPresent)
+			test.Printf(_L("%c: Medium not present - cannot perform test.\n"), (TUint)driveLetter);
+		else
+			test.Printf(_L("medium found (type %d) but drive %c: not ready\nPrevious test may have hung; else, check hardware.\n"), (TInt)d.iType, (TUint)driveLetter);
+		}
+	test_Value(r, r == KErrNone || r == KErrAlreadyExists);
+
+
+    CallTestsL();
+
+	TheFs.Close();
+
+    return(KErrNone);
+    }