sl@0: // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\pccd\t_med_writebm.cpp sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /* sl@0: SD/MMC/other media benchmark test sl@0: Writes data to the media and prints out time taken (microseconds). sl@0: Works on TBusLocalDrive level. May require a script to filter the results. sl@0: sl@0: Principle of operation: sl@0: In the simple case scenario the user specifies media start and end position in bytes, sl@0: write buffer size (window size), the number of write repetitions (optional) and write position increment. sl@0: sl@0: The test fills buffer with random data, writes it to the media (probably several times); prints out the time taken; sl@0: increments or decrements window position; goto begin. Test finishes when the window slides outside specified beginning or end media position. sl@0: sl@0: It more complex case we have 2 windows. It is useful for FAT emulation. sl@0: sl@0: ------------------------------------------- sl@0: Command line shall look like this: sl@0: drv=[0..25] pos=xxx:yyy [wrep=] wn=[1,2] w1sz= w1pi= [w2sz= w2pi=] sl@0: sl@0: where: sl@0: drv=N local drive physical number for 1st MMC slot on H2 & H4 it will be 1, see variantmediadef.h sl@0: pos=xxx:yyy xxx start media position, yyy end media position in bytes. The test will be writing data in the range xxx-yyy sl@0: wrep=N optional. Specifies how many times the window will be written to the media, just for more precise time calculation. Default is 1. sl@0: wn=N Number of data windows being written on the media. can be 1 or 2 sl@0: sl@0: w1sz=N Size of the data window #1 in bytes. Must be > 0 sl@0: w1pi=N Media position increment for the window #1. if positive, the window will be moving from xxx to yyy (see media pos parameter); sl@0: if 0, the window won't change its position; if <0, the window will be moving from yyy to xxx sl@0: sl@0: w2sz the same for the window #2 if it is specified sl@0: w2pi the same for the window #2 if it is specified sl@0: sl@0: The test will finish when one of the windows slides across the media boundaries xxx of yyy. If you specify w1pi=0 or both w1pi=0 w2pi=0 sl@0: it may run forever :) sl@0: sl@0: Be careful, all information on the medium will be lost !!! sl@0: */ sl@0: sl@0: RTest test(_L("MMC/SD write performance test")); sl@0: sl@0: TBusLocalDrive BusLocalDrv; sl@0: RFs Fs; sl@0: sl@0: RBuf8 gWriteBuffer1; sl@0: RBuf8 gWriteBuffer2; sl@0: sl@0: TInt gLocalDrvNum = -1; //-- LOCAL physical drive number (see Estart.txt) sl@0: TBool gChangeFlag; sl@0: sl@0: TUint gWindowsNum = 0; //-- number of windows being written sl@0: sl@0: TUint32 gWriteBufSize1 = 0; //-- write buffer 1 size, bytes sl@0: TInt32 gWriteGranularity1 = 0; //-- write granularity 1 (write buffer position increment) sl@0: sl@0: TUint32 gWriteBufSize2 = 0; //-- write buffer 2 size, bytes sl@0: TInt32 gWriteGranularity2 = 0; //-- write granularity 2 (write buffer position increment) sl@0: sl@0: TInt64 gMediaStartPos = 0; //-- media start position sl@0: TInt64 gMediaEndPos = 0; //-- media end position sl@0: sl@0: TUint gNumWrites = 1; //-- number of buffer writes to the media sl@0: sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: sl@0: void RndFillBuf(TDes8& aBuf); sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: The main part of the test, actually. Writes 1 or 2 buffers to the media (possibly several times) and sl@0: prints out the time taken. sl@0: */ sl@0: void DoWriteBMTest(void) sl@0: { sl@0: test.Next(_L("Performing write benchmark test.\n")); sl@0: sl@0: TInt nRes; sl@0: TTime timeStart; sl@0: TTime timeEnd; sl@0: sl@0: //-- if window pos increment is <0, it will move from end to the beginning position, backwards sl@0: TInt64 currMediaPos1 = (gWriteGranularity1 >=0) ? gMediaStartPos : gMediaEndPos-gWriteBufSize1; sl@0: TInt64 currMediaPos2 = (gWriteGranularity2 >=0) ? gMediaStartPos : gMediaEndPos-gWriteBufSize2; sl@0: sl@0: if(gWindowsNum == 1) //-- we have only 1 window sl@0: { sl@0: currMediaPos2 = 0; sl@0: gWriteGranularity2 = 0; sl@0: } sl@0: sl@0: RndFillBuf(gWriteBuffer1); sl@0: if(gWindowsNum == 2) sl@0: RndFillBuf(gWriteBuffer2); sl@0: sl@0: for(;;) sl@0: { sl@0: if(currMediaPos1 <0 || (currMediaPos1 + gWriteBufSize1) > gMediaEndPos) sl@0: break; sl@0: sl@0: if(currMediaPos2 <0 || (currMediaPos2 + gWriteBufSize2) > gMediaEndPos) sl@0: break; sl@0: sl@0: timeStart.UniversalTime(); //-- take start time sl@0: sl@0: for(TUint i=0; i= EDriveA) && (gLocalDrvNum <= EDriveZ)); sl@0: test(gMediaStartPos >=0 && gMediaEndPos >gMediaStartPos); sl@0: test(gWindowsNum == 1 || gWindowsNum == 2); sl@0: test(gWriteBufSize1 > 0); sl@0: if(gWindowsNum == 2) sl@0: { sl@0: test(gWriteBufSize2 > 0); sl@0: } sl@0: test(gNumWrites > 0); sl@0: sl@0: sl@0: TInt nRes; sl@0: nRes = Fs.Connect(); sl@0: test_KErrNone(nRes); sl@0: sl@0: //-- connect to the TBusLocalDrive sl@0: test.Printf(_L("Connecting to the PHYSICAL drive #%d\n"), gLocalDrvNum); sl@0: sl@0: nRes = BusLocalDrv.Connect(gLocalDrvNum, gChangeFlag); sl@0: test_KErrNone(nRes); sl@0: sl@0: TLocalDriveCapsV2 info; sl@0: TPckg infoPckg(info); sl@0: nRes = BusLocalDrv.Caps(infoPckg); sl@0: test_KErrNone(nRes); sl@0: sl@0: //-- create write buffer 1 sl@0: nRes=gWriteBuffer1.CreateMax(gWriteBufSize1); sl@0: test_KErrNone(nRes); sl@0: sl@0: sl@0: //-- create write buffer 2 sl@0: if(gWindowsNum == 2) sl@0: { sl@0: nRes=gWriteBuffer2.CreateMax(gWriteBufSize2); sl@0: test_KErrNone(nRes); sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: sl@0: /** Finalise environment */ sl@0: void Finalise(void) sl@0: { sl@0: BusLocalDrv.Disconnect(); sl@0: BusLocalDrv.Close(); sl@0: sl@0: gWriteBuffer1.Close(); sl@0: gWriteBuffer2.Close(); sl@0: sl@0: Fs.Close(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Just a helper method. Looks for a given pattern in the given string and returns the rest of the found token. sl@0: @return KErrNotFound if the aPattern wasn't found in aSrc sl@0: KErrNone otherwise and the rest of the token in aToken sl@0: */ sl@0: TInt DoFindToken(const TDesC& aSrc, const TDesC& aPattern,TPtrC& aToken) sl@0: { sl@0: TLex lex(aSrc); sl@0: TPtrC token; sl@0: sl@0: for(;;) sl@0: { sl@0: lex.SkipSpace(); sl@0: token.Set(lex.NextToken()); sl@0: sl@0: if(token.Length() == 0) sl@0: { sl@0: test.Printf(_L("Parameter %S not found!\n"), &aPattern); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: if(token.FindF(aPattern) == 0) sl@0: {//-- found a requires patern, extract substring next to it sl@0: aToken.Set(token.Right(token.Length() - aPattern.Length())); sl@0: break; sl@0: } sl@0: sl@0: sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Parse the command line, which shall look like: sl@0: drv=[0..25] pos=xxx:yyy [wrep=] wn=[1,2] w1sz= w1pi= [w2sz= w2pi=] sl@0: */ sl@0: TBool ParseCommandLine(void) sl@0: { sl@0: TBuf<0x100> cmdLine; sl@0: User::CommandLine(cmdLine); sl@0: sl@0: cmdLine.LowerCase(); sl@0: sl@0: test.Printf(_L("Command line:\n")); sl@0: test.Printf(cmdLine); sl@0: test.Printf(_L("\n")); sl@0: sl@0: TLex lexParam; sl@0: sl@0: TInt nVal; sl@0: TUint uVal; sl@0: TInt nRes; sl@0: sl@0: TPtrC token; sl@0: sl@0: //-- process "drv" parameter. It shall look like: "drv=1" sl@0: //-- this is a physical number of a local drive sl@0: if(DoFindToken(cmdLine, _L("drv="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: nRes = lexParam.Val(nVal); sl@0: if(nRes!= KErrNone || nVal < EDriveA || nVal > EDriveZ) sl@0: { sl@0: test.Printf(_L("Invalid 'drv' parameter value!\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gLocalDrvNum = nVal; sl@0: sl@0: sl@0: //-- process "pos" parameter It shall look like: "pos=xxx:yyy" where "xxx" is a start media position, "yyy" end media position sl@0: //-- It specifies start and end media position sl@0: if(DoFindToken(cmdLine, _L("pos="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: TInt64 startPos; sl@0: TInt64 endPos; sl@0: sl@0: //-- start media position sl@0: nRes = lexParam.Val(startPos); sl@0: if(nRes!= KErrNone || startPos< 0) sl@0: { sl@0: test.Printf(_L("invalid start 'pos' value!\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: //-- delimiter sl@0: lexParam.SkipSpace(); sl@0: if(lexParam.Get() != ':') sl@0: { sl@0: test.Printf(_L("invalid 'pos' parameter!\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: //-- end media position sl@0: lexParam.SkipSpace(); sl@0: nRes = lexParam.Val(endPos); sl@0: if(nRes!= KErrNone || endPos < 0) sl@0: { sl@0: test.Printf(_L("invalid end 'pos' value!\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gMediaStartPos = startPos; sl@0: gMediaEndPos = endPos; sl@0: sl@0: sl@0: //-- process "wn" parameter It shall look like: "wn=1" or "wn=2" sl@0: //-- It specifies number of sliding windows. sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("wn="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(uVal); sl@0: if(nRes!= KErrNone || uVal > 2) sl@0: { sl@0: test.Printf(_L("wrong 'wn' parameter value, it must be 1 or 2 !\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gWindowsNum = uVal; sl@0: sl@0: sl@0: //-- process "w1sz" & "w1pi" parameters. They shall look like: "w1sz=16384" & "w1pi=512" sl@0: //-- these parameters specify size and position increment for the window 1 sl@0: //-- if w1pi <0 the window will slide from the media end position to the beginning sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("w1sz="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(uVal); sl@0: if(nRes!= KErrNone || uVal ==0) sl@0: { sl@0: test.Printf(_L("wrong 'w1sz' parameter value, it must be > 0 !\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gWriteBufSize1 = uVal; sl@0: sl@0: sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("w1pi="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(nVal); sl@0: if(nRes!= KErrNone) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: gWriteGranularity1 = nVal; sl@0: sl@0: //-- process "w2sz" & "w2pi" parameters. They shall look like: "w2sz=16384" & "w2pi=512" sl@0: //-- these parameters specify size and position increment for the window 1 sl@0: //-- if w1pi <0 the window will slide from the media end position to the beginning sl@0: if(gWindowsNum == 2) sl@0: { sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("w2sz="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(uVal); sl@0: if(nRes!= KErrNone || uVal ==0) sl@0: { sl@0: test.Printf(_L("wrong 'w2sz' parameter value, it must be > 0 !\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gWriteBufSize2 = uVal; sl@0: sl@0: sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("w2pi="), token) != KErrNone) sl@0: return EFalse; sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(nVal); sl@0: if(nRes!= KErrNone) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: gWriteGranularity2 = nVal; sl@0: } sl@0: sl@0: //-- extract wrep= parameter. sl@0: //-- it specifies how many times buffers will be written to the media sl@0: lexParam.SkipSpace(); sl@0: if(DoFindToken(cmdLine, _L("wrep="), token) == KErrNone) sl@0: { sl@0: sl@0: sl@0: lexParam.Assign(token); sl@0: lexParam.SkipSpace(); sl@0: sl@0: nRes = lexParam.Val(uVal); sl@0: if(nRes!= KErrNone || uVal ==0 ) sl@0: { sl@0: test.Printf(_L("wrong 'wrep' parameter value, it must be >0 !\n")); sl@0: return EFalse; sl@0: } sl@0: sl@0: gNumWrites = uVal; sl@0: } sl@0: else sl@0: { sl@0: gNumWrites = 1; sl@0: } sl@0: sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: void PrintInfo() sl@0: { sl@0: test.Printf(_L("Media write benchmark test. For use mostly with mmc/sd cards.\n")); sl@0: test.Printf(_L("Usage: See source code for command line parameters.\n")); sl@0: } sl@0: sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: sl@0: void MainL(void) sl@0: { sl@0: test.Title(); sl@0: test.Start(_L("Start testing...\n")); sl@0: sl@0: sl@0: //-- it will initialise global test parameters sl@0: if(!ParseCommandLine()) sl@0: { sl@0: PrintInfo(); sl@0: return; sl@0: } sl@0: sl@0: if(!Initialise()) sl@0: { sl@0: return; //-- something went wrong sl@0: } sl@0: sl@0: sl@0: DoWriteBMTest(); sl@0: sl@0: Finalise(); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: TInt E32Main() sl@0: { sl@0: sl@0: CTrapCleanup* cleanup=CTrapCleanup::New() ; // get clean-up stack sl@0: sl@0: TRAPD(r,MainL()); sl@0: sl@0: delete cleanup ; // destroy clean-up stack sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: