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