--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/demandpaging/t_pagestress.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1231 @@
+// Copyright (c) 2006-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\demandpaging\t_pagestress.cpp
+// Demand Paging Stress Tests
+// t_pagestress.exe basically attempts to cause large ammounts of paging by calling
+// functions (256) which are alligned on a page boundary from multiple threads.
+// There are mulitple versions of t_pagestress installed on a test system to test rom
+// and code paging from various media types.
+// Usage:
+// t_pagestress and t_pagestress_rom
+// Common command lines:
+// t_pagestress lowmem
+// debug - switch on debugging information
+// silent - no output to the screen or serial port
+// check - check the allignments
+// single - run the tests in a single thread
+// multiple <numThreads> - run the tests in multiple threads where <numThreads>
+// interleave - force thread interleaving
+// prio - each thread reschedules in between each function call, causes lots of context changes
+// media - perform media access during the tests, very stressful
+// lowmem - low memory tests
+// forward - patern in which to execute function calls
+// backward - patern in which to execute function calls
+// random - patern in which to execute function calls
+// all - patern in which to execute function calls (forward, backward and random)
+// inst - for debugging a parameter passed to a spawned exe to give it an id.
+// iters <count> - the number of times to loop (a '-' means run forever)
+// t_pagestress causes a large ammount of paging by repeatedly calling
+// 256 functions which have been aligned on page boundaries from
+// multiple threads.
+// 1 - a single thread calling all functions
+// 2 - Multiple threads calling all functions
+// 3 - Multiple threads calling all functions with a priority change
+// after each function call
+// 4 - Multiple threads calling all functions with background
+// media activity
+// 5 - Multiple threads calling all functions with media activity and
+// a priority change after each function call
+// 6 - Multiple threads calling all functions with process interleave
+// 7 - Multiple threads calling all functions with process interleave
+// and a priority change after each function call
+// 8 - Multiple threads calling all functions with process interleave
+// media acess and a priority change after each function call
+// 9 - Multiple threads calling all functions with low available memory
+// 10 - Multiple threads calling all functions with low available memory,
+// starting with initial free ram.
+//
+//
+
+//! @SYMTestCaseID KBASE-T_PAGESTRESS-0327
+//! @SYMTestType UT
+//! @SYMPREQ PREQ1110
+//! @SYMTestCaseDesc Demand Paging Stress Tests
+//! @SYMTestActions 0 - Check the alignment of all functions
+//! @SYMTestExpectedResults All tests should pass.
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+
+#include <e32test.h>
+RTest test(_L("T_PAGESTRESS"));
+
+#include <e32rom.h>
+#include <u32hal.h>
+#include <f32file.h>
+#include <f32dbg.h>
+#include <e32msgqueue.h>
+#include <e32math.h>
+
+#include "testdefs.h"
+
+#ifdef __X86__
+#define TEST_ON_UNPAGED
+#endif
+
+
+/* The following line will cause t_pagestress.h to declare an array of function
+ * pointers to page boundary aligned functions that we can use in this test...
+ */
+#define TPS_DECLARE_ARRAY
+#include "t_pagestress.h"
+
+TBool TestDebug = EFalse;
+TBool TestSilent = EFalse;
+TBool TestExit = EFalse;
+
+TBool TestCheck = EFalse;
+TBool TestSingle = EFalse;
+TBool TestMultiple = EFalse;
+TBool TestForever = EFalse;
+TInt TestMaxLoops = 20;
+TInt TestMultipleThreadCount = 50;
+TInt TestInstanceId = 0;
+
+#define TEST_INTERLEAVE_PRIO EPriorityMore//EPriorityRealTime //23 // KNandThreadPriority - 1
+TBool TestInterleave = EFalse;
+TBool TestWeAreTheTestBase = EFalse;
+TBool TestBootedFromMmc = EFalse;
+TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect.
+#define TEST_NONE 0x0
+#define TEST_FORWARD 0x2
+#define TEST_BACKWARD 0x4
+#define TEST_RANDOM 0x8
+#define TEST_ALL (TEST_RANDOM | TEST_BACKWARD | TEST_FORWARD)
+TUint32 TestWhichTests = TEST_ALL;
+TBuf<32> TestNameBuffer;
+TBool TestPrioChange = ETrue;
+TBool TestStopMedia = EFalse;
+TBool TestMediaAccess = EFalse;
+#define TEST_LM_NUM_FREE 0
+#define TEST_LM_BLOCKSIZE 1
+#define TEST_LM_BLOCKS_FREE 4
+TBool TestLowMem = EFalse;
+RPageStressTestLdd Ldd;
+TInt TestPageSize = 4096;
+RSemaphore TestMultiSem;
+RMsgQueue<TBuf <64> > TestMsgQueue;
+TBool TestIsDemandPaged = ETrue;
+
+
+#define TEST_NEXT(__args) \
+ if (!TestSilent)\
+ test.Next __args;
+
+#define DBGS_PRINT(__args)\
+ if (!TestSilent)\
+ test.Printf __args ;
+
+#define DBGD_PRINT(__args)\
+ if (TestDebug)\
+ test.Printf __args ;\
+
+#define DEBUG_PRINT(__args)\
+if (!TestSilent)\
+ {\
+ if (aMsgQueue && aBuffer && aTheSem)\
+ {\
+ aBuffer->Zero();\
+ aBuffer->Format __args ;\
+ aTheSem->Wait();\
+ aMsgQueue->SendBlocking(*aBuffer);\
+ aTheSem->Signal();\
+ }\
+ else\
+ {\
+ test.Printf __args ;\
+ }\
+ }
+
+#define RUNTEST(__test, __error)\
+ if (!TestSilent)\
+ test(__test == __error);\
+ else\
+ __test;
+
+#define RUNTEST1(__test)\
+ if (!TestSilent)\
+ test(__test);
+
+#define DEBUG_PRINT1(__args)\
+if (TestDebug)\
+ {\
+ DEBUG_PRINT(__args)\
+ }
+
+//
+// CheckAlignments
+//
+// The following functions wanders through the function pointer array
+// declared in t_pagestress.h and ensures that the alignment has worked,
+// (a good start!) and then calls each of the functions in turn to
+// ensure that they work, simple first sanity check test.
+//
+
+TInt CheckAlignments()
+ {
+ // now it's time to play with the array of function pointers...
+ TInt seed = 1;
+ TUint32 index = 0;
+ TInt ret = KErrNone;
+
+ while (index < (PAGESTRESS_FUNC_COUNT - 1))
+ {
+ DBGD_PRINT((_L("\nAddress (%u) 0x%x difference to next %u\n"), index, (TUint32)PagestressFuncPtrs[index], (TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[index]));
+ if ((((TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[0]) % 4096) != 0)
+ {
+ DBGS_PRINT((_L("\nError! Allignment for %u is not offset of 4096 from index 0 0x%x 0x%x\n"), index, (TUint32)PagestressFuncPtrs[index + 1], (TUint32)PagestressFuncPtrs[0]));
+ ret = KErrGeneral;
+ }
+ //seed = PagestressFuncPtrs[index](seed, index);
+ seed = CallTestFunc(seed, index, index);
+ index ++;
+ }
+ return ret;
+ }
+
+//
+// RunThreadForward
+//
+// Walk through the function pointer array (forwards) calling each function
+//
+
+void RunThreadForward()
+ {
+ TInt seed = 1;
+ TUint32 index = 0;
+ RThread thisThread;
+
+ while (index < PAGESTRESS_FUNC_COUNT)
+ {
+ if (TestPrioChange)
+ {
+ TThreadPriority originalThreadPriority = thisThread.Priority();
+ thisThread.SetPriority(EPriorityLess);
+ User::AfterHighRes(0);
+ thisThread.SetPriority(originalThreadPriority);
+ }
+ //seed = PagestressFuncPtrs[index](seed, index);
+ seed = CallTestFunc(seed, index, index);
+ index ++;
+ }
+ }
+
+//
+// RunThreadBackward
+//
+// Walk through the function pointer array (backwards) calling each function
+//
+
+void RunThreadBackward()
+ {
+ TInt seed = 1;
+ TInt index = PAGESTRESS_FUNC_COUNT;
+ RThread thisThread;
+
+ while (index > 0)
+ {
+ if (TestPrioChange)
+ {
+ TThreadPriority originalThreadPriority = thisThread.Priority();
+ thisThread.SetPriority(EPriorityLess);
+ User::AfterHighRes(0);
+ thisThread.SetPriority(originalThreadPriority);
+ }
+ index --;
+ //seed = PagestressFuncPtrs[index](seed, index);
+ seed = CallTestFunc(seed, index, index);
+ }
+ }
+
+//
+// RunThreadRandom
+//
+// Walk through the function pointer array in a random order a number of times calling each function
+//
+
+void RunThreadRandom()
+ {
+ TInt seed = 1;
+ TInt index = 0;
+ TInt randNum;
+ RThread thisThread;
+
+ while (index < (TInt)PAGESTRESS_FUNC_COUNT)
+ {
+ if (TestPrioChange)
+ {
+ TThreadPriority originalThreadPriority = thisThread.Priority();
+ thisThread.SetPriority(EPriorityLess);
+ User::AfterHighRes(0);
+ thisThread.SetPriority(originalThreadPriority);
+ }
+ randNum = Math::Random();
+ randNum %= PAGESTRESS_FUNC_COUNT;
+ //seed = PagestressFuncPtrs[randNum](seed, randNum);
+ seed = CallTestFunc(seed, randNum, randNum);
+ index ++;
+ }
+ }
+
+
+//
+// PerformTestThread
+//
+// This is the function that actually does the work.
+// It is complicated a little because test.Printf can only be called from the first thread that calls it
+// so if we are using multiple threads we need to use a message queue to pass the debug info from the
+// child threads back to the parent for the parent to then call printf.
+//
+//
+
+LOCAL_C void PerformTestThread(TInt aThreadIndex,
+ RMsgQueue<TBuf <64> > *aMsgQueue = NULL,
+ TBuf<64> *aBuffer = NULL,
+ RSemaphore *aTheSem = NULL)
+ {
+ TUint start = User::TickCount();
+
+ DEBUG_PRINT1((_L("%S : thread Starting %d\n"), &TestNameBuffer, aThreadIndex));
+
+ // now select how we do the test...
+ TInt iterIndex;
+
+ if (TEST_ALL == (TestWhichTests & TEST_ALL))
+ {
+ #define LOCAL_ORDER_INDEX1 6
+ #define LOCAL_ORDER_INDEX2 3
+ TInt order[LOCAL_ORDER_INDEX1][LOCAL_ORDER_INDEX2] = { {TEST_FORWARD, TEST_BACKWARD,TEST_RANDOM},
+ {TEST_FORWARD, TEST_RANDOM, TEST_BACKWARD},
+ {TEST_BACKWARD,TEST_FORWARD, TEST_RANDOM},
+ {TEST_BACKWARD,TEST_RANDOM, TEST_FORWARD},
+ {TEST_RANDOM, TEST_FORWARD, TEST_BACKWARD},
+ {TEST_RANDOM, TEST_BACKWARD,TEST_FORWARD}};
+ TInt whichOrder = 0;
+
+ for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
+ {
+ TInt selOrder = ((aThreadIndex + 1) * (iterIndex + 1)) % LOCAL_ORDER_INDEX1;
+ for (whichOrder = 0; whichOrder < LOCAL_ORDER_INDEX2; whichOrder ++)
+ {
+ switch (order[selOrder][whichOrder])
+ {
+ case TEST_FORWARD:
+ DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadForward();
+ break;
+
+ case TEST_BACKWARD:
+ DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadBackward();
+ break;
+
+ case TEST_RANDOM:
+ DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadRandom();
+ break;
+
+ default: // this is really an error.
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (TestWhichTests & TEST_FORWARD)
+ {
+ for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
+ {
+ DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadForward();
+ }
+ }
+
+ if (TestWhichTests & TEST_BACKWARD)
+ {
+ for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
+ {
+ DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadBackward();
+ }
+ }
+
+ if (TestWhichTests & TEST_RANDOM)
+ {
+ for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
+ {
+ DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
+ RunThreadRandom();
+ }
+ }
+ }
+ DEBUG_PRINT1((_L("%S : thread Exiting %d (tickcount %u)\n"), &TestNameBuffer, aThreadIndex, User::TickCount() - start));
+ }
+
+
+//
+// MultipleTestThread
+//
+// Thread function, one created for each thread in a multiple thread test.
+//
+
+LOCAL_C TInt MultipleTestThread(TAny* aUseTb)
+ {
+ TBuf<64> localBuffer;
+
+ if (TestInterleave)
+ {
+ RThread thisThread;
+ thisThread.SetPriority((TThreadPriority) TEST_INTERLEAVE_PRIO);
+ }
+
+ PerformTestThread((TInt) aUseTb, &TestMsgQueue, &localBuffer, &TestMultiSem);
+
+ return KErrNone;
+ }
+
+//
+// DoSingleTest
+//
+// Perform the single thread test, spawning a number of threads.
+//
+
+LOCAL_C void DoSingleTest()
+ {
+ PerformTestThread((TInt) TestInstanceId);
+ }
+
+//
+// FindDriveNumber
+//
+// Find the first read write drive.
+//
+
+TInt FindDriveNumber(RFs fs)
+ {
+ TDriveInfo driveInfo;
+ for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
+ {
+ TInt r = fs.Drive(driveInfo, drvNum);
+ if (r >= 0)
+ {
+ if (driveInfo.iType == EMediaHardDisk)
+ return (drvNum);
+ }
+ }
+ return -1;
+ }
+
+//
+// FindFsNANDDrive
+//
+// Find the NAND drive
+//
+
+static TInt FindFsNANDDrive(RFs& aFs)
+ {
+ TDriveList driveList;
+ TDriveInfo driveInfo;
+ TInt r=aFs.DriveList(driveList);
+ if (r == KErrNone)
+ {
+ for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum<KMaxDrives; ++drvNum)
+ {
+ if(!driveList[drvNum])
+ continue; //-- skip unexisting drive
+
+ if (aFs.Drive(driveInfo, drvNum) == KErrNone)
+ {
+ if(driveInfo.iMediaAtt&KMediaAttPageable)
+ {
+ TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected; // skip ROFS partitions
+ if(!readOnly)
+ {
+ if ((drvNum==DriveNumber) || (DriveNumber<0)) // only test if running on this drive
+ {
+ return (drvNum);
+ }
+ }
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+//
+// FindMMCDriveNumber
+//
+// Find the first read write drive.
+//
+
+TInt FindMMCDriveNumber(RFs& aFs)
+ {
+ TDriveInfo driveInfo;
+ for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
+ {
+ TInt r = aFs.Drive(driveInfo, drvNum);
+ if (r >= 0)
+ {
+ if (driveInfo.iType == EMediaHardDisk)
+ return (drvNum);
+ }
+ }
+ return -1;
+ }
+
+//
+// PerformRomAndFileSystemAccess
+//
+// Access the rom and dump it out to one of the writeable partitions...
+// really just to make the media server a little busy during the test.
+//
+
+TInt PerformRomAndFileSystemAccessThread(RMsgQueue<TBuf <64> > *aMsgQueue = NULL,
+ TBuf<64> *aBuffer = NULL,
+ RSemaphore *aTheSem = NULL)
+ {
+ TUint maxBytes = KMaxTUint;
+ TInt startTime = User::TickCount();
+
+ RFs fs;
+ RFile file;
+ if (KErrNone != fs.Connect())
+ {
+ DEBUG_PRINT(_L("PerformRomAndFileSystemAccessThread : Can't connect to the FS\n"));
+ return KErrGeneral;
+ }
+
+ // get info about the ROM...
+ TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
+ TUint8* start;
+ TUint8* end;
+ if(romHeader->iPageableRomStart)
+ {
+ start = (TUint8*)romHeader + romHeader->iPageableRomStart;
+ end = start + romHeader->iPageableRomSize;
+ }
+ else
+ {
+ start = (TUint8*)romHeader;
+ end = start + romHeader->iUncompressedSize;
+ }
+ if (end <= start)
+ return KErrGeneral;
+
+ // read all ROM pages in a random order...and write out to file in ROFs,
+ TUint size = end - start - TestPageSize;
+ if(size > maxBytes)
+ size = maxBytes;
+
+ TUint32 random=1;
+ TPtrC8 rom;
+ TUint8 *theAddr;
+
+ TInt drvNum = TestBootedFromMmc ? FindMMCDriveNumber(fs) : FindFsNANDDrive(fs);
+ TBuf<32> filename = _L("d:\\Pageldrtst.tmp");
+ if (drvNum >= 0)
+ {
+ filename[0] = 'a' + drvNum;
+ DEBUG_PRINT((_L("%S : Filename %S\n"), &TestNameBuffer, &filename));
+ }
+ else
+ DEBUG_PRINT((_L("PerformRomAndFileSystemAccessThread : error getting drive num\n")));
+
+ for(TInt i=size/(TestPageSize); i>0; --i)
+ {
+ DEBUG_PRINT1((_L("%S : Opening the file\n"), &TestNameBuffer));
+ if (KErrNone != file.Replace(fs, filename, EFileWrite))
+ {
+ DEBUG_PRINT((_L("%S : Opening the file Failed!\n"), &TestNameBuffer));
+ }
+
+ random = random*69069+1;
+ theAddr = (TUint8*)(start+((TInt64(random)*TInt64(size))>>32));
+ if (theAddr + TestPageSize > end)
+ {
+ DEBUG_PRINT((_L("%S : address is past the end 0x%x / 0x%x\n"), &TestNameBuffer, (TInt)theAddr, (TInt)end));
+ }
+ rom.Set(theAddr,TestPageSize);
+ DEBUG_PRINT1((_L("%S : Writing the file\n"), &TestNameBuffer));
+ TInt ret = file.Write(rom);
+ if (ret != KErrNone)
+ {
+ DEBUG_PRINT1((_L("%S : Write returned error %d\n"), &TestNameBuffer, ret));
+ }
+ DEBUG_PRINT1((_L("%S : Closing the file\n"), &TestNameBuffer));
+ file.Close();
+
+ DEBUG_PRINT1((_L("%S : Deleting the file\n"), &TestNameBuffer));
+ ret = fs.Delete(filename);
+ if (KErrNone != ret)
+ {
+ DEBUG_PRINT((_L("%S : Delete returned error %d\n"), &TestNameBuffer, ret));
+ }
+ if (TestStopMedia)
+ break;
+ }
+ fs.Close();
+ DEBUG_PRINT1((_L("Done in %d ticks\n"), User::TickCount() - startTime));
+ return KErrNone;
+ }
+
+
+//
+// PerformRomAndFileSystemAccess
+//
+// Thread function, kicks off the file system access.
+//
+
+LOCAL_C TInt PerformRomAndFileSystemAccess(TAny* )
+ {
+ TBuf<64> localBuffer;
+
+ PerformRomAndFileSystemAccessThread(&TestMsgQueue, &localBuffer, &TestMultiSem);
+
+ return KErrNone;
+ }
+
+//
+// DoMultipleTest
+//
+// Perform the multiple thread test, spawning a number of threads.
+// It is complicated a little because test.Printf can only be called from the first thread that calls it
+// so if we are using multiple threads we need to use a message queue to pass the debug info from the
+// child threads back to the parent for the parent to then call printf.
+//
+#define DOTEST(__operation, __condition)\
+ if (aLowMem) \
+ {\
+ __operation;\
+ while (!__condition)\
+ {\
+ Ldd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\
+ __operation;\
+ }\
+ RUNTEST1(__condition);\
+ }\
+ else\
+ {\
+ __operation;\
+ RUNTEST1(__condition);\
+ }
+
+void DoMultipleTest(TBool aLowMem = EFalse)
+ {
+ TInt index;
+
+ RThread *pTheThreads = (RThread *)User::AllocZ(sizeof(RThread) * TestMultipleThreadCount);
+ TInt *pThreadInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount);
+
+ TRequestStatus mediaStatus;
+ RThread mediaThread;
+
+ TInt ret;
+ DOTEST((ret = TestMsgQueue.CreateLocal(TestMultipleThreadCount * 10, EOwnerProcess)),
+ (KErrNone == ret));
+
+ DOTEST((ret = TestMultiSem.CreateLocal(1)),
+ (KErrNone == ret));
+
+ // make sure we have a priority higher than that of the threads we spawn...
+ RThread thisThread;
+ TThreadPriority savedThreadPriority = thisThread.Priority();
+ const TThreadPriority KMainThreadPriority = EPriorityMuchMore;
+ __ASSERT_COMPILE(KMainThreadPriority>TEST_INTERLEAVE_PRIO);
+ thisThread.SetPriority(KMainThreadPriority);
+
+ if (TestMediaAccess)
+ {
+ TestStopMedia = EFalse;
+ mediaThread.Create(_L(""),PerformRomAndFileSystemAccess,KDefaultStackSize,NULL,NULL);
+ mediaThread.Logon(mediaStatus);
+ RUNTEST1(mediaStatus == KRequestPending);
+ mediaThread.Resume();
+ }
+
+ // spawn some processes to call the functions....
+ for (index = 0; index < TestMultipleThreadCount; index++)
+ {
+ DBGD_PRINT((_L("%S : Starting thread.%d!\n"), &TestNameBuffer, index));
+ DOTEST((ret = pTheThreads[index].Create(_L(""),MultipleTestThread,KDefaultStackSize,NULL,(TAny*) index)),
+ (ret == KErrNone));
+ pTheThreads[index].Resume();
+ pThreadInUse[index] = 1;
+ }
+
+ // now process any messages sent from the child threads.
+ TBool anyUsed = ETrue;
+ TBuf<64> localBuffer;
+
+ while(anyUsed)
+ {
+ anyUsed = EFalse;
+ // check the message queue and call printf if we get a message.
+ while (KErrNone == TestMsgQueue.Receive(localBuffer))
+ {
+ DBGS_PRINT((localBuffer));
+ }
+
+ // walk through the thread list to check which are still alive.
+ for (index = 0; index < TestMultipleThreadCount; index++)
+ {
+ if (pThreadInUse[index])
+ {
+ if (pTheThreads[index].ExitType() != EExitPending)
+ {
+ if (pTheThreads[index].ExitType() == EExitPanic)
+ {
+ DBGS_PRINT((_L("%S : Thread Panic'd %d...\n"), &TestNameBuffer, index));
+ }
+ pThreadInUse[index] = EFalse;
+ pTheThreads[index].Close();
+ }
+ else
+ {
+ anyUsed = ETrue;
+ }
+ }
+ }
+ User::AfterHighRes(50000);
+ }
+
+ if (TestMediaAccess)
+ {
+ TestStopMedia = ETrue;
+ DBGD_PRINT((_L("%S : Waiting for media thread to exit...\n"), &TestNameBuffer));
+ User::WaitForRequest(mediaStatus);
+ mediaThread.Close();
+ }
+
+ TestMsgQueue.Close();
+ TestMultiSem.Close();
+
+ // cleanup the resources and exit.
+ User::Free(pTheThreads);
+ User::Free(pThreadInUse);
+
+ thisThread.SetPriority(savedThreadPriority);
+ }
+
+
+//
+// ParseCommandLine
+//
+// read the arguments passed from the command line and set global variables to
+// control the tests.
+//
+
+TBool ParseCommandLine()
+ {
+ TBuf<256> args;
+ User::CommandLine(args);
+ TLex lex(args);
+ TBool retVal = ETrue;
+
+ // initially test for arguments, the parse them, if not apply some sensible defaults.
+ TBool foundArgs = EFalse;
+
+ FOREVER
+ {
+ TPtrC token=lex.NextToken();
+ if(token.Length()!=0)
+ {
+ if ((token == _L("help")) || (token == _L("-h")) || (token == _L("-?")))
+ {
+ DBGS_PRINT((_L("\nUsage: %S [debug] [check] [single | multiple <numThreads>] [forward | backward | random | all] [iters <iters>] [media] [lowmem] [interleave]\n'-' indicated infinity.\n\n"), &TestNameBuffer));
+ test.Getch();
+ }
+ else if (token == _L("debug"))
+ {
+ if (!TestSilent)
+ {
+ TestDebug = ETrue;
+ TestPrioChange = ETrue;
+ }
+ }
+ else if (token == _L("silent"))
+ {
+ TestSilent = ETrue;
+ TestDebug = EFalse;
+ }
+ else if (token == _L("check"))
+ {
+ TestCheck = ETrue;
+ }
+ else if (token == _L("single"))
+ {
+ TestSingle = ETrue;
+ }
+ else if (token == _L("multiple"))
+ {
+ TPtrC val=lex.NextToken();
+ TLex lexv(val);
+ TInt value;
+
+ if (lexv.Val(value)==KErrNone)
+ {
+ if ((value <= 0) || (value > 100))
+ {
+ TestMultipleThreadCount = 10;
+ }
+ else
+ {
+ TestMultipleThreadCount = value;
+ }
+ }
+ else
+ {
+ DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
+ retVal = EFalse;
+ break;
+ }
+ TestMultiple = ETrue;
+ }
+ else if (token == _L("prio"))
+ {
+ TestPrioChange = !TestPrioChange;
+ }
+ else if (token == _L("lowmem"))
+ {
+ TestLowMem = ETrue;
+ }
+ else if (token == _L("media"))
+ {
+ TestMediaAccess = ETrue;
+ }
+ else if (token == _L("forward"))
+ {
+ TestWhichTests = TEST_FORWARD;
+ }
+ else if (token == _L("backward"))
+ {
+ TestWhichTests = TEST_BACKWARD;
+ }
+ else if (token == _L("random"))
+ {
+ TestWhichTests = TEST_RANDOM;
+ }
+ else if (token == _L("all"))
+ {
+ TestWhichTests = TEST_ALL;
+ }
+ else if (token == _L("iters"))
+ {
+ TPtrC val=lex.NextToken();
+ TLex lexv(val);
+ TInt value;
+
+ if (val==_L("-"))
+ {
+ TestForever = ETrue;
+ TestMaxLoops = KMaxTInt;
+ }
+ else
+ {
+ if (lexv.Val(value)==KErrNone)
+ {
+ TestMaxLoops = value;
+ }
+ else
+ {
+ DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
+ retVal = EFalse;
+ break;
+ }
+ }
+ }
+ else if (token == _L("interleave"))
+ {
+ TestInterleave = ETrue;
+ }
+ else if (token == _L("inst"))
+ {
+ TPtrC val=lex.NextToken();
+ TLex lexv(val);
+ TInt value;
+
+ if (lexv.Val(value)==KErrNone)
+ {
+ TestInstanceId = value;
+ }
+ }
+ else
+ {
+ if ((foundArgs == EFalse) && (token.Length() == 1))
+ {
+ // Single letter argument...only run on MMC drive
+ if (token.CompareF(_L("d")) == 0)
+ {
+ break;
+ }
+ else
+ {
+ if (!TestSilent)
+ {
+ test.Title();
+ test.Start(_L("Skipping non drive 'd' - Test Exiting."));
+ test.End();
+ }
+ foundArgs = ETrue;
+ TestExit = ETrue;
+ break;
+ }
+ }
+ DBGS_PRINT((_L("Unknown argument '%S' was ignored.\n"), &token));
+ break;
+ }
+ foundArgs = ETrue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (!foundArgs)
+ {
+ retVal = EFalse;
+ }
+ return retVal;
+ }
+
+//
+// AreWeTheTestBase
+//
+// Test whether we are the root of the tests.
+//
+
+void AreWeTheTestBase(void)
+ {
+ if (!TestSilent)
+ {
+ TFileName filename(RProcess().FileName());
+
+ TParse myParse;
+ myParse.Set(filename, NULL, NULL);
+ TestNameBuffer.Zero();
+ TestNameBuffer.Append(myParse.Name());
+ TestNameBuffer.Append(_L(".exe"));
+
+ TestWeAreTheTestBase = !TestNameBuffer.Compare(_L("t_pagestress.exe"));
+
+ RFs fs;
+ if (KErrNone != fs.Connect())
+ {
+ TEntry anEntry;
+ TInt retVal = fs.Entry(_L("z:\\test\\mmcdemandpaginge32tests.bat"), anEntry);
+ if (retVal == KErrNone)
+ {
+ TestBootedFromMmc = ETrue;
+ }
+ else
+ {
+ TestBootedFromMmc = EFalse;
+ }
+ fs.Close();
+ }
+
+ }
+ else
+ {
+ TestNameBuffer.Zero();
+ TestNameBuffer.Append(_L("t_pagestress.exe"));
+ }
+ }
+
+//
+// PerformAutoTest
+//
+// Perform the autotest
+//
+void PerformAutoTest()
+ {
+ SVMCacheInfo tempPages;
+
+ if (TestIsDemandPaged)
+ {
+ UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
+ DBGS_PRINT((_L("PerformAutoTest : Start cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
+ tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
+ }
+ TestInterleave = EFalse;
+ TestPrioChange = EFalse;
+ TestMediaAccess = EFalse;
+
+#if defined __ARMCC__ || defined __X86__
+ // Currently we only build aligned DLLs on ARMV5 and X86 builds.
+ TEST_NEXT((_L("Alignment Check.")));
+ RUNTEST1(CheckAlignments() == KErrNone);
+#endif
+
+ TestMaxLoops = 2;
+ TestWhichTests = TEST_RANDOM;
+
+ TEST_NEXT((_L("Single thread all.")));
+ DoSingleTest();
+
+ TEST_NEXT((_L("Multiple threads all.")));
+ DoMultipleTest();
+
+ TestPrioChange = ETrue;
+ TEST_NEXT((_L("Multiple threads all with prio.")));
+ DoMultipleTest();
+
+ TestPrioChange = EFalse;
+ TestMediaAccess = ETrue;
+ TEST_NEXT((_L("Multiple threads all with media activity.")));
+ DoMultipleTest();
+
+ TestPrioChange = ETrue;
+ TestMediaAccess = ETrue;
+ TEST_NEXT((_L("Multiple threads all with media activity and prio.")));
+ DoMultipleTest();
+
+ TestInterleave = ETrue;
+ TestPrioChange = EFalse;
+ TestMediaAccess = EFalse;
+
+ TEST_NEXT((_L("Multiple threads random with interleave.")));
+ DoMultipleTest();
+
+ TestPrioChange = ETrue;
+ TEST_NEXT((_L("Multiple threads random with interleave and prio.")));
+ DoMultipleTest();
+
+ TestMediaAccess = ETrue;
+ TEST_NEXT((_L("Multiple threads random with media interleave and prio.")));
+ DoMultipleTest();
+
+ if (TestIsDemandPaged)
+ {
+ UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
+ DBGS_PRINT((_L("PerformAutoTest : End cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
+ tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
+ }
+ TestInterleave = EFalse;
+ TestPrioChange = EFalse;
+ TestMediaAccess = EFalse;
+ }
+
+//
+// DoLowMemTest
+//
+// Low Memory Test
+//
+
+void DoLowMemTest()
+ {
+ TInt r = User::LoadLogicalDevice(KPageStressTestLddName);
+ RUNTEST1(r==KErrNone || r==KErrAlreadyExists);
+ RUNTEST(Ldd.Open(),KErrNone);
+
+ SVMCacheInfo tempPages;
+ memset(&tempPages, 0, sizeof(tempPages));
+
+ if (TestIsDemandPaged)
+ {
+ // get the old cache info
+ UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
+ TInt minSize = 8 * 4096;
+ TInt maxSize = 256 * 4096;
+ UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+ }
+
+ // First load some pages onto the page cache
+ TestMaxLoops = 1;
+ TestWhichTests = TEST_RANDOM;
+ DoSingleTest();
+
+ Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
+ TEST_NEXT((_L("Single thread with Low memory.")));
+ TestMultipleThreadCount = 25;
+ TestInterleave = EFalse;
+ TestMaxLoops = 20;
+ TestPrioChange = EFalse;
+ TestMediaAccess = EFalse;
+ TestWhichTests = TEST_ALL;
+
+ DoSingleTest();
+
+ Ldd.DoConsumeRamFinish();
+
+ TEST_NEXT((_L("Multiple thread with Low memory.")));
+ // First load some pages onto the page cache
+ TestMaxLoops = 1;
+ TestWhichTests = TEST_RANDOM;
+ DoSingleTest();
+
+ Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
+
+ TestWhichTests = TEST_ALL;
+ TestMaxLoops = 10;
+ TestMultipleThreadCount = 25;
+ DoMultipleTest(ETrue);
+
+ Ldd.DoConsumeRamFinish();
+
+ TEST_NEXT((_L("Multiple thread with Low memory, with starting free ram.")));
+ // First load some pages onto the page cache
+ TestMaxLoops = 1;
+ TestWhichTests = TEST_RANDOM;
+ DoSingleTest();
+
+ Ldd.DoConsumeRamSetup(32, TEST_LM_BLOCKSIZE);
+
+ TestWhichTests = TEST_ALL;
+ TestMaxLoops = 10;
+ TestMultipleThreadCount = 25;
+ DoMultipleTest(ETrue);
+
+ Ldd.DoConsumeRamFinish();
+
+ TEST_NEXT((_L("Close test driver")));
+ Ldd.Close();
+ RUNTEST(User::FreeLogicalDevice(KPageStressTestLddName), KErrNone);
+ if (TestIsDemandPaged)
+ {
+ TInt minSize = tempPages.iMinSize;
+ TInt maxSize = tempPages.iMaxSize;
+ UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+ }
+ }
+
+//
+// E32Main
+//
+// Main entry point.
+//
+
+TInt E32Main()
+ {
+#ifndef TEST_ON_UNPAGED
+ TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
+ if(!romHeader->iPageableRomStart)
+ {
+ TestIsDemandPaged = EFalse;
+ }
+#endif
+ TUint start = User::TickCount();
+
+ TBool parseResult = ParseCommandLine();
+
+ if (TestExit)
+ {
+ return KErrNone;
+ }
+
+ AreWeTheTestBase();
+
+ TInt minSize = 8 * 4096;
+ TInt maxSize = 64 * 4096;
+ SVMCacheInfo tempPages;
+ memset(&tempPages, 0, sizeof(tempPages));
+ if (TestIsDemandPaged)
+ {
+ // get the old cache info
+ UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
+ // set the cache to our test value
+ UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+ }
+
+ // get the page size.
+ UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&TestPageSize,0);
+
+ if (!TestSilent)
+ {
+ test.Title();
+ test.Start(_L("Demand Paging stress tests..."));
+ test.Printf(_L("%S\n"), &TestNameBuffer);
+ }
+
+ if (parseResult)
+ {
+ if (!TestSilent)
+ {
+ extern TInt *CheckLdmiaInstr(void);
+ test.Printf(_L("%S : CheckLdmiaInstr\n"), &TestNameBuffer);
+ TInt *theAddr = CheckLdmiaInstr();
+ test.Printf(_L("%S : CheckLdmiaInstr complete 0x%x...\n"), &TestNameBuffer, (TInt)theAddr);
+ }
+ if (TestCheck)
+ {
+ CheckAlignments();
+ }
+ if (TestLowMem)
+ {
+ DoLowMemTest();
+ }
+ if (TestSingle)
+ {
+ DoSingleTest();
+ }
+ if (TestMultiple)
+ {
+ DoMultipleTest();
+ }
+ }
+ else
+ {
+ PerformAutoTest();
+
+ DoLowMemTest();
+
+ if (TestWeAreTheTestBase)
+ {
+ RProcess theProcess;
+ TRequestStatus status;
+
+ TInt retVal = theProcess.Create(_L("t_pagestress_rom.exe"),_L(""));
+ if (retVal != KErrNotFound)
+ {
+ RUNTEST1(retVal == KErrNone);
+ theProcess.Logon(status);
+ RUNTEST1(status == KRequestPending);
+ theProcess.Resume();
+ User::WaitForRequest(status);
+ if (theProcess.ExitType() != EExitPending)
+ {
+ RUNTEST1(theProcess.ExitType() != EExitPanic);
+ }
+ }
+ }
+ }
+
+ if (TestIsDemandPaged)
+ {
+ minSize = tempPages.iMinSize;
+ maxSize = tempPages.iMaxSize;
+ // put the cache back to the the original values.
+ UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+ }
+
+ if (!TestSilent)
+ {
+ test.Printf(_L("%S : Complete (%u ticks)\n"), &TestNameBuffer, User::TickCount() - start);
+ test.End();
+ }
+ return 0;
+ }
+
+