diff -r 000000000000 -r 96e5fb8b040d kerneltest/f32test/demandpaging/t_pagestress.cpp --- /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 - run the tests in multiple threads where +// 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 - 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 +RTest test(_L("T_PAGESTRESS")); + +#include +#include +#include +#include +#include +#include + +#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 > 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 > *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= 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= 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 > *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 ] [forward | backward | random | all] [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; + } + +