kerneltest/e32test/pccd/t_med_writebm.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/pccd/t_med_writebm.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,533 @@
+// 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:
+// e32test\pccd\t_med_writebm.cpp
+// 
+//
+
+/**
+ @file
+*/
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <f32fsys.h>
+#include <e32math.h>
+
+/*
+    SD/MMC/other media benchmark test
+    Writes data to the media and prints out time taken (microseconds).
+    Works on TBusLocalDrive level. May require a script to filter the results.
+
+    Principle of operation:
+    In the simple case scenario the user specifies media start and end position in bytes,
+    write buffer size (window size), the number of write repetitions (optional) and write position increment.
+    
+    The test fills buffer with random data, writes it to the media (probably several times); prints out the time taken;
+    increments or decrements window position; goto begin.  Test finishes when the window slides outside specified beginning or end media position.
+
+    It more complex case we have 2 windows. It is useful for FAT emulation.
+    
+    -------------------------------------------
+    Command line shall look like this:
+    drv=[0..25] pos=xxx:yyy [wrep=<number>] wn=[1,2] w1sz=<number> w1pi=<number> [w2sz=<number> w2pi=<number>]
+
+    where:
+    drv=N           local drive physical number for 1st MMC slot on H2 & H4 it will be 1, see variantmediadef.h
+    pos=xxx:yyy     xxx start media position, yyy end media position in bytes. The test will be writing data in the range xxx-yyy
+    wrep=N          optional. Specifies how many times the window will be written to the media, just for more precise time calculation. Default is 1.
+    wn=N            Number of data windows being written on the media. can be 1 or 2
+    
+    w1sz=N          Size of the data window #1 in bytes. Must be > 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); 
+                    if 0, the window won't change its position; if <0, the window will be moving from yyy to xxx
+
+    w2sz            the same for the window #2 if it is specified
+    w2pi            the same for the window #2 if it is specified
+
+    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
+    it may run forever :)
+
+    Be careful, all information on the medium will be lost !!!
+*/
+
+RTest test(_L("MMC/SD write performance test"));
+
+TBusLocalDrive BusLocalDrv;
+RFs            Fs;
+
+RBuf8   gWriteBuffer1;
+RBuf8   gWriteBuffer2;
+
+TInt    gLocalDrvNum = -1;       //-- LOCAL physical drive number (see Estart.txt)
+TBool   gChangeFlag;
+
+TUint   gWindowsNum = 0;         //-- number of windows being written
+
+TUint32 gWriteBufSize1     = 0;  //-- write buffer 1 size, bytes
+TInt32  gWriteGranularity1 = 0;  //-- write granularity 1 (write buffer position increment) 
+
+TUint32 gWriteBufSize2     = 0;  //-- write buffer 2 size, bytes
+TInt32  gWriteGranularity2 = 0;  //-- write granularity 2 (write buffer position increment) 
+
+TInt64  gMediaStartPos = 0;      //-- media start position
+TInt64  gMediaEndPos = 0;        //-- media end position
+
+TUint   gNumWrites = 1;          //-- number of buffer writes to the media
+
+
+//---------------------------------------------------------------------------------
+
+void RndFillBuf(TDes8& aBuf);
+
+//---------------------------------------------------------------------------------
+
+/**
+    The main part of the test, actually. Writes 1 or 2 buffers to the media (possibly several times) and 
+    prints out the time taken.
+*/
+void DoWriteBMTest(void)
+{
+    test.Next(_L("Performing write benchmark test.\n"));
+
+    TInt    nRes;
+    TTime   timeStart;
+    TTime   timeEnd;
+    
+    //-- if window pos increment is <0, it will move from end to the beginning position, backwards   
+    TInt64 currMediaPos1 =  (gWriteGranularity1 >=0) ? gMediaStartPos : gMediaEndPos-gWriteBufSize1;
+    TInt64 currMediaPos2 =  (gWriteGranularity2 >=0) ? gMediaStartPos : gMediaEndPos-gWriteBufSize2;
+
+    if(gWindowsNum == 1) //-- we have only 1 window 
+    {
+        currMediaPos2 = 0;
+        gWriteGranularity2 = 0;
+    }
+
+	RndFillBuf(gWriteBuffer1); 
+	if(gWindowsNum == 2)
+		RndFillBuf(gWriteBuffer2); 
+
+    for(;;)
+    {
+        if(currMediaPos1 <0 || (currMediaPos1 + gWriteBufSize1) > gMediaEndPos)
+            break;
+
+        if(currMediaPos2 <0 || (currMediaPos2 + gWriteBufSize2) > gMediaEndPos)
+            break;
+
+        timeStart.UniversalTime(); //-- take start time
+
+        for(TUint i=0; i<gNumWrites; ++i)
+        {
+            nRes = BusLocalDrv.Write(currMediaPos1, gWriteBuffer1); //-- write window 1
+            test_KErrNone(nRes);
+
+            if(gWindowsNum == 2)
+            {
+                nRes = BusLocalDrv.Write(currMediaPos2, gWriteBuffer2); //-- write window 2
+                test_KErrNone(nRes);
+            }
+        }//for(TUint i=0; i<gNumWrites; ++i)
+
+        timeEnd.UniversalTime(); //-- take end time
+        
+        TTimeIntervalMicroSeconds  usElapsed=timeEnd.MicroSecondsFrom(timeStart);
+        TInt64 usTaken = usElapsed.Int64()/gNumWrites;
+
+        //-- print out the result
+
+        test.Printf(_L("~#pos:%lu:%lu, time:%d us\n"), currMediaPos1, currMediaPos2, (TInt32)usTaken);
+
+        //-- move windows
+        currMediaPos1 += gWriteGranularity1;
+        currMediaPos2 += gWriteGranularity2;
+    }
+
+}
+
+
+//---------------------------------------------------------------------------------
+
+/** fill a given buffer with random bytes */
+void RndFillBuf(TDes8& aBuf)
+{
+    static TInt64 rndSeed = Math::Random();
+
+    //-- ?? optimise here ??
+    for(TInt i=0; i<aBuf.Size(); ++i)
+    {
+        aBuf[i] = (TUint8)Math::Rand(rndSeed);
+    }
+}
+
+
+//---------------------------------------------------------------------------------
+
+/** Initialise environment */
+TBool Initialise()
+{
+    //-- print out some parameters:
+    test.Printf(_L("~#Local Drive:%d\n"), gLocalDrvNum);
+    test.Printf(_L("~#MediaPos:%lu:%lu\n"), gMediaStartPos, gMediaEndPos);
+    test.Printf(_L("~#WinNum:%d\n"), gWindowsNum);
+    test.Printf(_L("~#NumWrites:%d\n"), gNumWrites);
+    test.Printf(_L("~#Window1 sz:%d, posInc:%d \n"), gWriteBufSize1, gWriteGranularity1);
+
+    if(gWindowsNum == 2)
+    {
+        test.Printf(_L("~#Window2 sz:%d, posInc:%d \n"), gWriteBufSize2, gWriteGranularity2);
+    }
+
+    
+    test((gLocalDrvNum >= EDriveA) && (gLocalDrvNum <= EDriveZ));
+    test(gMediaStartPos >=0 && gMediaEndPos >gMediaStartPos);
+    test(gWindowsNum == 1 || gWindowsNum == 2);
+    test(gWriteBufSize1 > 0);
+    if(gWindowsNum == 2)
+    {
+        test(gWriteBufSize2 > 0);
+    }
+    test(gNumWrites > 0);
+
+    
+    TInt nRes;
+    nRes = Fs.Connect();
+    test_KErrNone(nRes);
+
+    //-- connect to the TBusLocalDrive
+    test.Printf(_L("Connecting to the PHYSICAL drive #%d\n"), gLocalDrvNum);
+
+    nRes = BusLocalDrv.Connect(gLocalDrvNum, gChangeFlag);
+    test_KErrNone(nRes);
+
+    TLocalDriveCapsV2 info;
+    TPckg<TLocalDriveCapsV2> infoPckg(info);
+    nRes = BusLocalDrv.Caps(infoPckg);
+    test_KErrNone(nRes);
+
+    //-- create write buffer 1
+    nRes=gWriteBuffer1.CreateMax(gWriteBufSize1);
+    test_KErrNone(nRes);
+
+
+    //-- create write buffer 2
+    if(gWindowsNum == 2)
+    {
+        nRes=gWriteBuffer2.CreateMax(gWriteBufSize2);
+        test_KErrNone(nRes);
+    }
+
+    return ETrue;
+}
+
+//---------------------------------------------------------------------------------
+
+/** Finalise environment */
+void Finalise(void)
+{
+    BusLocalDrv.Disconnect();
+    BusLocalDrv.Close();
+    
+    gWriteBuffer1.Close();
+    gWriteBuffer2.Close();
+
+    Fs.Close();
+}
+
+
+/**
+    Just a helper method. Looks for a given pattern in the given string and returns the rest of the found token.
+    @return KErrNotFound if the aPattern wasn't found in aSrc
+            KErrNone otherwise and the rest of the token in aToken
+*/
+TInt DoFindToken(const TDesC& aSrc, const TDesC& aPattern,TPtrC& aToken)
+{
+    TLex    lex(aSrc);
+    TPtrC   token;
+
+    for(;;)
+    {
+        lex.SkipSpace();
+        token.Set(lex.NextToken());
+    
+        if(token.Length() == 0)
+        {
+            test.Printf(_L("Parameter %S not found!\n"), &aPattern);   
+            return KErrNotFound;            
+        }
+
+        if(token.FindF(aPattern) == 0)
+        {//-- found a requires patern, extract substring next to it
+            aToken.Set(token.Right(token.Length() - aPattern.Length()));
+            break;
+        }
+
+
+    }
+
+    return KErrNone;
+}
+
+
+/**
+    Parse the command line, which shall look like:
+    drv=[0..25] pos=xxx:yyy [wrep=<number>] wn=[1,2] w1sz=<number> w1pi=<number> [w2sz=<number> w2pi=<number>]
+*/
+TBool ParseCommandLine(void)
+{
+    TBuf<0x100> cmdLine;
+    User::CommandLine(cmdLine);
+
+    cmdLine.LowerCase();
+
+    test.Printf(_L("Command line:\n"));   
+    test.Printf(cmdLine);   
+    test.Printf(_L("\n"));   
+
+    TLex lexParam;
+
+    TInt    nVal;
+    TUint   uVal;
+    TInt    nRes;
+    
+    TPtrC   token;
+    
+    //-- process "drv" parameter. It shall look like: "drv=1"
+    //-- this is a physical number of a local drive
+    if(DoFindToken(cmdLine, _L("drv="), token) != KErrNone)
+        return  EFalse;
+
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+    nRes = lexParam.Val(nVal);
+    if(nRes!= KErrNone || nVal < EDriveA || nVal > EDriveZ)
+    {
+            test.Printf(_L("Invalid 'drv' parameter value!\n"));   
+            return EFalse;
+    }
+
+    gLocalDrvNum = nVal;
+
+
+    //-- process "pos" parameter It shall look like: "pos=xxx:yyy" where "xxx" is a start media position, "yyy" end media position
+    //-- It specifies start and end media position
+    if(DoFindToken(cmdLine, _L("pos="), token) != KErrNone)
+        return  EFalse;
+
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+
+    TInt64 startPos;
+    TInt64 endPos;
+                
+    //-- start media position
+    nRes = lexParam.Val(startPos);
+    if(nRes!= KErrNone || startPos< 0)
+    {
+        test.Printf(_L("invalid start 'pos' value!\n"));   
+        return EFalse;
+    }
+
+    //-- delimiter
+    lexParam.SkipSpace();
+    if(lexParam.Get() != ':')
+    {
+        test.Printf(_L("invalid 'pos' parameter!\n"));   
+        return EFalse;
+    }
+
+    //-- end media position
+    lexParam.SkipSpace();
+    nRes = lexParam.Val(endPos);
+    if(nRes!= KErrNone || endPos < 0)
+    {
+        test.Printf(_L("invalid end 'pos' value!\n"));   
+        return EFalse;
+    }
+
+    gMediaStartPos = startPos;
+    gMediaEndPos = endPos;
+
+
+    //-- process "wn" parameter It shall look like: "wn=1" or "wn=2"
+    //-- It specifies number of sliding windows.
+    lexParam.SkipSpace();
+    if(DoFindToken(cmdLine, _L("wn="), token) != KErrNone)
+        return  EFalse;
+    
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+
+    nRes = lexParam.Val(uVal);
+    if(nRes!= KErrNone || uVal > 2)
+    {
+        test.Printf(_L("wrong 'wn' parameter value, it must be 1 or 2 !\n"));   
+        return EFalse;
+    }
+
+    gWindowsNum = uVal;
+
+
+    //-- process "w1sz" & "w1pi" parameters. They shall look like: "w1sz=16384" & "w1pi=512"
+    //-- these parameters specify size and position increment for the window 1
+    //-- if w1pi <0 the window will slide from the media end position to the beginning
+    lexParam.SkipSpace();
+    if(DoFindToken(cmdLine, _L("w1sz="), token) != KErrNone)
+        return  EFalse;
+
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+
+    nRes = lexParam.Val(uVal);
+    if(nRes!= KErrNone || uVal ==0)
+    {
+        test.Printf(_L("wrong 'w1sz' parameter value, it must be > 0 !\n"));   
+        return EFalse;
+    }
+
+    gWriteBufSize1 = uVal;
+    
+
+    lexParam.SkipSpace();
+    if(DoFindToken(cmdLine, _L("w1pi="), token) != KErrNone)
+        return  EFalse;
+
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+
+    nRes = lexParam.Val(nVal);
+    if(nRes!= KErrNone)
+    {
+        return EFalse;
+    }
+
+    gWriteGranularity1 = nVal;
+
+    //-- process "w2sz" & "w2pi" parameters. They shall look like: "w2sz=16384" & "w2pi=512"
+    //-- these parameters specify size and position increment for the window 1
+    //-- if w1pi <0 the window will slide from the media end position to the beginning
+    if(gWindowsNum == 2)
+    {
+        lexParam.SkipSpace();
+        if(DoFindToken(cmdLine, _L("w2sz="), token) != KErrNone)
+            return  EFalse;
+
+        lexParam.Assign(token);
+        lexParam.SkipSpace();
+
+        nRes = lexParam.Val(uVal);
+        if(nRes!= KErrNone || uVal ==0)
+        {
+            test.Printf(_L("wrong 'w2sz' parameter value, it must be > 0 !\n"));   
+            return EFalse;
+        }
+
+        gWriteBufSize2 = uVal;
+    
+
+        lexParam.SkipSpace();
+        if(DoFindToken(cmdLine, _L("w2pi="), token) != KErrNone)
+            return  EFalse;
+
+        lexParam.Assign(token);
+        lexParam.SkipSpace();
+
+        nRes = lexParam.Val(nVal);
+        if(nRes!= KErrNone)
+        {
+            return EFalse;
+        }
+
+        gWriteGranularity2 = nVal;
+     }
+    
+    //-- extract wrep=<number> parameter.
+    //-- it specifies how many times buffers will be written to the media
+    lexParam.SkipSpace();
+    if(DoFindToken(cmdLine, _L("wrep="), token) == KErrNone)
+    {
+    
+    
+    lexParam.Assign(token);
+    lexParam.SkipSpace();
+
+    nRes = lexParam.Val(uVal);
+    if(nRes!= KErrNone || uVal ==0 )
+    {
+        test.Printf(_L("wrong 'wrep' parameter value, it must be >0 !\n"));   
+        return EFalse;
+    }
+     
+        gNumWrites = uVal;
+    }
+    else
+    {
+        gNumWrites = 1;
+    }
+
+
+    return ETrue;
+}
+
+void PrintInfo()
+{
+    test.Printf(_L("Media write benchmark test. For use mostly with mmc/sd cards.\n"));
+    test.Printf(_L("Usage: See source code for command line parameters.\n"));
+}
+
+
+//---------------------------------------------------------------------------------
+
+void MainL(void)
+{
+    test.Title();
+    test.Start(_L("Start testing...\n"));
+
+    
+    //-- it will initialise global test parameters
+    if(!ParseCommandLine())
+    {
+        PrintInfo();
+        return;
+    }
+
+    if(!Initialise())
+    {
+        return; //-- something went wrong
+    }
+
+
+    DoWriteBMTest();
+    
+    Finalise();
+    
+    test.End();
+}
+
+
+TInt E32Main()
+{
+
+    CTrapCleanup* cleanup=CTrapCleanup::New() ; // get clean-up stack
+    
+    TRAPD(r,MainL());
+    
+    delete cleanup ; // destroy clean-up stack
+    
+    return r;
+}
+
+
+