diff -r 000000000000 -r 96e5fb8b040d kerneltest/f32test/demandpaging/loader/t_pageldrtst.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/demandpaging/loader/t_pageldrtst.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,5143 @@ +// 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\loader\t_pageldrtst.cpp +// Demand Paging Loader Stress Tests +// Demand Paging Loader stress tests attempt to cause as much paging as possible +// whilst putting the system various types of load. +// t_pageldrtst.exe is the root of the tests, it in turn will start copies of +// itself stored in various types of media (t_pageldrtst_rom.exe for example). +// It also loads DLLs from various media, each DLL containing simple functions +// that are aligned on page boundaries, so each function call is likely to +// cause a page fault. +// Usage: +// t_pageldrtst and t_pageldrtst_rom +// Common command lines: +// t_pageldrtst - run the auto test suite +// t_pageldrtst lowmem - run the low memory tests +// t_pageldrtst chunks - run the chunk tests +// t_pageldrtst chunks+ - run the chunk tests (same as used in autotest) +// t_pageldrtst echunks - run the really stressful chunk tests +// t_pageldrtst auto debug - run the autotest but with debug output to the serial port +// t_pageldrtst d_exc - run the d_exc tests +// Arguments: +// single - run the tests in a single thread +// multiple - run the tests in multiple threads where +// auto - dummy param to trick the tests into running the auto test suite with extra params +// fullauto - param to make the tests perform the full automatic stress test +// 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 +// mmc - only use the mmc media for media access to test file caching +// min - min cache size in pages +// max - max cache size in pages +// chunks - simple chunk stress tests +// chunks+ - the chunk auto tests +// echunks - extremem chunks tests +// nochunkdata - don't check the integrity of the data in the chunks +// lowmem - low memory tests +// dll - only load dll's +// exe - only start exe's (t_pagestress) +// self - only start copies of self (t_pageldrtst from various media) +// complete - dll, exe and self. +// rom - only load from ROM +// base - only load the base DLL and exe's (from code) +// mixed - rom and base. +// all_media - load dlls and exes from all media +// debug - switch on debugging information +// silent - no output to the screen or serial port +// noclean - don't delete copied files on exit +// d_exc - run the d_exc tests +// global - load dlls once globally +// thread - load dlls once per thread +// func - load dlls in the test function (default and most stressful) +// 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) +// reaper - test the reaper. +// btrace - test the btrace code. +// defrag - test the ram defrag code. +// stressfree - set the page cache to stress free size and run tests. +// t_pageldrtst causes a large ammount of paging by repeatedly calling +// functions from multiple DLLs which include 64 functions which have +// been aligned on page boundaries from multiple threads, whilst causing +// background paging by spawning copies of itself and t_pagestress. +// The test also endeavours to stress the loader by loading and unloading +// DLLs from multiple threads from various types of media at the same +// time as stressing the media, testing chunks, the reaper and changing +// thread priorities. +// 002 Load thrashing, test rapid loading and unloading of DLLs from +// multiple threads (DEF100158) +// 003 Multiple threads loading DLLs in random pattern +// 004 Multiple threads loading EXE, SELF and DLLs in random pattern with +// all media, loaded in thread with prio change +// 005 Multiple threads loading EXE, SELF and DLLs in random pattern with +// all media, loaded globally with prio change +// 006 Multiple threads loading EXE, SELF and DLLs in random pattern with +// all media, loaded in func with process interleaving +// 007 Multiple threads loading EXE, SELF and DLLs in random pattern with +// all media, loaded in func with process interleaving, prio change +// and media access +// 008 Low Memory setup test +// 009 Low Memory, Multiple threads loading EXE, SELF and DLLs in random +// pattern, loaded in func. +// 010 Low Memory setup test +// 011 Low Memory, Multiple threads loading EXE, SELF and DLLs in random +// pattern, loaded in func with process interleaving, +// prio change and media access +// 012 Close test driver +// 013 Chunk tests, Multiple threads loading EXE, SELF and DLLs in random +// pattern with ROM / ROFS media, loaded in func with prio change +// 014 Reaper tests with Multiple threads loading EXE, SELF and DLLs in random +// pattern with all media +// 015 Reaper tests with Multiple threads loading EXE, SELF and DLLs in random +// pattern with all media, prio change and process interleaving +// 016 d_exc check test +// +// + +//! @SYMTestCaseID KBASE-T_PAGELDRTST-0326 +//! @SYMTestType UT +//! @SYMPREQ PREQ1110 +//! @SYMTestCaseDesc Demand Paging Loader Stress Tests +//! @SYMTestActions 001 Demand Paging loader stress tests... +//! @SYMTestExpectedResults All tests should pass. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "t_hash.h" +#include "paging_info.h" + +#ifndef TEST_AUTOTEST +#define TEST_RUN_REAPERTEST +#define TEST_RUN_LOWMEMTEST +#define TEST_RUN_DEFRAGTEST +#define TEST_RUN_D_EXCTEST +#define TEST_RUN_CHUNKTEST +#define TEST_RUN_AUTOTEST +RTest test(_L("T_PAGELDRTST")); +#else +#ifdef TEST_RUN_REAPERTEST +RTest test(_L("T_PAGELDRTST_REAPER")); +#endif +#ifdef TEST_RUN_LOWMEMTEST +RTest test(_L("T_PAGELDRTST_LOWMEM")); +#endif +#ifdef TEST_RUN_DEFRAGTEST +RTest test(_L("T_PAGELDRTST_DEFRAG")); +#endif +#ifdef TEST_RUN_D_EXCTEST +RTest test(_L("T_PAGELDRTST_D_EXC")); +#endif +#ifdef TEST_RUN_CHUNKTEST +RTest test(_L("T_PAGELDRTST_CHUNK")); +#endif +#ifdef TEST_RUN_AUTOTEST +RTest test(_L("T_PAGELDRTST_AUTO")); +#endif +#endif //TEST_AUTOTEST + +const TInt KMessageBufSize = 80; +typedef TBuf TMessageBuf; + +//#define TEST_SHORT_TEST +//#define TEST_THRASHING_TEST +//#define TEST_ADD_FAT_MEDIA +#define TEST_DONT_RESET_STATS +#define TEST_MINIMAL_STATS +//#define TEST_KERN_HEAP +#define TEST_ADD_FRAGD_MEDIA +#ifdef TEST_ADD_FRAGD_MEDIA +#endif + +#if defined(_DEBUG) || defined(_DEBUG_RELEASE) +//#define WANT_FS_CACHE_STATS +#endif + +#ifdef __X86__ +#define TEST_ON_UNPAGED +#define TEST_NO_DEXC_IN_AUTO +#endif + + +#include "t_pagestress.h" +#include "t_pageldrtstdll.h" + +#include "t_ramstress.h" + +TBool TestDebug = EFalse; +TBool TestSilent = EFalse; +TBool TestExit = EFalse; +#define TEST_EXE 0x01 +#define TEST_DLL 0x02 +#define TEST_SELF 0x04 +#define TEST_EXE_SELF (TEST_EXE | TEST_SELF) +#define TEST_EXE_SELF_DLL (TEST_EXE | TEST_SELF | TEST_DLL) +TInt TestLoading = TEST_EXE_SELF_DLL; + +#define TEST_MEDIA_BASE (1 << KTestMediaBase) +#define TEST_MEDIA_ROM (1 << KTestMediaRom) +#define TEST_MEDIA_ROFS (1 << KTestMediaRofs) +#define TEST_MEDIA_EXT (1 << KTestMediaExt) +#define TEST_MEDIA_FAT (1 << KTestMediaFat) +#define TEST_MEDIA_MMC (1 << KTestMediaMmc) +#define TEST_MEDIA_ROM_BASE (TEST_MEDIA_ROM | TEST_MEDIA_BASE) +#define TEST_MEDIA_ALL (TEST_MEDIA_ROM | TEST_MEDIA_BASE | TEST_MEDIA_ROFS | TEST_MEDIA_EXT | TEST_MEDIA_MMC) + +typedef enum +{ + KTestMediaBase = 0, + KTestMediaRom, + KTestMediaExt, + KTestMediaRofs, +#ifdef TEST_ADD_FAT_MEDIA + KTestMediaFat, // this is the last one that is always present. +#endif + KTestMediaMmc, +#ifdef TEST_ADD_FRAGD_MEDIA + KTestMediaNandFrag, + KTestMediaMmcFrag, +#endif + KTestMediaCOUNT, +}ETestMediaType; +#ifdef TEST_ADD_FAT_MEDIA +#define TEST_MEDIA_COUNT_HACK (KTestMediaFat + 1) +#else +#define TEST_MEDIA_COUNT_HACK (KTestMediaRofs + 1) +#endif + +typedef enum +{ + KTestMediaAccessNone = 0, + KTestMediaAccessBasic, + KTestMediaAccessMultipleThreads, + KTestMediaAccessMultiplePattern, + KTestMediaAccessMixed, + KTestMediaAccessCOUNT, +}ETestMediaAccess; + +TInt TestWhichMedia = TEST_MEDIA_ROM_BASE; +TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect. +TBool TestSingle = EFalse; +TBool TestMultiple = EFalse; +TInt TestMaxLoops = 20; +#define TEST_2MEDIA_THREADS 20 +#define TEST_ALLMEDIA_THREADS 20 +TInt TestMultipleThreadCount = TEST_2MEDIA_THREADS; +TInt TestInstanceId = 0; +TBool TestWeAreTheTestBase = EFalse; +TBool TestBootedFromMmc = EFalse; +TBool TestOnlyFromMmc = EFalse; +TBool TestD_Exc = EFalse; +TBool TestNoClean = EFalse; +TBool TestFullAutoTest = EFalse; +#define TEST_DLL_GLOBAL 0x01 +#define TEST_DLL_THREAD 0x02 +#define TEST_DLL_FUNC 0x04 +TInt TestLoadDllHow = TEST_DLL_FUNC; +TBool TestIsAutomated = EFalse; + +#define TEST_INTERLEAVE_PRIO EPriorityMore//EPriorityRealTime //23 // KNandThreadPriority - 1 +TBool TestInterleave = EFalse; +TFileName TestNameBuffer; +TBool TestPrioChange = EFalse; + +volatile TBool TestStopMedia = EFalse; +ETestMediaAccess TestMediaAccess = KTestMediaAccessNone; +#define TEST_NUM_FILES 5 + +RSemaphore TestMultiSem; +RMsgQueue TestMsgQueue; + +#define TEST_LM_NUM_FREE 0 +#define TEST_LM_BLOCKSIZE 1 +#define TEST_LM_BLOCKS_FREE 4 +TBool TestLowMem = EFalse; +TBool TestingLowMem = EFalse; +RPageStressTestLdd PagestressLdd; +RRamStressTestLdd RamstressLdd; + +TBool TestBtrace = EFalse; +TBool TestDefrag = EFalse; +TBool TestChunks = EFalse; +TBool TestChunksPlus = EFalse; +TBool TestExtremeChunks = EFalse; +TBool TestChunkData = ETrue; +TBool TestingChunks = EFalse; +volatile TBool TestDefragTestEnd = EFalse; +TBool TestingDefrag = EFalse; +volatile TBool TestThreadsExit = EFalse; +TInt TestPageSize = 4096; +RChunk TestChunk; +TInt TestCommitEnd = 0; +TUint8* TestChunkBase = NULL; +#define TEST_NUM_PAGES 64 +#define TEST_NUM_CHUNK_PAGES (TEST_NUM_PAGES * 2) +TBool TestChunkPageState[TEST_NUM_CHUNK_PAGES]; + +TBool TestReaper = EFalse; +TBool TestingReaper = EFalse; +TBool TestingReaperCleaningFiles = EFalse; +#define TEST_REAPER_ITERS 20 +#define TEST_DOT_PERIOD 30 +TBool TestStressFree = EFalse; +TInt TestMinCacheSize = 64 * 4096; +TInt TestMaxCacheSize = 128 * 4096; +TBool TestIsDemandPaged = ETrue; +#define TEST_MAX_ZONE_THREADS 8 +TUint TestZoneCount = 0; +TInt TickPeriod = 15625; + +#define TEST_NONE 0x0 +#define TEST_THRASH 0x1 +#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; +_LIT(KRomPath, "z:\\sys\\bin\\"); +_LIT(KMmcDefaultPath, "d:\\sys\\bin\\"); + +#define EXISTS(__val) ((__val == KErrNone) ? &KFileExists : &KFileMissing) +_LIT(KSysHash,"?:\\Sys\\Hash\\"); +_LIT(KTestBlank, ""); +_LIT(KFileExists, "Exists"); +_LIT(KFileMissing, "Missing"); +_LIT(KMultipleTest, "Multiple"); +_LIT(KSingleTest, "Single "); +_LIT(KTestExe, "Exe "); +_LIT(KTestDll, "Dll "); +_LIT(KTestSelf, "Self "); +_LIT(KTestBase, "Base "); +_LIT(KTestRom, "ROM "); +_LIT(KTestAll, "All "); +_LIT(KTestGlobal, "Global"); +_LIT(KTestThread, "Thread"); +_LIT(KTestFunc, "Func"); +_LIT(KTestInter, "Interleave "); +_LIT(KTestPrio, "Prio "); +_LIT(KTestMedia, "Media "); +_LIT(KTestLowMem, "LowMem "); +_LIT(KTestChunking, "Chunks "); +_LIT(KTestEChunking, "EChunks "); +_LIT(KTestChunkingPlus, "Chunks+ "); +_LIT(KTestReaper, "Reaper "); +_LIT(KTestThrash, "Thrash "); +_LIT(KTestForward, "Forward "); +_LIT(KTestBackward, "Backward "); +_LIT(KTestRandom, "Random "); + +typedef struct + { + TBool testFullAutoOnly; + TInt testLoading; + TInt testWhichMedia; + TBool testMultiple; + TInt testMaxLoops; + TInt testMultipleThreadCount; + TBool testLoadDllHow; + TBool testInterleave; + TBool testPrioChange; + ETestMediaAccess testMediaAccess; + TUint32 testWhichTests; + TBool testLowMem; + TInt testFreeRam; + }TTheTests; + +typedef struct + { + TInt ok; + TInt fail; + }TChunkTestPair; + +typedef struct + { + TChunkTestPair lock; + TChunkTestPair unlock; + TChunkTestPair decommit; + TChunkTestPair commit; + TChunkTestPair check; + } +TChunkTestStats; + +TChunkTestStats TestChunkStats[TEST_NUM_CHUNK_PAGES]; + + +TPtrC TestPsExeNames[KTestMediaCOUNT] = { _L("t_pagestress.exe"), + _L("t_pagestress_rom.exe"), + _L("t_pagestress_ext.exe"), + _L("t_pagestress_rofs.exe"), +#ifdef TEST_ADD_FAT_MEDIA + _L("t_pagestress_fat.exe"), +#endif + _L("t_pagestress_mmc.exe"), +#ifdef TEST_ADD_FRAGD_MEDIA + _L("t_pagestress_nfr.exe"), + _L("t_pagestress_mfr.exe"), +#endif + }; + +TPtrC TestPlExeNames[KTestMediaCOUNT] = { _L("t_pageldrtst.exe"), + _L("t_pageldrtst_rom.exe"), + _L("t_pageldrtst_ext.exe"), + _L("t_pageldrtst_rofs.exe"), +#ifdef TEST_ADD_FAT_MEDIA + _L("t_pageldrtst_fat.exe"), +#endif + _L("t_pageldrtst_mmc.exe"), +#ifdef TEST_ADD_FRAGD_MEDIA + _L("t_pageldrtst_nfr.exe"), + _L("t_pageldrtst_mfr.exe"), +#endif + }; + +_LIT(KDllBaseName, "t_pageldrtst"); + +TPtrC TestPlExtNames[KTestMediaCOUNT] = { _L(".dll"), + _L("_rom.dll"), + _L("_ext.dll"), + _L("_rofs.dll"), +#ifdef TEST_ADD_FAT_MEDIA + _L("_fat.dll"), +#endif + _L("_mmc.dll"), +#ifdef TEST_ADD_FRAGD_MEDIA + _L("_nfr.dll"), + _L("_mfr.dll"), +#endif + }; + + +TBool TestDllExesExist[KTestMediaCOUNT] = { EFalse, + EFalse, + EFalse, + EFalse, +#ifdef TEST_ADD_FAT_MEDIA + EFalse, +#endif + EFalse, +#ifdef TEST_ADD_FRAGD_MEDIA + EFalse, + EFalse, +#endif + }; +#define DBGS_PRINT(__args)\ + if (!TestSilent) test.Printf __args; + +#define DBGD_PRINT(__args)\ + if (TestDebug) test.Printf __args; + +void SendDebugMessage(RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + for (;;) + { + aTheSem->Wait(); + TInt r = aMsgQueue->Send(*aBuffer); + aTheSem->Signal(); + if (r != KErrOverflow) + return; + User::After(0); + } + } + +#define DEBUG_PRINT(__args)\ +if (!TestSilent) \ + {\ + if (aMsgQueue && aBuffer && aTheSem)\ + {\ + aBuffer->Zero();\ + aBuffer->Format __args ;\ + SendDebugMessage(aMsgQueue, aBuffer, aTheSem);\ + }\ + 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)\ + } + +#define DOTEST(__operation, __condition)\ + if (aLowMem) \ + {\ + __operation;\ + while (!__condition)\ + {\ + DBGD_PRINT((_L("Releasing some memory on line %d\n"), __LINE__));\ + if (pTheSem)\ + pTheSem->Wait();\ + PagestressLdd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\ + if (pTheSem)\ + pTheSem->Signal();\ + __operation;\ + }\ + RUNTEST1(__condition);\ + }\ + else\ + {\ + __operation;\ + RUNTEST1(__condition);\ + } + +#define DOTEST1(__var, __func, __ok, __fail)\ + if (aLowMem) \ + {\ + __var = __func;\ + while (__var == __fail)\ + {\ + DBGD_PRINT((_L("Releasing some memory on line %d\n"), __LINE__));\ + if (pTheSem)\ + pTheSem->Wait();\ + PagestressLdd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\ + if (pTheSem)\ + pTheSem->Signal();\ + __var = __func;\ + }\ + if (__var != __ok)\ + DBGS_PRINT((_L("Failing on line %d with error %d\n"), __LINE__, __var));\ + RUNTEST1(__var == __ok);\ + }\ + else\ + {\ + __var = __func;\ + RUNTEST1(__var == __ok);\ + } + +#define DOLOADALLOC(__numDlls, __pTheLibs, __theSem)\ + if (TestingLowMem)\ + {\ + __pTheLibs = (PageLdrRLibrary *)User::AllocZ(sizeof(PageLdrRLibrary) * __numDlls);\ + while (__pTheLibs == NULL)\ + {\ + DEBUG_PRINT1((_L("Releasing some memory for alloc on line %d\n"), __LINE__));\ + if (__theSem)\ + __theSem->Wait();\ + PagestressLdd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\ + if (__theSem)\ + __theSem->Signal();\ + __pTheLibs = (PageLdrRLibrary *)User::AllocZ(sizeof(PageLdrRLibrary) * __numDlls);\ + }\ + }\ + else\ + {\ + __pTheLibs = (PageLdrRLibrary *)User::AllocZ(sizeof(PageLdrRLibrary) * __numDlls);\ + if (__pTheLibs == NULL)\ + return KErrGeneral;\ + } + +#define TEST_NEXT(__args) \ + if (!TestSilent)\ + test.Next __args; + +void DoStats(); +void CheckFilePresence(TBool aDoFileCopy); +void CleanupFiles(TBool silent); +typedef TInt (*TCallFunction)(TUint32 funcIndex, TInt param1, TInt param2); + +class PageLdrRLibrary : public RLibrary + { +public: + TInt TestLoadLibrary(const TDesC& aFileName, TInt aThreadIndex, RMsgQueue *aMsgQueue, TMessageBuf *aBuffer, RSemaphore *aTheSem); + TInt CloseLibrary(); + +public: + TBool iInUse; + TUint32 iFuncCount; + TLibraryFunction iInitFunc; + TLibraryFunction iFunctionCountFunc; + TCallFunction iCallFunctionFunc; + TLibraryFunction iSetCloseFunc; + }; + +TInt PageLdrRLibrary::CloseLibrary() + { + if (iInUse) + { + if (iSetCloseFunc) + (iSetCloseFunc)(); + Close(); + iFuncCount = 0; + iInitFunc = NULL; + iFunctionCountFunc = NULL; + iCallFunctionFunc = NULL; + iSetCloseFunc = NULL; + iInUse = EFalse; + } + return KErrNone; + } + +PageLdrRLibrary theGlobalLibs[PAGELDRTST_MAX_DLLS * KTestMediaCOUNT]; + +//////////////////////////////////////////////////////////// +// Template functions encapsulating ControlIo magic +// +GLDEF_D template +GLDEF_C TInt controlIo(RFs &fs, TInt drv, TInt fkn, C &c) +{ + TPtr8 ptrC((TUint8 *)&c, sizeof(C), sizeof(C)); + + TInt r = fs.ControlIo(drv, fkn, ptrC); + + return r; +} + +// +// FreeRam +// +// Get available free ram. +// + +TInt FreeRam() + { + // wait for any async cleanup in the supervisor to finish first... + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); + + TMemoryInfoV1Buf meminfo; + TInt r=UserHal::MemoryInfo(meminfo); + test (r==KErrNone); + return meminfo().iFreeRamInBytes; + } + +// +// 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; + } + + +// +// PageLdrRLibrary::TestLoadLibrary +// +// Load a library and initialise information about that library +// + +TInt PageLdrRLibrary::TestLoadLibrary(const TDesC& aFileName, + TInt aThreadIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TInt retVal = KErrNone; + if (TestingLowMem) + { + TBool whinged = EFalse; + TInt initialFreeRam = 0; + TInt freeRam = 0; + + while (1) + { + initialFreeRam = FreeRam(); + retVal = Load(aFileName); + freeRam = FreeRam(); + if (retVal == KErrNoMemory) + { + if (!whinged && (freeRam > (4 * TestPageSize))) + { + whinged = ETrue; + DEBUG_PRINT1((_L("Load() %d pages %S\n"), (freeRam / TestPageSize), &aFileName)); + if (TestIsDemandPaged) + { + SVMCacheInfo tempPages; + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + + DEBUG_PRINT1((_L("DPC : min %d max %d curr %d\n"), + tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize)); + DEBUG_PRINT1((_L(" : maxFree %d freeRam %d\n"), + tempPages.iMaxFreeSize, FreeRam())); + } + } + DEBUG_PRINT1((_L("Load() releasing some memory for %S (%d)\n"), &aFileName, retVal)); + if (aTheSem) + aTheSem->Wait(); + PagestressLdd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE); + if (aTheSem) + aTheSem->Signal(); + } + else + { + if (whinged) + { + DEBUG_PRINT((_L("Load() Ok %d pages (%d) %S\n"), ((initialFreeRam - freeRam) / TestPageSize), (freeRam / TestPageSize), &aFileName)); + } + break; + } + } + } + else + { + DEBUG_PRINT1((_L("Loading %S (%d)\n"), &aFileName, aThreadIndex)); + retVal = Load(aFileName); + if (retVal != KErrNone) + { + DEBUG_PRINT1((_L("Load failed %S (%d)\n"), &aFileName, aThreadIndex)); + if (TestingReaper ) + { + TInt tempIndex = 0; + TBool whinged = EFalse; + while ( ( (retVal == KErrNotFound) + || (retVal == KErrPermissionDenied) + || (retVal == KErrCorrupt) + || (retVal == KErrInUse)) + && ( TestingReaperCleaningFiles + || (tempIndex < TEST_REAPER_ITERS))) + { + User::After(2000000); + if (!whinged) + { + DEBUG_PRINT((_L("Load() retrying load for %S (%d)\n"), &aFileName, retVal)); + whinged = ETrue; + } + retVal = Load(aFileName); + if (!TestingReaperCleaningFiles) + { + tempIndex ++; + } + } + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Load() failing for %S (%d) idx %d\n"), &aFileName, retVal, tempIndex)); + } + } + else if (TestingDefrag) + { + TInt tempIndex = 0; + TBool whinged = EFalse; + while ((retVal == KErrGeneral) && (tempIndex < 10)) + { + User::After(20000); + if (!whinged) + { + DEBUG_PRINT((_L("Load() retrying load for %S (%d)\n"), &aFileName, retVal)); + whinged = ETrue; + } + retVal = Load(aFileName); + tempIndex ++; + } + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Load() failing for %S (%d) idx %d\n"), &aFileName, retVal, tempIndex)); + } + } + } + } + DEBUG_PRINT1((_L("Loaded %S (%d)\n"), &aFileName, aThreadIndex)); + if (retVal == KErrNone) + { + iInUse = ETrue; + iInitFunc = Lookup(PAGELDRTST_FUNC_Init); + iFunctionCountFunc = Lookup(PAGELDRTST_FUNC_FunctionCount); + iCallFunctionFunc = (TCallFunction)Lookup(PAGELDRTST_FUNC_CallFunction); + iSetCloseFunc = Lookup(PAGELDRTST_FUNC_SetClose); + if ( (iInitFunc != NULL) + && (iFunctionCountFunc != NULL) + && (iCallFunctionFunc != NULL) + && (iSetCloseFunc != NULL)) + { + retVal = (iInitFunc)(); + if (retVal == KErrNone) + { + iFuncCount = (iFunctionCountFunc)(); + if (iFuncCount != 0) + { + DEBUG_PRINT1((_L("Loaded ok %S (%d)\n"), &aFileName, aThreadIndex)); + return KErrNone; + } + retVal = KErrGeneral; + DEBUG_PRINT((_L("!!! bad count %S (%d)\n"), &aFileName, aThreadIndex)); + } + else + { + DEBUG_PRINT((_L("!!! init failed %S (%d)\n"), &aFileName, aThreadIndex)); + retVal = KErrGeneral; + } + } + else + { + DEBUG_PRINT((_L("!!! missing %S (%d)\n"), &aFileName, aThreadIndex)); + retVal = KErrGeneral; + } + } + else + { + DEBUG_PRINT((_L("Load() failed %S %d\n"), &aFileName, retVal)); +#ifdef WANT_FS_CACHE_STATS + RFs fs; + if (KErrNone != fs.Connect()) + { + DEBUG_PRINT(_L("TestLoadLibrary : Can't connect to the FS\n")); + } + else + { + TFileCacheStats stats1; + TInt drvNum = FindMMCDriveNumber(fs); + controlIo(fs,drvNum, KControlIoFileCacheStats, stats1); + + DEBUG_PRINT((_L("FSC: drv %d %c free %d used %d locked %d\n"), + drvNum, 'a' + drvNum, + stats1.iFreeCount, + stats1.iUsedCount, + stats1.iLockedSegmentCount)); + DEBUG_PRINT((_L(" : alloc %d lock %d closed %d\n"), + stats1.iAllocatedSegmentCount, + stats1.iFileCount, + stats1.iFilesOnClosedQueue)); + fs.Close(); + } +#endif //WANT_FS_CACHE_STATS + + if (TestIsDemandPaged) + { + SVMCacheInfo tempPages; + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + + DEBUG_PRINT((_L("DPC : min %d max %d curr %d\n"), + tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize)); + DEBUG_PRINT((_L(" : maxFree %d freeRam %d\n"), + tempPages.iMaxFreeSize, FreeRam())); + } + } + return retVal; + } + +// +// GetNumDlls +// +// Work out how many Dlls we will play with +// +TInt GetNumDlls() + { + TInt maxDllIndex; + + switch (TestWhichMedia) + { + default: + case TEST_MEDIA_BASE: + case TEST_MEDIA_ROM: + maxDllIndex = PAGELDRTST_MAX_DLLS; + break; + + case TEST_MEDIA_ROM_BASE: + maxDllIndex = PAGELDRTST_MAX_DLLS * 2; + break; + + case TEST_MEDIA_ALL: + maxDllIndex = PAGELDRTST_MAX_DLLS * KTestMediaCOUNT; + break; + } + return maxDllIndex; + } + +// +// LoadTheLibs +// +// Open DLLs for use in the tests. +// + +TInt LoadTheLibs(PageLdrRLibrary *aTheLibs, + TInt aLibCount, + TInt aThreadIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TBuf<128> nameBuffer; + TInt dllIndex = 0; + TInt realDllIndex = 0; + TInt dllOffset = -1; + TInt testWhich; + RThread thisThread; + + memset(aTheLibs, 0, sizeof(*aTheLibs) * aLibCount); + for (dllIndex = 0; dllIndex < aLibCount; dllIndex ++) + { + realDllIndex = (dllIndex + aThreadIndex) % PAGELDRTST_MAX_DLLS; +// realDllIndex = (dllIndex) % PAGELDRTST_MAX_DLLS; + if (realDllIndex == 0) + dllOffset ++; + + if ((TestWhichMedia & TEST_MEDIA_ALL) == TEST_MEDIA_ALL) + testWhich = (dllIndex + dllOffset) % KTestMediaCOUNT; + else if ((TestWhichMedia & TEST_MEDIA_ALL) == TEST_MEDIA_ROM_BASE) + testWhich = ((dllIndex + dllOffset) & 1) ? KTestMediaBase : KTestMediaRom; + else if (TestWhichMedia & TEST_MEDIA_BASE ) + testWhich = KTestMediaBase; + else + testWhich = KTestMediaRom; + + if (!TestDllExesExist[testWhich]) + testWhich = KTestMediaBase; + + nameBuffer.Format(_L("%S%d%S"), &KDllBaseName, realDllIndex, &TestPlExtNames[testWhich]); + + DEBUG_PRINT1((_L("LoadTheLibs[%02d] - loading %S\n"), aThreadIndex, &nameBuffer)); + TInt theErr = aTheLibs[dllIndex].TestLoadLibrary(nameBuffer, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (theErr != KErrNone) + { + DEBUG_PRINT((_L("LoadTheLibs[%02d] - fail %S %d\n"), aThreadIndex, &nameBuffer, theErr)); + return KErrGeneral; + } + else + { + DEBUG_PRINT1((_L("LoadTheLibs[%02d] - loaded %S OK\n"), aThreadIndex, &nameBuffer)); + } + if (TestThreadsExit) + { + DEBUG_PRINT((_L("LoadTheLibs[%02d] - cancelled\n"), aThreadIndex)); + return KErrCancel; + } + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + DEBUG_PRINT1((_L("LoadTheLibs[%02d] before priority change\n"), aThreadIndex)); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + DEBUG_PRINT1((_L("LoadTheLibs[%02d] after priority change\n"), aThreadIndex)); + } + } + DEBUG_PRINT((_L("LoadTheLibs[%02d] done\n"), aThreadIndex)); + return KErrNone; + } + +// +// CloseTheLibs +// +// Close the DLLs that we have previously opened +// + +void CloseTheLibs (PageLdrRLibrary *aTheLibs, + TInt aLibCount) + { + TInt dllIndex = 0; + + for (dllIndex = 0; dllIndex < aLibCount; dllIndex ++) + { + aTheLibs[dllIndex].CloseLibrary(); + } + memset(aTheLibs, 0, sizeof(*aTheLibs) * aLibCount); + } + +// +// RunThreadForward +// +// Walk through the function pointer array (forwards) calling each function +// + +TInt RunThreadForward(TInt aThreadIndex, + PageLdrRLibrary *aTheLibs, + TInt aMaxDllIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TInt seed = 1; + TUint32 index = 0; + RThread thisThread; + PageLdrRLibrary *pTheLibs = NULL; + TInt dllIndex = 0; + + if (TestLoadDllHow == TEST_DLL_FUNC) + { + DOLOADALLOC(aMaxDllIndex, pTheLibs, aTheSem); + if (pTheLibs) + { + TInt retVal = LoadTheLibs(pTheLibs, aMaxDllIndex, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Forward[%d] - load fail\n"), aThreadIndex)); + CloseTheLibs (pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + return retVal; + } + } + else + { + DEBUG_PRINT((_L("Forward[%d] - alloc fail\n"), aThreadIndex)); + return KErrGeneral; + } + } + else + { + pTheLibs = aTheLibs; + } + + for (dllIndex = 0; dllIndex < aMaxDllIndex; dllIndex ++) + { + index = 0; + while (index < pTheLibs[dllIndex].iFuncCount) + { + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + } + if (pTheLibs[dllIndex].iCallFunctionFunc) + seed = pTheLibs[dllIndex].iCallFunctionFunc(index, seed, index); + else + DEBUG_PRINT((_L("Forward[%d] : dll %d was NULL\n"), aThreadIndex, dllIndex)); + index ++; + if (TestThreadsExit) + break; + } + if (TestThreadsExit) + break; + } + if (TestLoadDllHow == TEST_DLL_FUNC) + { + CloseTheLibs(pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + } + return KErrNone; + } + +// +// RunThreadBackward +// +// Walk through the function pointer array (backwards) calling each function +// + +TInt RunThreadBackward(TInt aThreadIndex, + PageLdrRLibrary *aTheLibs, + TInt aMaxDllIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TInt seed = 1; + TUint32 index = 0; + RThread thisThread; + PageLdrRLibrary *pTheLibs = NULL; + TInt dllIndex = 0; + + if (TestLoadDllHow == TEST_DLL_FUNC) + { + DOLOADALLOC(aMaxDllIndex, pTheLibs, aTheSem); + if (pTheLibs) + { + TInt retVal = LoadTheLibs(pTheLibs, aMaxDllIndex, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Backward[%d] - load fail\n"), aThreadIndex)); + CloseTheLibs (pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + return retVal; + } + } + else + { + DEBUG_PRINT((_L("Backward[%d] - alloc fail\n"), aThreadIndex)); + return KErrGeneral; + } + } + else + { + pTheLibs = aTheLibs; + } + + for (dllIndex = aMaxDllIndex - 1; dllIndex >= 0; dllIndex --) + { + index = pTheLibs[dllIndex].iFuncCount; + while (index > 0) + { + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + } + if (pTheLibs[dllIndex].iCallFunctionFunc) + seed = pTheLibs[dllIndex].iCallFunctionFunc(index, seed, index); + else + DEBUG_PRINT((_L("Backward[%d] : dll %d was NULL\n"), aThreadIndex, dllIndex)); + index --; + if (TestThreadsExit) + break; + } + if (TestThreadsExit) + break; + } + if (TestLoadDllHow == TEST_DLL_FUNC) + { + CloseTheLibs(pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + } + return KErrNone; + } + +// +// RunThreadRandom +// +// Walk through the function pointer array in a random order a number of times calling each function +// + +TInt RunThreadRandom(TInt aThreadIndex, + PageLdrRLibrary *aTheLibs, + TInt aMaxDllIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TInt seed = 1; + TUint randNum; + RThread thisThread; + PageLdrRLibrary *pTheLibs = NULL; + TUint dllIndex = 0; + + if (TestLoadDllHow == TEST_DLL_FUNC) + { + DOLOADALLOC(aMaxDllIndex, pTheLibs, aTheSem); + if (pTheLibs) + { + TInt retVal = LoadTheLibs(pTheLibs, aMaxDllIndex, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Random[%d] - load fail\n"), aThreadIndex)); + CloseTheLibs (pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + return retVal; + } + } + else + { + DEBUG_PRINT((_L("Random[%d] - alloc fail\n"), aThreadIndex)); + return KErrGeneral; + } + } + else + { + pTheLibs = aTheLibs; + } + + + TUint funcCount = (TUint)pTheLibs[0].iFuncCount; + TInt iterCount = aMaxDllIndex * funcCount; + + // reduce the time for auto tests by reducing the number of cycles. + if (TestIsAutomated) + iterCount /= 4; + + while (iterCount > 0) + { + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + } + + randNum = (TUint)Math::Random(); + dllIndex = randNum % (TUint)aMaxDllIndex; + + randNum %= funcCount; + + if ( (randNum < funcCount) + && ((TInt)dllIndex < aMaxDllIndex)) + { + if (pTheLibs[dllIndex].iCallFunctionFunc) + { + seed = pTheLibs[dllIndex].iCallFunctionFunc(randNum, seed, randNum); + } + else + DEBUG_PRINT((_L("Random[%d] : dll %d was NULL\n"), aThreadIndex, dllIndex)); + } + else + { + DEBUG_PRINT((_L("Random[%d] : %d ERROR dllIndex %u rand %u\n"), aThreadIndex, iterCount, dllIndex, randNum)); + } + + --iterCount; + if (TestThreadsExit) + break; + } + + if (TestLoadDllHow == TEST_DLL_FUNC) + { + CloseTheLibs(pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + } + return KErrNone; + } + + +// +// ThrashThreadLoad +// +// Load and unload the DLLs rapidly to show up a timing window in the kernel. +// + +TInt ThrashThreadLoad (TInt aThreadIndex, + PageLdrRLibrary *aTheLibs, + TInt aMaxDllIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + if (TestLoadDllHow == TEST_DLL_FUNC) + { + PageLdrRLibrary *pTheLibs = NULL; + DOLOADALLOC(aMaxDllIndex, pTheLibs, aTheSem); + if (pTheLibs) + { + TInt retVal = LoadTheLibs(pTheLibs, aMaxDllIndex, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Thrash[%d] - load fail\n"), aThreadIndex)); + CloseTheLibs (pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + return retVal; + } + } + else + { + DEBUG_PRINT((_L("Thrash[%d] - alloc fail\n"), aThreadIndex)); + return KErrGeneral; + } + + CloseTheLibs(pTheLibs, aMaxDllIndex); + User::Free(pTheLibs); + } + return KErrNone; + } + + +// +// 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 TInt PerformTestThread(TInt aThreadIndex, + RMsgQueue *aMsgQueue = NULL, + TMessageBuf *aBuffer = NULL, + RSemaphore *aTheSem = NULL) + { + TUint start = User::TickCount(); + + TFullName n(RThread().Name()); + + DEBUG_PRINT((_L("%S : thread %d Executing %S\n"), &TestNameBuffer, aThreadIndex, &n)); + + // now select how we do the test... + TInt iterIndex; + + PageLdrRLibrary *pTheLibs = theGlobalLibs; + TInt maxDllIndex = GetNumDlls(); + + switch (TestLoadDllHow) + { + case TEST_DLL_THREAD: + pTheLibs = NULL; + DOLOADALLOC(maxDllIndex, pTheLibs, aTheSem); + if (pTheLibs) + { + TInt retVal = LoadTheLibs(pTheLibs, maxDllIndex, aThreadIndex, aMsgQueue, aBuffer, aTheSem); + if (retVal != KErrNone) + { + DEBUG_PRINT((_L("Perform[%d] - load fail\n"), aThreadIndex)); + CloseTheLibs (pTheLibs, maxDllIndex); + User::Free(pTheLibs); + return retVal; + } + } + else + { + DEBUG_PRINT((_L("Perform[%d] - alloc fail\n"), aThreadIndex)); + return KErrGeneral; + } + break; + + case TEST_DLL_GLOBAL: + pTheLibs = theGlobalLibs; + break; + + case TEST_DLL_FUNC: + default: + // do nowt + break; + } + + TInt retVal = KErrNone; + 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; ; ) + { + 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_PRINT((_L("%S : %d Iter %d.%d Forward\n"), + &TestNameBuffer, aThreadIndex, iterIndex, whichOrder)); + retVal = RunThreadForward(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + break; + + case TEST_BACKWARD: + DEBUG_PRINT((_L("%S : %d Iter %d.%d Backward\n"), + &TestNameBuffer, aThreadIndex, iterIndex, whichOrder)); + retVal = RunThreadBackward(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + break; + + case TEST_RANDOM: + DEBUG_PRINT((_L("%S : %d Iter %d.%d Random\n"), + &TestNameBuffer, aThreadIndex, iterIndex, whichOrder)); + retVal = RunThreadRandom(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + break; + + default: // this is really an error. + break; + } + DEBUG_PRINT((_L("%S : %d Iter %d.%d finished %d\n"), + &TestNameBuffer, aThreadIndex, iterIndex, whichOrder, retVal)); + if ((retVal == KErrCancel) && iterIndex > 0) + retVal = KErrNone; + if ((retVal != KErrNone) || TestThreadsExit) + break; + } + if ((retVal != KErrNone) || TestThreadsExit) + break; + if (++iterIndex >= TestMaxLoops) + break; + User::AfterHighRes(TEST_DOT_PERIOD/3*1000000); + } + } + else + { + if (TestWhichTests & TEST_FORWARD) + { + for (iterIndex = 0; ; ) + { + DEBUG_PRINT((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex)); + retVal = RunThreadForward(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + DEBUG_PRINT((_L("%S : %d Iter %d finished %d\n"), &TestNameBuffer, aThreadIndex, iterIndex, retVal)); + if ((retVal == KErrCancel) && iterIndex > 0) + retVal = KErrNone; + if ((retVal != KErrNone) || TestThreadsExit) + break; + if (++iterIndex >= TestMaxLoops) + break; + User::AfterHighRes(TEST_DOT_PERIOD/3*1000000); + } + } + + if (TestWhichTests & TEST_BACKWARD) + { + for (iterIndex = 0; ; ) + { + DEBUG_PRINT((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex)); + retVal = RunThreadBackward(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + DEBUG_PRINT((_L("%S : %d Iter %d finished %d\n"), &TestNameBuffer, aThreadIndex, iterIndex, retVal)); + if ((retVal == KErrCancel) && iterIndex > 0) + retVal = KErrNone; + if ((retVal != KErrNone) || TestThreadsExit) + break; + if (++iterIndex >= TestMaxLoops) + break; + User::AfterHighRes(TEST_DOT_PERIOD/3*1000000); + } + } + + if (TestWhichTests & TEST_RANDOM) + { + for (iterIndex = 0; ; ) + { + DEBUG_PRINT((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex)); + retVal = RunThreadRandom(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + DEBUG_PRINT((_L("%S : %d Iter %d finished %d\n"), &TestNameBuffer, aThreadIndex, iterIndex, retVal)); + if ((retVal == KErrCancel) && iterIndex > 0) + retVal = KErrNone; + if ((retVal != KErrNone) || TestThreadsExit) + break; + if (++iterIndex >= TestMaxLoops) + break; + User::AfterHighRes(TEST_DOT_PERIOD/3*1000000); + } + } + + if (TestWhichTests & TEST_THRASH) + { + for (iterIndex = 0; ; ) + { + DEBUG_PRINT((_L("%S : %d Iter %d Thrash Load\n"), &TestNameBuffer, aThreadIndex, iterIndex)); + retVal = ThrashThreadLoad(aThreadIndex, pTheLibs, maxDllIndex, aMsgQueue, aBuffer, aTheSem); + DEBUG_PRINT((_L("%S : %d Iter %d finished %d\n"), &TestNameBuffer, aThreadIndex, iterIndex, retVal)); + if ((retVal == KErrCancel) && iterIndex > 0) + retVal = KErrNone; + if ((retVal != KErrNone) || TestThreadsExit) + break; + if (++iterIndex >= TestMaxLoops) + break; + User::AfterHighRes(TEST_DOT_PERIOD/3*1000000); + } + } + } + + if (TestLoadDllHow == TEST_DLL_THREAD) + { + CloseTheLibs(pTheLibs, maxDllIndex); + User::Free(pTheLibs); + } + + DEBUG_PRINT((_L("%S : thread %d Exit (tick %u)\n"), &TestNameBuffer, aThreadIndex, User::TickCount() - start)); + return retVal; + } + + +// +// MultipleTestThread +// +// Thread function, one created for each thread in a multiple thread test. +// + +LOCAL_C TInt MultipleTestThread(TAny* aUseTb) + { + TInt ret; + TMessageBuf localBuffer; + + if (TestInterleave) + { + RThread thisThread; + thisThread.SetPriority((TThreadPriority) TEST_INTERLEAVE_PRIO); + } + + ret = PerformTestThread((TInt) aUseTb, &TestMsgQueue, &localBuffer, &TestMultiSem); + if (!TestingChunks) + { + if (ret != KErrNone) + User::Panic(_L("LOAD"), KErrGeneral); + } + return KErrNone; + } + +// +// StartExe +// +// Start an executable. +// + +TInt StartExe(RProcess& aTheProcesses, TRequestStatus* aPrStatus, TInt aIndex, TBool aLoadSelf, TBool aLowMem, RSemaphore *pTheSem = NULL) + { + TBuf<256> buffer; + TInt testWhich = KTestMediaRom; + //y_LIT(KTestDebug, "debug"); + _LIT(KTestSilent, "silent"); + + if ((TestWhichMedia & TEST_MEDIA_ALL) == TEST_MEDIA_ALL) + testWhich = aIndex % KTestMediaCOUNT; + else if ((TestWhichMedia & TEST_MEDIA_ALL) == TEST_MEDIA_ROM_BASE) + testWhich = (aIndex & 1) ? KTestMediaBase : KTestMediaRom; + else if (TestWhichMedia & TEST_MEDIA_BASE ) + testWhich = KTestMediaBase; + else + testWhich = KTestMediaRom; + + if (!TestDllExesExist[testWhich]) + testWhich = KTestMediaBase; + + buffer.Zero(); + TInt ret; + if (aLoadSelf) + { + buffer.Format(_L("single random dll %S iters %d inst %d"), + /* TestDebug ? &KTestDebug : */ &KTestSilent, TestMaxLoops, aIndex); + if (TestExtremeChunks) + buffer.Append(_L(" echunks")); + else if (TestChunksPlus) + buffer.Append(_L(" chunks prio")); + if (TestChunkData == EFalse) + buffer.Append(_L(" nochunkdata")); + DBGS_PRINT((_L("%S : Starting Process %d %S %S\n"), + &TestNameBuffer, aIndex, &TestPlExeNames[testWhich], &buffer)); + DOTEST1(ret,aTheProcesses.Create(TestPlExeNames[testWhich],buffer),KErrNone, KErrNoMemory); + } + else + { + buffer.Format(_L("single random %S iters %d inst %d"), + /* TestDebug ? &KTestDebug : */ &KTestSilent, TestMaxLoops, aIndex); + DBGS_PRINT((_L("%S : Starting Process %d %S %S\n"), + &TestNameBuffer, aIndex, &TestPsExeNames[testWhich], &buffer)); + DOTEST1(ret,aTheProcesses.Create(TestPsExeNames[testWhich],buffer),KErrNone, KErrNoMemory); + } + if (ret == KErrNone) + { + if(aPrStatus) + { + aTheProcesses.Logon(*aPrStatus); + RUNTEST1(*aPrStatus == KRequestPending); + } + aTheProcesses.Resume(); + } + return ret; + } + +// +// PerformRomAndFileSystemAccessThread +// +// 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(TInt aThreadId, + RMsgQueue *aMsgQueue, + TMessageBuf *aBuffer, + RSemaphore *aTheSem, + TBool aLowMem) + { + RThread thisThread; + TUint maxBytes = KMaxTUint; + TInt startTime = User::TickCount(); + RSemaphore *pTheSem = aTheSem; + 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 + TInt pageSize = 0; + UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0); + + TUint size = end - start - pageSize; + if(size > maxBytes) + size = maxBytes; + + TUint32 random = 1 + aThreadId; + TPtrC8 sourceData; + TUint8* theAddr; + HBufC8* checkData; + + DOTEST((checkData = HBufC8::New(pageSize + 10)), + (checkData != NULL)); + + if (!checkData) + { + DEBUG_PRINT((_L("RomAndFSThread %S : failed to alloc read buffer\n"), &TestNameBuffer)); + } + + TInt drvNum = (TestBootedFromMmc || TestOnlyFromMmc) ? FindMMCDriveNumber(fs) : FindFsNANDDrive(fs); + TBuf<32> filename; + + filename.Format(_L("?:\\Pageldrtst%d.tmp"), aThreadId); + if (drvNum >= 0) + { + DEBUG_PRINT((_L("%S : Filename %S\n"), &TestNameBuffer, &filename)); + } + else + { + DEBUG_PRINT((_L("RomAndFSThread : error getting drive num\n"))); + drvNum = 3; //make it 'd' by default. + } + filename[0] = 'a' + drvNum; + +#ifdef WANT_FS_CACHE_STATS + TInt allocatedSegmentCount = 0; + TInt filesOnClosedQueue = 0; +#endif + TInt ret; + while(1) + { + for(TInt i = size / (pageSize); i>0; --i) + { + DEBUG_PRINT1((_L("%S : Opening the file\n"), &TestNameBuffer)); + DOTEST((ret = file.Replace(fs, filename, EFileWrite)), + (KErrNone == ret)); + + random = random * 69069 + 1; + theAddr = (TUint8 *)(start + ((TInt64(random) * TInt64(size - pageSize)) >> 32)); + sourceData.Set(theAddr,pageSize); + DEBUG_PRINT1((_L("%S : Writing the file\n"), &TestNameBuffer)); + ret = file.Write(sourceData); + if (ret != KErrNone) + { + DEBUG_PRINT((_L("%S : Write returned error %d\n"), &TestNameBuffer, ret)); + } + DEBUG_PRINT1((_L("%S : Closing the file\n"), &TestNameBuffer)); + file.Close(); + + if (checkData) + { + TPtr8 theBuf = checkData->Des(); + +#ifdef WANT_FS_CACHE_STATS + // Page cache + TFileCacheStats stats1; + TFileCacheStats stats2; + ret = controlIo(fs,drvNum, KControlIoFileCacheStats, stats1); + if ((ret != KErrNone) && (ret != KErrNotSupported)) + { + DEBUG_PRINT((_L("%S : KControlIoFileCacheStats 1 failed %d\n"), &TestNameBuffer, ret)); + } + + if (aThreadId & 1) + { + // flush closed files queue + ret = fs.ControlIo(drvNum, KControlIoFlushClosedFiles); + if (ret != KErrNone) + { + DEBUG_PRINT((_L("%S : KControlIoFlushClosedFiles failed %d\n"), &TestNameBuffer, ret)); + } + } + else +#endif //WANT_FS_CACHE_STATS + { + // rename file to make sure it has cleared the cache. + TBuf<32> newname; + newname.Format(_L("d:\\Pageldrtst%d.temp"), aThreadId); + if (drvNum >= 0) + { + newname[0] = 'a' + drvNum; + } + fs.Rename(filename, newname); + filename = newname; + } +#ifdef WANT_FS_CACHE_STATS + ret = controlIo(fs,drvNum, KControlIoFileCacheStats, stats2); + if (ret != KErrNone && ret != KErrNotSupported) + { + DEBUG_PRINT((_L("%S : KControlIoFileCacheStats2 failed %d\n"), &TestNameBuffer, ret)); + } + + allocatedSegmentCount = (allocatedSegmentCount > stats1.iAllocatedSegmentCount) ? allocatedSegmentCount : stats1.iAllocatedSegmentCount; + filesOnClosedQueue = (filesOnClosedQueue > stats1.iFilesOnClosedQueue) ? filesOnClosedQueue : stats1.iFilesOnClosedQueue; +#endif //WANT_FS_CACHE_STATS + + DOTEST((ret = file.Open(fs, filename, EFileRead)), + (KErrNone == ret)); + // now read back the page that we wrote and compare with the source. + ret = file.Read(0, theBuf, pageSize); + if (ret == KErrNone) + { + ret = sourceData.Compare(theBuf); + if (ret != 0) + { + DEBUG_PRINT((_L("%S : read compare error %d\n"), &TestNameBuffer, ret)); + } + } + else + { + DEBUG_PRINT((_L("%S : failed read compare, error %d\n"), &TestNameBuffer, ret)); + } + file.Close(); + } + DEBUG_PRINT1((_L("%S : Deleting the file\n"), &TestNameBuffer)); + ret = fs.Delete(filename); + if (KErrNone != ret) + { + DEBUG_PRINT((_L("%S [%d] Delete %S Failed %d!\n"), &TestNameBuffer, aThreadId, &filename, ret)); + } + + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + DEBUG_PRINT1((_L("%S [%d] media thread before priority change, stop = %d\n"), &TestNameBuffer, aThreadId, TestStopMedia)); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + DEBUG_PRINT1((_L("%S [%d] media thread after priority change, stop = %d\n"), &TestNameBuffer, aThreadId, TestStopMedia)); + } + if (TestStopMedia) + break; + } + if (TestStopMedia) + break; + } + +#ifdef WANT_FS_CACHE_STATS + DEBUG_PRINT((_L("%S : [%d] allocPageCount %d filesClosedQueue %d \n"),&TestNameBuffer, aThreadId,allocatedSegmentCount,filesOnClosedQueue)); +#endif //WANT_FS_CACHE_STATS + + if (checkData) + { + delete checkData; + } + fs.Close(); + DEBUG_PRINT1((_L("Done in %d ticks\n"), User::TickCount() - startTime)); + return KErrNone; + } + +// +// PerformFileSystemAccessThread +// +// 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 PerformFileSystemAccessThread(TInt aThreadId, + RMsgQueue *aMsgQueue, + TMessageBuf *aBuffer, + RSemaphore *aTheSem, + TBool aLowMem) + { + RThread thisThread; + TInt startTime = User::TickCount(); + RSemaphore *pTheSem = aTheSem; + RFs fs; + RFile file; + if (KErrNone != fs.Connect()) + { + DEBUG_PRINT(_L("PerformFileSystemAccessThread : Can't connect to the FS\n")); + return KErrGeneral; + } + + // read all ROM pages in a random order...and write out to file in ROFs + TInt pageSize = 0; + UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0); + + HBufC8* checkData; + HBufC8* sourceData; + TUint32 random = 1 + aThreadId; + TInt dataSize = pageSize + (pageSize / 2); + + DOTEST((sourceData = HBufC8::New(dataSize)), + (sourceData != NULL)); + if (!sourceData) + { + DEBUG_PRINT((_L("RomAndFSThread %S : failed to alloc read buffer\n"), &TestNameBuffer)); + fs.Close(); + return KErrGeneral; + } + + DOTEST((checkData = HBufC8::New(dataSize)), + (checkData != NULL)); + if (!checkData) + { + DEBUG_PRINT((_L("RomAndFSThread %S : failed to alloc read buffer\n"), &TestNameBuffer)); + } + + TInt drvNum = (TestBootedFromMmc || TestOnlyFromMmc) ? FindMMCDriveNumber(fs) : FindFsNANDDrive(fs); + TBuf<32> filename; + + if (drvNum < 0) + { + drvNum = 3; //make it 'd' by default. + DEBUG_PRINT((_L("FSAccessThread : error getting drive num\n"))); + } + +#ifdef WANT_FS_CACHE_STATS + TInt allocatedSegmentCount = 0; + TInt filesOnClosedQueue = 0; +#endif + TInt fileIndex; + TInt ret; + + TPtr8 pBuf = sourceData->Des(); + + while (1) + { + TUint32 randomStart = random; + // write the file + for (fileIndex = 0; fileIndex < TEST_NUM_FILES; fileIndex ++) + { + filename.Format(_L("%c:\\pldrtst%d_%d.tmp"), 'a' + drvNum, aThreadId, fileIndex); + + DEBUG_PRINT1((_L("%S : Opening the file\n"), &TestNameBuffer)); + + DOTEST ((ret = file.Replace(fs, filename, EFileWrite)), + (KErrNone == ret)); + + pBuf.Zero(); + if (fileIndex & 1) + { + TInt fillSize = dataSize / sizeof(TUint32); + while (fillSize > 0) + { + random = random * 69069 + 1; + pBuf.Append((const TUint8 *) &random, sizeof(random)); + fillSize --; + } + } + else + { + pBuf.Fill('x',dataSize); + } + + + DEBUG_PRINT1((_L("%S : Writing the file\n"), &TestNameBuffer)); + ret = file.Write(sourceData->Des()); + if (ret != KErrNone) + { + DEBUG_PRINT((_L("%S : Write returned error %d\n"), &TestNameBuffer, ret)); + } + DEBUG_PRINT1((_L("%S : Closing the file\n"), &TestNameBuffer)); + file.Close(); + } + + random = randomStart; + // check the file + for (fileIndex = 0; fileIndex < TEST_NUM_FILES; fileIndex ++) + { + filename.Format(_L("%c:\\pldrtst%d_%d.tmp"), 'a' + drvNum, aThreadId, fileIndex); + + if (checkData) + { + TPtr8 theBuf = checkData->Des(); + +#ifdef WANT_FS_CACHE_STATS + // Page cache + TFileCacheStats stats1; + TFileCacheStats stats2; + ret = controlIo(fs,drvNum, KControlIoFileCacheStats, stats1); + if ((ret != KErrNone) && (ret != KErrNotSupported)) + { + DEBUG_PRINT((_L("%S : KControlIoFileCacheStats 1 failed %d\n"), &TestNameBuffer, ret)); + } + + if (aThreadId & 1) + { + // flush closed files queue + ret = fs.ControlIo(drvNum, KControlIoFlushClosedFiles); + if (ret != KErrNone) + { + DEBUG_PRINT((_L("%S : KControlIoFlushClosedFiles failed %d\n"), &TestNameBuffer, ret)); + } + } + else +#endif //WANT_FS_CACHE_STATS + { + // rename file to make sure it has cleared the cache. + TBuf<32> newname; + newname.Format(_L("%c:\\pldrtst%d_%d.temp"), 'a' + drvNum, aThreadId, fileIndex); + fs.Rename(filename, newname); + filename = newname; + } +#ifdef WANT_FS_CACHE_STATS + ret = controlIo(fs,drvNum, KControlIoFileCacheStats, stats2); + if (ret != KErrNone && ret != KErrNotSupported) + { + DEBUG_PRINT((_L("%S : KControlIoFileCacheStats2 failed %d\n"), &TestNameBuffer, ret)); + } + allocatedSegmentCount = (allocatedSegmentCount > stats1.iAllocatedSegmentCount) ? allocatedSegmentCount : stats1.iAllocatedSegmentCount; + filesOnClosedQueue = (filesOnClosedQueue > stats1.iFilesOnClosedQueue) ? filesOnClosedQueue : stats1.iFilesOnClosedQueue; +#endif //WANT_FS_CACHE_STATS + + DOTEST((ret = file.Open(fs, filename, EFileRead)), + (KErrNone == ret)); + // now read back the page that we wrote and compare with the source. + ret = file.Read(0, theBuf, dataSize); + if (ret == KErrNone) + { + pBuf.Zero(); + if (fileIndex & 1) + { + TInt fillSize = dataSize / sizeof(TUint32); + while (fillSize > 0) + { + random = random * 69069 + 1; + pBuf.Append((const TUint8 *) &random, sizeof(random)); + fillSize --; + } + } + else + { + pBuf.Fill('x',dataSize); + } + + ret = sourceData->Des().Compare(theBuf); + if (ret != 0) + { + DEBUG_PRINT((_L("%S :compare error %S %d\n"), &TestNameBuffer, &filename, ret)); + } + } + else + { + DEBUG_PRINT((_L("%S : failed read compare, error %d\n"), &TestNameBuffer, ret)); + } + file.Close(); + } + DEBUG_PRINT1((_L("%S : Deleting the file\n"), &TestNameBuffer)); + ret = fs.Delete(filename); + if (KErrNone != ret) + { + DEBUG_PRINT((_L("%S [%d] Delete %S Failed %d!\n"), &TestNameBuffer, aThreadId, &filename, ret)); + } + if (TestPrioChange) + { + TThreadPriority originalThreadPriority = thisThread.Priority(); + thisThread.SetPriority(EPriorityLess); + User::AfterHighRes(0); + thisThread.SetPriority(originalThreadPriority); + } + if (TestStopMedia) + break; + } + if (TestStopMedia) + break; + } +#ifdef WANT_FS_CACHE_STATS + DEBUG_PRINT((_L("%S : [%d] allocPageCount %d filesClosedQueue %d \n"),&TestNameBuffer, aThreadId,allocatedSegmentCount,filesOnClosedQueue)); +#endif //WANT_FS_CACHE_STATS + + if (checkData) + { + delete checkData; + } + delete sourceData; + 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* aParam) + { + TMessageBuf localBuffer; + TInt threadId = (TInt) aParam; + TInt retVal = KErrGeneral; + + if (TestInterleave) + { + RThread thisThread; + thisThread.SetPriority((TThreadPriority) TEST_INTERLEAVE_PRIO); + } + + switch (TestMediaAccess) + { + default: + break; + + case KTestMediaAccessBasic: + case KTestMediaAccessMultipleThreads: + retVal = PerformRomAndFileSystemAccessThread(threadId, &TestMsgQueue, &localBuffer, &TestMultiSem, TestingLowMem); + break; + + case KTestMediaAccessMultiplePattern: + retVal = PerformFileSystemAccessThread(threadId, &TestMsgQueue, &localBuffer, &TestMultiSem, TestingLowMem); + break; + + case KTestMediaAccessMixed: + if (threadId < ((TestMultipleThreadCount + 1) / 2)) + retVal = PerformRomAndFileSystemAccessThread(threadId, &TestMsgQueue, &localBuffer, &TestMultiSem, TestingLowMem); + else + retVal = PerformFileSystemAccessThread(threadId, &TestMsgQueue, &localBuffer, &TestMultiSem, TestingLowMem); + break; + } + return retVal; + } + + +// +// DisplayTestBanner +// +// Output a header showing the test parameters. +// + +void DisplayTestBanner(TBool aMultiple) + { + DBGS_PRINT((_L("%S : what = %S%S%S(0x%x), media = %S%S%S(0x%x)\n"), + aMultiple ? &KMultipleTest : &KSingleTest, + TestLoading & TEST_EXE ? &KTestExe : &KTestBlank, + TestLoading & TEST_DLL ? &KTestDll : &KTestBlank, + TestLoading & TEST_SELF ? &KTestSelf : &KTestBlank, + TestLoading, + TestWhichMedia & TEST_MEDIA_BASE ? &KTestBase : &KTestBlank, + TestWhichMedia & TEST_MEDIA_ROM ? &KTestRom : &KTestBlank, + (TestWhichMedia & TEST_MEDIA_ALL) == TEST_MEDIA_ALL ? &KTestAll : &KTestBlank, + TestWhichMedia)); + DBGS_PRINT((_L(" : maxLoops = %d, threads = %d, loadHow = %S (0x%x)\n"), + TestMaxLoops, + TestMultipleThreadCount, + TestLoadDllHow == TEST_DLL_GLOBAL ? &KTestGlobal : TestLoadDllHow == TEST_DLL_THREAD ? &KTestThread : &KTestFunc, TestLoadDllHow)); + DBGS_PRINT((_L(" : options = %S%S%S%S%S%S, which = %S%S%S%S (0x%x)\n"), + TestInterleave ? &KTestInter : &KTestBlank, + TestPrioChange ? &KTestPrio: &KTestBlank, + (TestMediaAccess == KTestMediaAccessNone) ? &KTestBlank : &KTestMedia, + TestingLowMem ? &KTestLowMem : &KTestBlank, + TestExtremeChunks ? &KTestEChunking : TestChunksPlus ? &KTestChunkingPlus : TestingChunks ? &KTestChunking : &KTestBlank, + TestingReaper ? &KTestReaper : &KTestBlank, + TestWhichTests & TEST_THRASH ? &KTestThrash : &KTestBlank, + TestWhichTests & TEST_FORWARD ? &KTestForward : &KTestBlank, + TestWhichTests & TEST_BACKWARD ? &KTestBackward : &KTestBlank, + TestWhichTests & TEST_RANDOM ? &KTestRandom : &KTestBlank, + TestWhichTests)); + } + +// +// DoSingleTest +// +// Perform the single thread test, spawning a number of threads. +// + +LOCAL_C TInt DoSingleTest(TBool aLowMem = EFalse) + { + TUint start = User::TickCount(); + RSemaphore *pTheSem = NULL; + TInt ret = KErrNone; + DisplayTestBanner(EFalse); + + if (aLowMem) + { + DOTEST1(ret,TestMultiSem.CreateLocal(1),KErrNone, KErrNoMemory); + pTheSem = &TestMultiSem; + } + if (TestLoading & TEST_EXE) + { + RProcess theProcess; + TRequestStatus status; + + if (StartExe(theProcess, &status, 0, EFalse, aLowMem, pTheSem) == KErrNone) + { + User::WaitForRequest(status); + if (theProcess.ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Process Panic'd...\n"), &TestNameBuffer)); + } + theProcess.Close(); + } + } + + if (TestLoading & TEST_SELF) + { + RProcess theProcess; + TRequestStatus status; + + if (StartExe(theProcess, &status, 0, ETrue, aLowMem,pTheSem) == KErrNone) + { + User::WaitForRequest(status); + if (theProcess.ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Process Panic'd...\n"), &TestNameBuffer)); + } + theProcess.Close(); + } + } + + if (TestLoading & TEST_DLL) + { + TInt maxDlls = GetNumDlls(); + if (TestLoadDllHow == TEST_DLL_GLOBAL) + { + TInt retVal = LoadTheLibs(theGlobalLibs, maxDlls, TestInstanceId, NULL, NULL, pTheSem); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("DoSingleTest - unable to load libs\n") )); + CloseTheLibs (theGlobalLibs, PAGELDRTST_MAX_DLLS); + if (aLowMem) + { + TestMultiSem.Close(); + } + return KErrGeneral; + } + } + + ret = PerformTestThread((TInt) TestInstanceId, NULL, NULL, pTheSem); + + if (TestLoadDllHow == TEST_DLL_GLOBAL) + { + CloseTheLibs(theGlobalLibs, maxDlls); + } + } + if (aLowMem) + { + TestMultiSem.Close(); + } + + if (!TestSilent) + { + TInt end = User::TickCount(); + TInt time = TUint((TUint64)(end-start)*(TUint64)TickPeriod/(TUint64)1000000); + DBGS_PRINT((_L("\n%S : Single Test : (%u seconds)\n"), &TestNameBuffer, time)); + } + + return ret; + } + +// +// FillPage +// +// Fill a page with test data +// + +void FillPage(TUint aOffset) + { + if (TestChunkData) + { + TUint32* ptr = (TUint32 *)((TUint8 *)TestChunkBase+aOffset); + TUint32* ptrEnd = (TUint32 *)((TUint8 *)ptr + TestPageSize); + do + { + *ptr = 0x55000000 + aOffset; + ptr ++; + aOffset += 4; + } + while(ptr>32; + if (index >= TEST_NUM_CHUNK_PAGES) + TestChunkingIndexFails ++; + + theOffset = index * TestPageSize; + if (theOffset < TestCommitEnd) + { + if (lockit) + { + if (decomit) + { + ret = TestChunk.Decommit(theOffset,TestPageSize); + if (KErrNone == ret) + TestChunkStats[index].decommit.ok ++; + else + TestChunkStats[index].decommit.fail ++; + ret = TestChunk.Commit(theOffset,TestPageSize); + if (KErrNone == ret) + { + TestChunkStats[index].commit.ok ++; + FillPage(theOffset); + TestChunkPageState[index] = ETrue; + } + else + { + TestChunkStats[index].commit.fail ++; + TestChunkPageState[index] = EFalse; + } + ret = KErrNone; + } + else + { + ret = TestChunk.Lock(theOffset,TestPageSize); + if (KErrNone == ret) + { + TestChunkStats[index].lock.ok ++; + if (!CheckPage(index, theOffset)) + FillPage(theOffset); + TestChunkPageState[index] = ETrue; + } + else + { + TestChunkStats[index].lock.fail ++; + TestChunkPageState[index] = EFalse; + } + } + decomit = !decomit; + } + else + { + if (TestChunkPageState[index]) + { + // this one should still be locked so the data should be ok. + if (KErrNone == TestChunk.Lock(theOffset,TestPageSize)) + { + TestChunkStats[index].lock.ok ++; + CheckPage(index, theOffset); + } + else + TestChunkStats[index].lock.fail ++; + } + ret = TestChunk.Unlock(theOffset,TestPageSize); + if (KErrNone == ret) + TestChunkStats[index].unlock.ok ++; + else + TestChunkStats[index].unlock.fail ++; + TestChunkPageState[index] = EFalse; + } + if (KErrNone != ret) + { + // so now we need to commit another page in this pages place. + ret = TestChunk.Commit(theOffset,TestPageSize); + if (KErrNone != ret) + { + TestChunkStats[index].commit.fail ++; + //DBGS_PRINT((_L("%S : DoSomeChunking[%03d] index %03d failed to commit a page %d\n"), &TestNameBuffer, iters, index, ret)); + TestChunkPageState[index] = EFalse; + } + else + { + TestChunkStats[index].commit.ok ++; + FillPage(theOffset); + TestChunkPageState[index] = ETrue; + } + } + lockit = !lockit; + } + else + { + RDebug::Printf("DoSomeChunking - offset was bad %d / %d", theOffset, TestCommitEnd); + } + iters --; + } + } + +// +// 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. +// + +TInt DoMultipleTest(TBool aLowMem = EFalse) + { + TInt index; + TUint start = User::TickCount(); + RThread *pTheThreads = NULL; + TInt *pThreadInUse = NULL; + + RProcess *pTheProcesses = NULL; + TInt *pProcessInUse = NULL; + + RThread *pMedThreads = NULL; + TInt *pMedInUse = NULL; + + TRequestStatus mediaStatus; + RThread mediaThread; + TInt ret; + + RSemaphore *pTheSem = NULL; + + DisplayTestBanner(ETrue); + + TestThreadsExit = EFalse; + + DOTEST1(ret,TestMultiSem.CreateLocal(1),KErrNone, KErrNoMemory); + + pTheSem = &TestMultiSem; + if (TestLoading & TEST_DLL) + { + DOTEST((pTheThreads = (RThread *)User::AllocZ(sizeof(RThread) * TestMultipleThreadCount)), + (pTheThreads != NULL)) + DOTEST((pThreadInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount)), + (pThreadInUse != NULL)); + RUNTEST1(pTheThreads && pThreadInUse); + if (!(pTheThreads && pThreadInUse)) + return KErrGeneral; + } + + if (TestLoading & TEST_EXE_SELF) + { + DOTEST((pTheProcesses = (RProcess *)User::AllocZ(sizeof(RProcess) * TestMultipleThreadCount)), + (pTheProcesses != NULL)); + DOTEST((pProcessInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount)), + (pProcessInUse != NULL)); + RUNTEST1(pTheProcesses && pProcessInUse); + if (!(pTheProcesses && pProcessInUse)) + return KErrGeneral; + } + + if (!TestSilent) + { + DOTEST1(ret,TestMsgQueue.CreateLocal(TestMultipleThreadCount * 10, EOwnerProcess),KErrNone, KErrNoMemory); + if (ret != KErrNone) + return KErrGeneral; + } + + if (TestMediaAccess != KTestMediaAccessNone) + { + if (TestMediaAccess != KTestMediaAccessBasic) + { + TestStopMedia = EFalse; + DOTEST((pMedThreads = (RThread *)User::AllocZ(sizeof(RThread) * TestMultipleThreadCount)), + (pMedThreads != NULL)) + DOTEST((pMedInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount)), + (pMedInUse != NULL)); + RUNTEST1(pMedThreads && pMedInUse); + if (!(pMedThreads && pMedInUse)) + return KErrGeneral; + + for (index = 0; index < TestMultipleThreadCount; index++) + { + DBGS_PRINT((_L("%S : Starting Media Thread %d\n"), &TestNameBuffer, index)); + DOTEST1(ret,pMedThreads[index].Create(KTestBlank,PerformRomAndFileSystemAccess,KDefaultStackSize,NULL,(TAny*) index),KErrNone, KErrNoMemory); + if (ret == KErrNone) + { + pMedThreads[index].Resume(); + pMedInUse[index] = 1; + } + User::AfterHighRes(0); + } + } + else + { + TestStopMedia = EFalse; + DOTEST1(ret,mediaThread.Create(KTestBlank,PerformRomAndFileSystemAccess,KDefaultStackSize,NULL,(TAny *) 0),KErrNone, KErrNoMemory); + if (ret == KErrNone) + { + mediaThread.Logon(mediaStatus); + RUNTEST1(mediaStatus == KRequestPending); + mediaThread.Resume(); + } + } + } + + TInt maxDlls = GetNumDlls(); + if (TestLoadDllHow == TEST_DLL_GLOBAL) + { + TInt retVal = LoadTheLibs(theGlobalLibs, maxDlls, 0, NULL, NULL, NULL); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("DoMultipleTest - unable to load libs\n"))); + CloseTheLibs (theGlobalLibs, maxDlls); + if (!TestSilent) + { + TestMsgQueue.Close(); + } + TestMultiSem.Close(); + return KErrGeneral; + } + } + + // 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); + + + for (index = 0; index < TestMultipleThreadCount; index++) + { + if (TestLoading & TEST_EXE_SELF) + { + if (KErrNone == StartExe(pTheProcesses[index], 0, index + ((TestLoading & TEST_DLL) ? TestMultipleThreadCount : 0), ((TestLoading & TEST_EXE_SELF) == TEST_EXE_SELF) ? (index & 2) : (TestLoading & TEST_SELF), aLowMem, pTheSem)) + { + User::AfterHighRes(0); + pProcessInUse[index] = 1; + } + } + + + if (TestLoading & TEST_DLL) + { + DBGS_PRINT((_L("%S : Starting Thread %d\n"), &TestNameBuffer, index)); + DOTEST1(ret,pTheThreads[index].Create(KTestBlank,MultipleTestThread,KDefaultStackSize,NULL,(TAny*) index),KErrNone, KErrNoMemory); + if (ret == KErrNone) + { + pTheThreads[index].Resume(); + User::AfterHighRes(0); + pThreadInUse[index] = 1; + } + } + } + + // wait for any child threads to exit and process any debug messages they pass back to the parent. + TBool anyUsed = ETrue; + TMessageBuf localBuffer; + + TInt processOk = 0; + TInt threadOk = 0; + TInt processPanic = 0; + TInt threadPanic = 0; + TUint end = start; + TUint now; + TUint time; + TUint killNext = 0; + TUint numDots = 0; + TUint maxDots = (10*60)/TEST_DOT_PERIOD; // No individual test should take longer than 10 minutes! + // Most have been tuned to take between 2 and 8 minutes. + // The autotests should not take more than 120 minutes total. + + while(anyUsed) + { + TInt threadCount = 0; + TInt processCount = 0; + anyUsed = EFalse; + + // check the message queue and call printf if we get a message. + if (!TestSilent) + { + 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 (TestLoading & TEST_DLL) + { + if (pThreadInUse[index]) + { + if (pTheThreads[index].ExitType() != EExitPending) + { + if (pTheThreads[index].ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Thread %d Panic'd after %u ticks \n"), + &TestNameBuffer, index, User::TickCount() - start)); + threadPanic ++; + } + else + { + DBGS_PRINT((_L("%S : Thread %d Exited after %u ticks \n"), + &TestNameBuffer, index, User::TickCount() - start)); + threadOk ++; + } + pTheThreads[index].Close(); + pThreadInUse[index] = EFalse; + } + else + { + threadCount += 1; + anyUsed = ETrue; + if (TestThreadsExit) + { + now = User::TickCount(); + time = TUint((TUint64)(now-end)*(TUint64)TickPeriod/(TUint64)1000000); + if (time > TEST_DOT_PERIOD) + { + DBGS_PRINT((_L("%S : Thread %d still running\n"), &TestNameBuffer, index)); + } + time = TUint((TUint64)(now-killNext)*(TUint64)TickPeriod/(TUint64)1000000); + const TUint killTimeStep = (TEST_DOT_PERIOD+9)/10; // 1/10th of a dot + if(time>TEST_DOT_PERIOD+killTimeStep) + { + killNext += killTimeStep*1000000/TickPeriod; + DBGS_PRINT((_L("%S : killing Thread %d\n"), &TestNameBuffer, index)); + pTheThreads[index].Kill(KErrNone); + pTheThreads[index].Close(); + pThreadInUse[index] = EFalse; + } + } + } + } + } + if (TestLoading & TEST_EXE_SELF) + { + if (pProcessInUse[index]) + { + if (pTheProcesses[index].ExitType() != EExitPending) + { + if (pTheProcesses[index].ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Process %d Panic'd after %u ticks \n"), + &TestNameBuffer, + index + ((TestLoading & TEST_DLL) ? TestMultipleThreadCount : 0), + User::TickCount() - start)); + processPanic ++; + } + else + { + DBGS_PRINT((_L("%S : Process %d Exited after %u ticks \n"), + &TestNameBuffer, + index + ((TestLoading & TEST_DLL) ? TestMultipleThreadCount : 0), + User::TickCount() - start)); + processOk ++; + } + + pTheProcesses[index].Close(); + pProcessInUse[index] = EFalse; + } + else + { + processCount += 1; + anyUsed = ETrue; + if (TestThreadsExit) + { + now = User::TickCount(); + time = TUint((TUint64)(now-end)*(TUint64)TickPeriod/(TUint64)1000000); + if (time > TEST_DOT_PERIOD) + { + DBGS_PRINT((_L("%S : Process %d still running; killing it.\n"), + &TestNameBuffer, index)); + pTheProcesses[index].Kill(EExitKill); + pTheProcesses[index].Close(); + pProcessInUse[index] = EFalse; + } + + } + } + } + } + } + + now = User::TickCount(); + time = TUint((TUint64)(now-end)*(TUint64)TickPeriod/(TUint64)1000000); + + DBGD_PRINT((_L("%S : %d seconds (%d ticks) %d threads, %d processes still alive\n"), + &TestNameBuffer, time, now, threadCount, processCount)); + + if (time > TEST_DOT_PERIOD) + { + DBGS_PRINT((_L("."))); + numDots ++; + end += TEST_DOT_PERIOD*1000000/TickPeriod; + if (TestingReaper) + { + TestingReaperCleaningFiles = ETrue; + CleanupFiles(EFalse); + CheckFilePresence(ETrue); + TestingReaperCleaningFiles = EFalse; + } + if ((numDots >= maxDots) && (!TestThreadsExit)) + { + DBGS_PRINT((_L("Taking longer than %d dots...exiting test case."), maxDots)); + TestThreadsExit = ETrue; + killNext = end; + } + } + + if (TestingChunks) + { + DoSomeChunking(); + } + +#ifdef TEST_THRASHING_TEST + User::AfterHighRes(1000); +#else + User::AfterHighRes(TickPeriod); +#endif + } + + DBGD_PRINT((_L("%S : all test threads presumably gone now\n"), &TestNameBuffer)); + + if (TestMediaAccess != KTestMediaAccessNone) + { + if (TestMediaAccess != KTestMediaAccessBasic) + { + TBool killMedia = EFalse; + TestStopMedia = ETrue; + anyUsed = ETrue; + DBGS_PRINT((_L("%S : Waiting for media threads to exit...\n"), &TestNameBuffer)); + end = User::TickCount(); + while (anyUsed) + { + anyUsed = EFalse; + + // check the message queue and call printf if we get a message. + if (!TestSilent) + { + while (KErrNone == TestMsgQueue.Receive(localBuffer)) + { + DBGS_PRINT((localBuffer)); + } + } + + for (index = 0; index < TestMultipleThreadCount; index++) + { + if (pMedInUse[index]) + { + if (pMedThreads[index].ExitType() != EExitPending) + { + if (pMedThreads[index].ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Media Thread %d Panic'd after %u ticks \n"), + &TestNameBuffer, index, User::TickCount() - start)); + threadPanic ++; + } + else + { + DBGS_PRINT((_L("%S : Media Thread %d Exited after %u ticks \n"), + &TestNameBuffer, index, User::TickCount() - start)); + threadOk ++; + } + pMedInUse[index] = EFalse; + } + else + { + anyUsed = ETrue; + if (killMedia) + { + DBGS_PRINT((_L("%S : Media Thread %d still going after %u ticks; killing it!\n"), + &TestNameBuffer, index, User::TickCount() - start)); + pMedThreads[index].Kill(EExitKill); + } + } + } + } + now = User::TickCount(); + time = TUint((TUint64)(now-end)*(TUint64)TickPeriod/(TUint64)1000000); + if (time > TEST_DOT_PERIOD) + { + DBGS_PRINT((_L("."))); + end += TEST_DOT_PERIOD*1000000/TickPeriod; + killMedia = ETrue; + } + + User::AfterHighRes(50000); + + } + DBGS_PRINT((_L("%S : Media threads exited...\n"), &TestNameBuffer)); + User::Free(pMedThreads); + User::Free(pMedInUse); + } + else + { + TestStopMedia = ETrue; + DBGS_PRINT((_L("%S : Waiting for media thread to exit...\n"), &TestNameBuffer)); + end = User::TickCount(); + while (mediaThread.ExitType() == EExitPending) + { + now = User::TickCount(); + time = TUint((TUint64)(now-end)*(TUint64)TickPeriod/(TUint64)1000000); + if (time > TEST_DOT_PERIOD) + { + DBGS_PRINT((_L("%S : Media thread still going after %u seconds; killing it!\n"), + &TestNameBuffer, time)); + mediaThread.Kill(EExitKill); + } + User::AfterHighRes(50000); + } + User::WaitForRequest(mediaStatus); + mediaThread.Close(); + DBGS_PRINT((_L("%S : Media thread exited...\n"), &TestNameBuffer)); + } + } + + DBGD_PRINT((_L("%S : all media threads presumably gone now\n"), &TestNameBuffer)); + + if (!TestSilent) + { + TestMsgQueue.Close(); + } + TestMultiSem.Close(); + + DBGD_PRINT((_L("%S : about to close the libraries\n"), &TestNameBuffer)); + + if (TestLoadDllHow == TEST_DLL_GLOBAL) + { + CloseTheLibs(theGlobalLibs, maxDlls); + } + + TestThreadsExit = EFalse; + + DBGD_PRINT((_L("%S : cleaning up\n"), &TestNameBuffer)); + + // cleanup the resources and exit. + if (TestLoading & TEST_EXE_SELF) + { + User::Free(pTheProcesses); + User::Free(pProcessInUse); + } + + // cleanup the resources and exit. + if (TestLoading & TEST_DLL) + { + User::Free(pTheThreads); + User::Free(pThreadInUse); + } + + if (!TestSilent) + { + end = User::TickCount(); + time = TUint((TUint64)(end-start)*(TUint64)TickPeriod/(TUint64)1000000); + DBGS_PRINT((_L("\n%S : Multiple Test : (%u seconds)\n\tThreads panic'd = %d Ok = %d\n\tProcess panic'd = %d Ok = %d\n"), &TestNameBuffer, time, threadPanic, threadOk, processPanic, processOk)); + } + + thisThread.SetPriority(savedThreadPriority); + + return (threadPanic | processPanic) ? KErrGeneral : KErrNone; + } + +// +// DoChunkTests +// +// Allocate a chunk and assign some pages to it... +// Then do a multiple test. +// + +void DoChunkTests() + { + SVMCacheInfo tempPages; + memset(&tempPages, 0, sizeof(tempPages)); + if (TestIsDemandPaged) + { + // Shrink the page cache down to the minimum. + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + + DBGS_PRINT((_L("Start : min %d max %d current %d maxFree %d freeRam %d\n"), + tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam())); + + // set the cache small + TInt minSize = 16 * TestPageSize; + TInt maxSize = TEST_NUM_PAGES * TestPageSize; + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + } + + if (KErrNone != TestChunk.CreateDisconnectedLocal(0,0,TEST_NUM_CHUNK_PAGES *TestPageSize)) + { + DBGS_PRINT((_L("DoChunkTests - create failed.\n"))); + return; + } + TestChunkBase = TestChunk.Base(); + if (TestChunkBase == NULL) + { + RDebug::Printf("DoChunkTests - TestChunkBase was NULL"); + TestChunk.Close(); + return; + } + TInt retVal = KErrNone; + TUint index = 0; + TestCommitEnd = 0; + memset(TestChunkPageState, 0, sizeof(TestChunkPageState)); + memset(TestChunkStats,0,sizeof(TestChunkStats)); + while(index < TEST_NUM_CHUNK_PAGES) + { + retVal = TestChunk.Commit(TestCommitEnd,TestPageSize); + if (KErrNone != retVal) + { + DBGS_PRINT((_L("%S : TestChunk.Commit returned %d for 0x%08x...\n"), &TestNameBuffer, retVal, TestCommitEnd)); + break; + } + TestChunkPageState[index] = ETrue; + FillPage(TestCommitEnd); + TestCommitEnd += TestPageSize; + index ++; + } + RUNTEST1(retVal == KErrNone); + + // now do some testing.... + TestingChunks = ETrue; + TestInterleave = EFalse; + TestPrioChange = ETrue; + TestMediaAccess = KTestMediaAccessNone; + // temp + TestWhichMedia = TEST_MEDIA_ROM_BASE; + + if (TestChunksPlus) + { + TestMaxLoops = 1; + TestMultipleThreadCount = 40; + } + else if (TestExtremeChunks) + { + TestMaxLoops = 10; + TestMultipleThreadCount = 12; + } + else + { + TestMaxLoops = 3; + TestMultipleThreadCount = 20; + } + TestWhichTests = TEST_RANDOM; + + TestLoading = TEST_EXE_SELF_DLL; + TestLoadDllHow = TEST_DLL_FUNC; + TestChunkingIndexFails = 0; + + TEST_NEXT((_L("Multiple threads random with chunks."))); + RUNTEST(DoMultipleTest(), KErrNone); + + TestingChunks = EFalse; + + // clean up. + UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); + TestChunk.Close(); + + if (TestIsDemandPaged) + { + // put the cache back to the the original values. + TInt minSize = tempPages.iMinSize; + TInt maxSize = tempPages.iMaxSize; + + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + + DBGS_PRINT((_L("Finish : min %d max %d current %d maxFree %d freeRam %d\n"), + tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam())); + } + TChunkTestStats stats; + + memset(&stats, 0, sizeof(stats)); + DBGS_PRINT((_L("Stats : (pass/fail) \nindex\t\tlock\t\tunlock\t\tcommit\t\tdecommit\t\tcheck\n"))); + for (index = 0; index < TEST_NUM_CHUNK_PAGES; index ++) + { + DBGS_PRINT((_L("%u\t\t%d/%d\t\t%d/%d\t\t%d/%d\t\t%d/%d\t\t%d/%d\n"), + index, + TestChunkStats[index].lock.ok, TestChunkStats[index].lock.fail, + TestChunkStats[index].unlock.ok, TestChunkStats[index].unlock.fail, + TestChunkStats[index].commit.ok, TestChunkStats[index].commit.fail, + TestChunkStats[index].decommit.ok, TestChunkStats[index].decommit.fail, + TestChunkStats[index].check.ok, TestChunkStats[index].check.fail)); + + stats.lock.ok += TestChunkStats[index].lock.ok; + stats.lock.fail += TestChunkStats[index].lock.fail; + stats.unlock.ok += TestChunkStats[index].unlock.ok; + stats.unlock.fail += TestChunkStats[index].unlock.fail; + stats.decommit.ok += TestChunkStats[index].decommit.ok; + stats.decommit.fail += TestChunkStats[index].decommit.fail; + stats.commit.ok += TestChunkStats[index].commit.ok; + stats.commit.fail += TestChunkStats[index].commit.fail; + stats.check.ok += TestChunkStats[index].check.ok; + stats.check.fail += TestChunkStats[index].check.fail; + } + + DBGS_PRINT((_L("Total Stats (p/f): \n\t lock %d / %d\n\t unlock %d / %d\n\t commit %d / %d\n\t decommit %d / %d\n\t check %d / %d\n"), + stats.lock.ok, stats.lock.fail, + stats.unlock.ok, stats.unlock.fail, + stats.commit.ok, stats.commit.fail, + stats.decommit.ok, stats.decommit.fail, + stats.check.ok, stats.check.fail)); + DBGS_PRINT((_L("TestChunkingIndexFails %d\n"), TestChunkingIndexFails)); + + } + +// +// DoReaperTests +// +// Test the reaper by deleting the transient files and re-creating them. +// + +void DoReaperTests(void) + { + // make sure we have the full complement of files. + CheckFilePresence(ETrue); + + // now do some testing.... + TestInterleave = EFalse; + TestPrioChange = EFalse; + TestMediaAccess = KTestMediaAccessNone; + // temp + TestWhichMedia = TEST_MEDIA_ALL; + TestMaxLoops = 3; + TestMultipleThreadCount = 12; + TestWhichTests = TEST_RANDOM; + + TestLoading = TEST_EXE_SELF_DLL; + TestLoadDllHow = TEST_DLL_FUNC; + + TestingReaper = ETrue; + + TEST_NEXT((_L("Reaper tests."))); + RUNTEST(DoMultipleTest(), KErrNone); + TestInterleave = ETrue; + TestPrioChange = ETrue; + TEST_NEXT((_L("Reaper tests 2."))); + RUNTEST(DoMultipleTest(), KErrNone); + + TestingReaper = EFalse; + } + +// +// DoBtraceTest +// +// Test the paging BTrace function. +// + +void DoBtraceTest(void) + { +#define LE4(a) ((*((a) + 3) << 24) + (*((a) + 2) << 16) + (*((a) + 1) << 8) + *(a)) + + RBTrace bTraceHandle; + + TInt r = bTraceHandle.Open(); + test(r == KErrNone); + + r = bTraceHandle.ResizeBuffer(0x200000); + test(r == KErrNone); + bTraceHandle.SetFilter(BTrace::EPaging, ETrue); + + // Enable trace + bTraceHandle.Empty(); + bTraceHandle.SetMode(RBTrace::EEnable); + + TestLoading = TEST_EXE_SELF_DLL; + TestWhichMedia = TEST_MEDIA_ROM_BASE; + TestMaxLoops = 2; + TestMultipleThreadCount = 10; + TestLoadDllHow = TEST_DLL_FUNC; + TestInterleave = ETrue; + TestPrioChange = ETrue; + TestMediaAccess = KTestMediaAccessNone; + TestWhichTests = TEST_RANDOM; + TestingLowMem = EFalse; + + RUNTEST(DoMultipleTest(TestingLowMem), KErrNone); + + bTraceHandle.SetMode(0); + + // analyse the btrace logs and display on the serial port. + TUint8* pDataStart; + TInt dataSize; + TUint8* pTemp; + TUint8* pThis; + TUint8* pEnd; + TBuf<128> data; + while (1) + { + dataSize = bTraceHandle.GetData(pDataStart); + if (dataSize <= 0) + { + break; + } + pEnd = pDataStart + dataSize; + pTemp = pDataStart; + while (pTemp < pEnd) + { + TUint8 recSize = pTemp[BTrace::ESizeIndex]; + TUint8 recFlags = pTemp[BTrace::EFlagsIndex]; + TUint8 recCat = pTemp[BTrace::ECategoryIndex]; + TUint8 recSub = pTemp[BTrace::ESubCategoryIndex]; + TUint32 addr[4]; + pThis = pTemp; + + data.Zero(); + // step over the header. + data.Format(_L("size %d cat %d sub %d flg 0x%02x "), recSize, recCat, recSub, recFlags); + pTemp += 4; + + if (recFlags & BTrace::EHeader2Present) + { + data.AppendFormat(_L("h2 0x%08x "), LE4(pTemp)); + pTemp += 4; + } + if (recFlags & BTrace::ETimestampPresent) + { + data.AppendFormat(_L("ts 0x%08x "), LE4(pTemp)); + pTemp += 4; + } + if (recFlags & BTrace::ETimestamp2Present) + { + data.AppendFormat(_L("ts2 0x%08x "), LE4(pTemp)); + pTemp += 4; + } + if (recFlags & BTrace::EContextIdPresent) + { + data.AppendFormat(_L("cId 0x%08x "), LE4(pTemp)); + pTemp += 4; + } + TInt index; + for (index = 0; index < 4; index ++) + { + if (recSize > pTemp - pThis) + { + addr[index] = LE4(pTemp); + pTemp += 4; + } + else + addr[index] = 0; + } + + switch(recCat) + { + case BTrace::EPaging: + { + switch (recSub) + { + case BTrace::EPagingPageInBegin: + /** + - 4 bytes containing the virtual address which was accessed, causing this paging event. + - 4 bytes containing the virtual address of the instuction which caused this paging event. + (The PC value.) + **/ + test.Printf(_L("PageInBegin : %S addr 0x%08x inst 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 0 bytes. (No extra data.) + */ + case BTrace::EPagingPageInUnneeded: + test.Printf(_L("PageInUnneeded : %S\n"), &data); + break; + + /** + - 4 bytes containing the physical address of the page 'paged in'. + - 4 bytes containing the virtual address of the page 'paged in'. + */ + case BTrace::EPagingPageInROM: + test.Printf(_L("PageInROM : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being 'paged out'. + - 4 bytes containing the virtual address of the page being 'paged out'. + */ + case BTrace::EPagingPageOutROM: + test.Printf(_L("PageOutROM : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being 'paged in'. + */ + case BTrace::EPagingPageInFree: + test.Printf(_L("PageInFree : %S phys 0x%08x\n"), &data, addr[0]); + break; + + /** + - 4 bytes containing the physical address of the page being 'paged out'. + */ + case BTrace::EPagingPageOutFree: + test.Printf(_L("PageOutFree : %S phys 0x%08x\n"), &data, addr[0]); + break; + + /** + - 4 bytes containing the physical address of the page being rejuvenated, (made young). + - 4 bytes containing the virtual address which was accessed, causing this paging event. + - 4 bytes containing the virtual address of the instuction which caused this paging event. + (The PC value.) + */ + case BTrace::EPagingRejuvenate: + test.Printf(_L("Rejuvenate : %S phys 0x%08x virt 0x%08x inst 0x%08x\n"), &data, addr[0], addr[1], addr[2]); + break; + + /** + - 4 bytes containing the physical address of the page accessed. + - 4 bytes containing the virtual address which was accessed, causing this paging event. + - 4 bytes containing the virtual address of the instuction which caused this paging event. + (The PC value.) + */ + case BTrace::EPagingPageNop: + test.Printf(_L("PageNop : %S phys 0x%08x virt 0x%08x inst 0x%08x\n"), &data, addr[0], addr[1], addr[2]); + break; + + /** + - 4 bytes containing the physical address of the page being locked. + - 4 bytes containing the value of the lock count after the paged was locked. + */ + case BTrace::EPagingPageLock: + test.Printf(_L("PageLock : %S phys 0x%08x lock 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being unlocked. + - 4 bytes containing the value of the lock count before the paged was unlocked. + */ + case BTrace::EPagingPageUnlock: + test.Printf(_L("PageUnlock : %S phys 0x%08x lock 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being 'paged out'. + - 4 bytes containing the virtual address of the page being 'paged out'. + */ + case BTrace::EPagingPageOutCache: + test.Printf(_L("PageOutCache : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page 'paged in'. + - 4 bytes containing the virtual address of the page 'paged in'. + */ + case BTrace::EPagingPageInCode: + test.Printf(_L("PageInCode : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being 'paged out'. + - 4 bytes containing the virtual address of the page being 'paged out'. + */ + case BTrace::EPagingPageOutCode: + test.Printf(_L("PageOutCode : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page 'paged in'. + - 4 bytes containing the virtual address of the page 'paged in'. + */ + case BTrace::EPagingMapCode: + test.Printf(_L("MapCode : %S phys 0x%08x virt 0x%08x\n"), &data, addr[0], addr[1]); + break; + + /** + - 4 bytes containing the physical address of the page being aged, (made old). + */ + case BTrace::EPagingAged: + test.Printf(_L("Aged : %S phys 0x%08x\n"), &data, addr[0]); + break; + } + } + break; + + default: + + break; + } + pTemp = BTrace::NextRecord(pThis); + } + bTraceHandle.DataUsed(); + } + bTraceHandle.Close(); + } + +// +// 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: [ single | multiple ] [ dll | exe | self | complete ] [func | thread | global ] [ rom | base | mixed | mall ] [reaper] [chunks|echunks|chunks+ {nochunkdata}] [prio] [media] [lowmem] [forward | backward | random | all] [loadGlobal | loadThread | loadFunc] [interleave] [d_exc] [btrace] [defrag] [noclean] [min ] [max ] [stressfree] [iters ]\n'-' indicated infinity.\n\n"))); + test.Getch(); + } + else if (token == _L("mmc")) + { + TestOnlyFromMmc = ETrue; + } + else if (token == _L("min")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt value; + lexv.Val(value); + TestMinCacheSize = value * 4096; + } + else if (token == _L("max")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt value; + lexv.Val(value); + TestMaxCacheSize = value * 4096; + } + else if (token == _L("interleave")) + { + TestInterleave = ETrue; + } + else if (token == _L("auto")) + { + TestFullAutoTest = EFalse; + retVal = EFalse; + } + else if (token == _L("stressfree")) + { + TestStressFree = !TestStressFree; + retVal = EFalse; + } + else if (token == _L("fullauto")) + { + TestFullAutoTest = ETrue; + retVal = EFalse; + } + else if (token == _L("prio")) + { + TestPrioChange = !TestPrioChange; + } + else if (token == _L("media")) + { + TestMediaAccess = KTestMediaAccessBasic; + } + else if (token == _L("reaper")) + { + TestReaper = ETrue; + } + else if (token == _L("btrace")) + { + TestBtrace = ETrue; + } + else if (token == _L("defrag")) + { + TestDefrag = ETrue; + } + else if (token == _L("echunks")) + { + TestChunks = ETrue; + TestExtremeChunks = ETrue; + } + else if (token == _L("chunks+")) + { + TestChunks = ETrue; + TestChunksPlus = ETrue; + } + else if (token == _L("chunks")) + { + TestChunks = ETrue; + } + else if (token == _L("nochunkdata")) + { + TestChunkData = EFalse; + } + else if (token == _L("lowmem")) + { + TestLowMem = ETrue; + } + else if (token == _L("dll")) + { + TestLoading = TEST_DLL; + } + else if (token == _L("exe")) + { + TestLoading = TEST_EXE; + } + else if (token == _L("self")) + { + TestLoading = TEST_SELF; + } + else if (token == _L("complete")) + { + TestLoading |= TEST_EXE_SELF_DLL; + } + else if (token == _L("rom")) + { + TestWhichMedia = TEST_MEDIA_ROM; + } + else if (token == _L("base")) + { + TestWhichMedia = TEST_MEDIA_BASE; + } + else if (token == _L("mixed")) + { + TestWhichMedia |= TEST_MEDIA_ROM_BASE; + } + else if (token == _L("all_media")) + { + TestWhichMedia |= TEST_MEDIA_ALL; + } + else if (token == _L("debug")) + { + if (!TestSilent) + { + TestDebug = ETrue; + TestPrioChange = ETrue; + } + } + else if (token == _L("silent")) + { + TestSilent = ETrue; + TestDebug = EFalse; + } + else if (token == _L("noclean")) + { + TestNoClean = ETrue; + } + else if (token == _L("d_exc")) + { + TestD_Exc = ETrue; + } + else if (token == _L("global")) + { + TestLoadDllHow = TEST_DLL_GLOBAL; + } + else if (token == _L("thread")) + { + TestLoadDllHow = TEST_DLL_THREAD; + } + else if (token == _L("func")) + { + TestLoadDllHow = TEST_DLL_FUNC; + } + 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("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("inst")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt value; + + if (lexv.Val(value)==KErrNone) + { + TestInstanceId = value; + } + } + else if (token == _L("iters")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt value; + + if (val==_L("-")) + { + 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 ((foundArgs == EFalse) && (token.Length() == 1)) + { + // Single letter argument...only run on 'd' + if (token.CompareF(_L("d")) == 0) + { + + TestFullAutoTest = EFalse; + TestIsAutomated = ETrue; + 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() + { + 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(TestPlExeNames[KTestMediaBase]); + + 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_pageldrtst.exe")); + } + } +#define MEDNONE KTestMediaAccessNone +#define MEDBASIC KTestMediaAccessBasic +#define MEDMTHRE KTestMediaAccessMultipleThreads +#define MEDMPATT KTestMediaAccessMultiplePattern +#define MEDMIX KTestMediaAccessMixed + +TTheTests TheAutoTests[] = + {// fullOnly, loading, media, multi, loops, threads, loadHow, inter, prio, media, whichTests, lowmem, free, testName +#ifdef TEST_SHORT_TEST + { EFalse, TEST_DLL, TEST_MEDIA_ALL, ETrue, 2, 24, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL Load (ALL Media) Multiple thread all."), }, +#else + { EFalse, TEST_DLL, TEST_MEDIA_BASE, ETrue, 5, 24, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_THRASH, EFalse, 0, }, //_L("DLL Load (ROM) Multiple thread Thrash."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 5, 20, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_ALL, EFalse, 0, }, //_L("DLL Load (ROM/ROFS) Single thread all."), }, + { ETrue, TEST_EXE, TEST_MEDIA_ROM_BASE, EFalse, 5, 20, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_ALL, EFalse, 0, }, //_L("Exe Load (ROM/ROFS) Single thread."), }, + { ETrue, TEST_SELF, TEST_MEDIA_ROM_BASE, EFalse, 5, 20, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_ALL, EFalse, 0, }, //_L("Self Load (ROM/ROFS) Single thread."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, ETrue, 5, 20, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL Load (ROM/ROFS) Multiple thread all."), }, + { EFalse, TEST_DLL, TEST_MEDIA_ALL, ETrue, 3, 20, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL Load (ALL Media) Multiple thread all."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, EFalse, ETrue, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with prio."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 10, TEST_DLL_FUNC, EFalse, EFalse, MEDBASIC, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with media access."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_FUNC, EFalse, ETrue, MEDBASIC, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with media access and prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_THREAD, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load thread (All Media) Multiple threads."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_THREAD, EFalse, ETrue, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load thread (All Media) Multiple threads with prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_THREAD, EFalse, ETrue, MEDBASIC, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load thread (All Media) Multiple threads with media access and prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_GLOBAL, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load global (All Media) Multiple threads."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_GLOBAL, EFalse, ETrue, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load global (All Media) Multiple threads with prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_GLOBAL, EFalse, ETrue, MEDBASIC, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load global (All Media) Multiple threads with media access and prio."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave, prio."), }, + + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDBASIC, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave, media and prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_FUNC, ETrue, ETrue, MEDMTHRE, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave, multi media and prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_FUNC, ETrue, ETrue, MEDMPATT, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave, media and prio."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_FUNC, ETrue, ETrue, MEDMIX, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load (All Media) Multiple threads with interleave, media and prio."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 10, TEST_DLL_FUNC, ETrue, ETrue, MEDMIX, TEST_RANDOM, EFalse, 0, }, //_L("DLL/EXE/SELF Load Multiple threads with interleave, media and prio."), }, +#endif // TEST_SHORT_TEST + }; +#define NUM_AUTO_TESTS (TInt)(sizeof(TheAutoTests) / sizeof(TTheTests)) + +// +// PerformAutoTest +// +// The autotest. +// + +void PerformAutoTest(TBool aReduceTime = EFalse) + { + TInt testIndex; + TTheTests *pTest = &TheAutoTests[0]; + + DoStats(); + + for (testIndex = 0; testIndex < NUM_AUTO_TESTS; testIndex ++, pTest++) + { + if ( ( !TestWeAreTheTestBase + && ( (pTest->testLoadDllHow != TEST_DLL_FUNC) + || !pTest->testMultiple)) + || ((TestFullAutoTest == EFalse) && (pTest->testFullAutoOnly))) + { + continue; + } + + TestLoading = pTest->testLoading; + TestWhichMedia = pTest->testWhichMedia; + TestMaxLoops = aReduceTime ? 1 : pTest->testMaxLoops; + TestMultipleThreadCount = aReduceTime ? 10 : pTest->testMultipleThreadCount; + TestLoadDllHow = pTest->testLoadDllHow; + TestInterleave = pTest->testInterleave; + TestPrioChange = pTest->testPrioChange; + TestMediaAccess = pTest->testMediaAccess; + if (aReduceTime && (TestMediaAccess != MEDBASIC) && (TestMediaAccess != MEDNONE)) + { + continue; + } + TestWhichTests = pTest->testWhichTests; + TestingLowMem = pTest->testLowMem; + if (!TestSilent) + { + test.Next(_L("Auto Test")); + } + if (pTest->testMultiple) + { + RUNTEST(DoMultipleTest(ETrue), KErrNone); + } + else + { + RUNTEST(DoSingleTest(ETrue), KErrNone); + } + + DoStats(); + +#ifdef TEST_KERN_HEAP + __KHEAP_MARK; + __KHEAP_CHECK(0); + __KHEAP_MARKEND; +#endif + } +#ifdef TEST_KERN_HEAP + __KHEAP_MARK; + __KHEAP_CHECK(0); + __KHEAP_MARKEND; +#endif + } + +TTheTests TheLowMemTests[] = + {// fullOnly, loading, media, multi, loops, threads, loadHow, inter, prio, media, whichTests, lowmem, free, testName +#ifndef TEST_SHORT_TEST + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Single thread with Low memory (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, EFalse, 5, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, ETrue, 0, }, //_L("Single thread with Low memory."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 16, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory ."), }, + { EFalse, TEST_DLL, TEST_MEDIA_ALL, EFalse, 5, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory and All media(init)."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 12, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory and All media."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory, with starting free ram (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 16, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, ETrue, 32, }, //_L("Multiple thread with Low memory, with starting free ram."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 16, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory and prio and media access(init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 16, TEST_DLL_FUNC, EFalse, ETrue, MEDBASIC, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory and prio and media access."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, prio and media access(init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDBASIC, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, prio and media access."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, media access and All media (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, EFalse, MEDBASIC, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, media access and All media + loading."), }, + { EFalse, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 10, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Single thread with Low memory (init)."), }, + { EFalse, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 5, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, ETrue, 0, }, //_L("Single thread with Low memory."), }, +#endif //TEST_SHORT_TEST + { EFalse, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 10, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media (init)."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDBASIC, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media + loading."), }, + { EFalse, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 5, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media (init)."), }, + { EFalse, TEST_EXE_SELF_DLL, TEST_MEDIA_ROM_BASE, ETrue, 2, 10, TEST_DLL_FUNC, ETrue, ETrue, MEDMTHRE, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, prio, multi media access and All media + loading."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDBASIC, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media + loading."), }, + { ETrue, TEST_DLL, TEST_MEDIA_ROM_BASE, EFalse, 1, 1, TEST_DLL_FUNC, EFalse, EFalse, MEDNONE, TEST_RANDOM, EFalse, 0, }, //_L("Multiple thread with Low memory interleave, prio, media access and All media (init)."), }, + { ETrue, TEST_EXE_SELF_DLL, TEST_MEDIA_ALL, ETrue, 2, 16, TEST_DLL_FUNC, ETrue, ETrue, MEDMTHRE, TEST_RANDOM, ETrue, 0, }, //_L("Multiple thread with Low memory interleave, prio, multi media access and All media + loading."), }, + + }; +#define NUM_LOWMEM_TESTS (TInt)(sizeof(TheLowMemTests) / sizeof(TTheTests)) + +// +// DoLowMemTest +// +// Low Memory Test +// +void DoLowMemTest(TBool aEnableAllMedia = EFalse) + { + TInt r = User::LoadLogicalDevice(KPageStressTestLddName); + RUNTEST1(r==KErrNone || r==KErrAlreadyExists); + RUNTEST(PagestressLdd.Open(),KErrNone); + RUNTEST(PagestressLdd.DoSetDebugFlag((TInt)TestDebug),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); + } + + TInt testIndex; + TTheTests *pTest = &TheLowMemTests[0]; + for (testIndex = 0; testIndex < NUM_LOWMEM_TESTS; testIndex ++, pTest++) + { + if ( (!aEnableAllMedia && (pTest->testWhichMedia == TEST_MEDIA_ALL)) + || ((TestFullAutoTest == EFalse) && (pTest->testFullAutoOnly))) + { + continue; + } + + TestLoading = pTest->testLoading; + TestWhichMedia = pTest->testWhichMedia; + TestMaxLoops = pTest->testMaxLoops; + TestMultipleThreadCount = pTest->testMultipleThreadCount; + TestLoadDllHow = pTest->testLoadDllHow; + TestInterleave = pTest->testInterleave; + TestPrioChange = pTest->testPrioChange; + TestMediaAccess = pTest->testMediaAccess; + TestWhichTests = pTest->testWhichTests; + TestingLowMem = pTest->testLowMem; + if (!TestSilent) + { + test.Next(_L("Low Memory")); + } + if (pTest->testLowMem) + { + PagestressLdd.DoConsumeRamSetup(pTest->testFreeRam, TEST_LM_BLOCKSIZE); + } + + if (pTest->testMultiple) + { + RUNTEST(DoMultipleTest(pTest->testLowMem), KErrNone); + } + else + { + RUNTEST(DoSingleTest(pTest->testLowMem), KErrNone); + } + + if (pTest->testLowMem) + { + PagestressLdd.DoConsumeRamFinish(); + } + + DoStats(); +#ifdef TEST_KERN_HEAP + __KHEAP_MARK; + __KHEAP_CHECK(0); + __KHEAP_MARKEND; +#endif + } + + if (!TestSilent) + { + test.Next(_L("Close test driver")); + } + PagestressLdd.Close(); + RUNTEST(User::FreeLogicalDevice(KPageStressTestLddName), KErrNone); + + if (TestIsDemandPaged) + { + TInt minSize = tempPages.iMinSize; + TInt maxSize = tempPages.iMaxSize; + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + } + +#ifdef TEST_KERN_HEAP + __KHEAP_MARK; + __KHEAP_CHECK(0); + __KHEAP_MARKEND; +#endif + TestingLowMem = EFalse; + + } + +// +// MultipleDefragThread +// +// Thread function, one created for each zone in a multiple thread test. +// + +LOCAL_C TInt MultipleDefragThread(TAny* aUseTb) + { + TInt numZones = 1; + TInt zoneId = (TInt)aUseTb; + + if (TestZoneCount > TEST_MAX_ZONE_THREADS) + { + numZones = TestZoneCount / TEST_MAX_ZONE_THREADS; + } + + while (1) + { + TInt index = 0; + TInt tempy = 0; + for (; index < numZones; index ++) + { + User::AfterHighRes(TEST_MAX_ZONE_THREADS*TickPeriod/4); + tempy = zoneId + (TEST_MAX_ZONE_THREADS * index); + if (tempy < (TInt)TestZoneCount) + { + RamstressLdd.DoMovePagesInZone(tempy); + } + if (TestDefragTestEnd) + break; + } + if (TestDefragTestEnd) + break; + } + return KErrNone; + } + +// +// DoDefragAutoTest +// +// Call the auto tests whilst defraging in the background. +// + +void DoDefragAutoTest() + { + TUint localZoneCount = TestZoneCount; + if (TestZoneCount > TEST_MAX_ZONE_THREADS) + { + localZoneCount = TEST_MAX_ZONE_THREADS; + } + TInt size = (sizeof(RThread) * localZoneCount) + + (sizeof(TInt) * localZoneCount); + TUint8* pBuf = (TUint8*)User::AllocZ(size); + + test(pBuf != NULL); + RThread *pTheThreads = (RThread*)pBuf; + TInt *pThreadInUse = (TInt*)(pTheThreads + localZoneCount); + TInt ret; + TUint index; + for (index = 0; index < localZoneCount; index ++) + { + DBGS_PRINT((_L("%S : Starting Defrag Thread %d\n"), &TestNameBuffer, index)); + ret = pTheThreads[index].Create(KTestBlank,MultipleDefragThread,KDefaultStackSize,NULL,(TAny*) index); + if (ret == KErrNone) + { + pTheThreads[index].Resume(); + pThreadInUse[index] = 1; + } + else + { + DBGS_PRINT((_L("%S : Starting Defrag Thread Failed %d\n"), &TestNameBuffer, index)); + } + } + + // Do the full auto tests... + PerformAutoTest(TestIsDemandPaged); + + TestDefragTestEnd = ETrue; + RamstressLdd.DoSetEndFlag(1); + TBool anyUsed = ETrue; + + DBGS_PRINT((_L("%S : Waiting for Defrag Threads to exit...\n"), &TestNameBuffer)); + TUint killNext = User::TickCount(); + while(anyUsed) + { + anyUsed = EFalse; + + // walk through the thread list to check which are still alive. + for (index = 0; index < localZoneCount; index++) + { + if (pThreadInUse[index]) + { + if (pTheThreads[index].ExitType() != EExitPending) + { + if (pTheThreads[index].ExitType() == EExitPanic) + { + DBGS_PRINT((_L("%S : Defrag Thread %d Panic'd\n"), &TestNameBuffer, index)); + } + else + { + DBGS_PRINT((_L("%S : Defrag Thread %d Exited\n"), &TestNameBuffer, index)); + } + pTheThreads[index].Close(); + pThreadInUse[index] = EFalse; + } + else + { + anyUsed = ETrue; + TUint now = User::TickCount(); + TUint time = TUint((TUint64)(now-killNext)*(TUint64)TickPeriod/(TUint64)1000000); + const TUint killTimeStep = (TEST_DOT_PERIOD+9)/10; // 1/10th of a dot + if(time>TEST_DOT_PERIOD+killTimeStep) + { + killNext += killTimeStep*1000000/TickPeriod; + DBGS_PRINT((_L("%S : killing Defrag Thread %d\n"), &TestNameBuffer, index)); + pTheThreads[index].Kill(KErrNone); + pTheThreads[index].Close(); + pThreadInUse[index] = EFalse; + } + } + } + } + User::After(500000); + } + DBGS_PRINT((_L("%S : Defrag Threads exited...\n"), &TestNameBuffer)); + RamstressLdd.DoSetEndFlag(0); + User::Free(pBuf); + } + +// +// DoDefragTest +// +// Test the ram defrag code. +// + +void DoDefragTest(void) + { + SVMCacheInfo tempPages; + memset(&tempPages, 0, sizeof(tempPages)); + + test.Next(_L("Ram Defrag : Get the number of zones")); + // first get the number of zones + TInt ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneCount,&TestZoneCount,0); + if(ret==KErrNotSupported) + { + test.Next(_L("TESTS NOT RUN - Ram Defrag appears to not be supported.\n")); + return; + } + test(ret == KErrNone); + test(TestZoneCount != 0); + test.Printf(_L("RAM Zones (count=%u)\n"),TestZoneCount); + + // now get the config of each of the zones. + TUint index; + struct SRamZoneConfig config; + struct SRamZoneUtilisation util; + test.Next(_L("Ram Defrag : Get info about the zones")); + for (index = 0; index < TestZoneCount; index ++) + { + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneConfig,(TAny*)index, (TAny*)&config); + test(ret == KErrNone); + test.Printf(_L("config : id=%d index=%d base=0x%08x end=0x%08x pages=%d pref=%d flags=0x%x\n"), + config.iZoneId,config.iZoneIndex,config.iPhysBase,config.iPhysEnd,config.iPhysPages, + config.iPref,config.iFlags); + + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneUtilisation,(TAny*)index, (TAny*)&util); + test(ret == KErrNone); + test.Printf(_L("usage : id=%d index=%d pages=%d free=%d unknown=%d fixed=%d move=%d discard=%d other=%d\n"), + util.iZoneId,util.iZoneIndex,util.iPhysPages,util.iFreePages, + util.iAllocUnknown,util.iAllocFixed,util.iAllocMovable,util.iAllocDiscardable,util.iAllocOther); + } + // Now test for zones out of range. + test.Next(_L("Ram Defrag : test out of range indexes")); + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneConfig,(TAny*)(TestZoneCount + 1), (TAny*)&config); + test(ret != KErrNone); + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneUtilisation,(TAny*)(TestZoneCount + 1), (TAny*)&util); + test(ret != KErrNone); + + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneConfig,(TAny*)-1, (TAny*)&config); + test(ret != KErrNone); + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneUtilisation,(TAny*)-1, (TAny*)&util); + test(ret != KErrNone); + test.Next(_L("Ram Defrag : test out of range enums")); + ret = UserSvr::HalFunction(EHalGroupRam,-1, 0, 0); + test(ret != KErrNone); + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneUtilisation + 1,0, 0); + test(ret != KErrNone); + + TInt r = User::LoadLogicalDevice(KRamStressTestLddName); + RUNTEST1(r==KErrNone || r==KErrAlreadyExists); + RUNTEST(RamstressLdd.Open(),KErrNone); + //TestDebug = ETrue; + RUNTEST(RamstressLdd.DoSetDebugFlag((TInt)TestDebug),KErrNone); + + test.Next(_L("Ram Defrag : set VM cache to stress free...")); + + if (TestIsDemandPaged) + { + // get the old cache info + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + + TInt minSize = 512 * 4096; + TInt maxSize = 32767 * 4096; + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + } + + test.Next(_L("Ram Defrag : move all pages in all zone in 1 thread...")); + + for (index = 0; index < TestZoneCount; index ++) + { + test.Printf(_L("Ram Defrag : moving pages in zone %u\n"),index); + ret = RamstressLdd.DoMovePagesInZone(index); + if (ret != KErrNone) + { + test.Printf(_L("Ram Defrag : moving pages in zone failed %u err=%d\n"), index, ret); + } + } + + + test.Next(_L("Ram Defrag : Get info after test")); + for (index = 0; index < TestZoneCount; index ++) + { + ret = UserSvr::HalFunction(EHalGroupRam,ERamHalGetZoneUtilisation,(TAny*)index, (TAny*)&util); + test(ret == KErrNone); + test.Printf(_L("usage : id=%d index=%d pages=%d free=%d unknown=%d fixed=%d move=%d discard=%d other=%d\n"), + util.iZoneId,util.iZoneIndex,util.iPhysPages,util.iFreePages, + util.iAllocUnknown,util.iAllocFixed,util.iAllocMovable,util.iAllocDiscardable,util.iAllocOther); + } + + test.Next(_L("Ram Defrag : Page moving on multiple threads with auto test running.")); + + TestingDefrag = ETrue; + TestDefragTestEnd = EFalse; + + DoDefragAutoTest(); + TestingDefrag = EFalse; + /* + * End of test cleanup. + */ + + test.Next(_L("Ram Defrag : reset VM cache back to stressed.")); + if (TestIsDemandPaged) + { + TInt minSize = tempPages.iMinSize; + TInt maxSize = tempPages.iMaxSize; + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + } + RamstressLdd.Close(); + test.Next(_L("Ram Defrag : Done")); + } + +// +// PerformExceptionThread +// +// Generate a Panic +// + +LOCAL_C TInt PerformExceptionThread(TAny* ) + { + User::AfterHighRes(1000000); + // this line will cause a Kern::Exec 0 !!! + test.Printf(_L("Hello World\n")); + + return KErrNone; + } + +// +// DoExceptionInAnotherThread +// +// Test the d_exc and minkda functionality with faulting processes. +// + +void DoExceptionInAnotherThread(void) + { + TRequestStatus theStatus; + RThread theThread; + + TInt ret = theThread.Create(KTestBlank,PerformExceptionThread,KDefaultStackSize,NULL,NULL); + test(ret == KErrNone); + theThread.Logon(theStatus); + RUNTEST1(theStatus == KRequestPending); + theThread.Resume(); + theThread.Close(); + User::WaitForRequest(theStatus); + } + +// +// DoTestD_Exc +// +// Test the d_exc and minkda functionality with faulting processes. +// + +TInt DoTestD_Exc() + { + if (!TestSilent) + { + test.Next(_L("DoTestD_Exc : d_exc check test.")); + } + DBGS_PRINT((_L("%S : DoTestD_Exc start...\n"), &TestNameBuffer)); + // first we need to spawn d_exc.exe + RProcess dexcProcess; + TInt ret = dexcProcess.Create(_L("d_exc.exe"),_L("-b")); + RUNTEST1(KErrNone == ret); + TRequestStatus dexcStatus; + dexcProcess.Logon(dexcStatus); + RUNTEST1(dexcStatus == KRequestPending); + dexcProcess.Resume(); + + DBGS_PRINT((_L("%S : DoTestD_Exc started d_exc.exe\n"), &TestNameBuffer)); + + DoExceptionInAnotherThread(); + + DBGS_PRINT((_L("%S : DoTestD_Exc test completed\n"), &TestNameBuffer)); + // check that d_exc and minkda don't die! + RUNTEST1(dexcProcess.ExitType() == EExitPending); + + DBGS_PRINT((_L("%S : DoTestD_Exc d_exc still running\n"), &TestNameBuffer)); + + // kill off d_exc! + dexcProcess.Kill(KErrNone); + dexcProcess.Close(); + User::WaitForRequest(dexcStatus); + DBGS_PRINT((_L("%S : DoTestD_Exc d_exc killed and exiting\n"), &TestNameBuffer)); + return KErrNone; + } + +/** + Get name of the hash file used for an EXE or DLL which has been + copied to writable media. + + @param aOrigName Name of EXE or DLL which has been copied to + writable media. This does not have to be + qualified because only the name and extension + are used. + @param aHashName On return this is set to the absolute filename + which should contain the file's hash. This + function does not create the file, or its containing + directory. + */ + +static void GetHashFileName(const TDesC& aOrigName, TDes& aHashName) + { + aHashName.Copy(KSysHash); + aHashName[0] = (TUint8) RFs::GetSystemDriveChar(); + const TParsePtrC ppc(aOrigName); + aHashName.Append(ppc.NameAndExt()); + } + +// +// HashFile +// take hash of files require full drive:/path/name.ext +// + +void HashFile(const TDesC& aFileName, RFs& aFs) + { + CSHA1* sha1 = CSHA1::NewL(); + CleanupStack::PushL(sha1); + + TBuf<50> hashfile; + hashfile = KSysHash; + hashfile[0] = (TUint8) RFs::GetSystemDriveChar(); + + TInt r = aFs.MkDirAll(hashfile); + RUNTEST1(r==KErrNone || r==KErrAlreadyExists); + + RFile fDest; + r = fDest.Open(aFs, aFileName, EFileRead | EFileStream); + if (r != KErrNone) + { + if (TestingReaper && (r == KErrInUse)) + { + TBool whinged = EFalse; + while (r == KErrInUse) + { + User::After(2000000); + if (!whinged) + { + DBGS_PRINT((_L("HashFile() retrying Open for %S (%d)\n"), &aFileName, r)); + whinged = ETrue; + } + r = fDest.Open(aFs, aFileName, EFileRead | EFileStream); + } + + } + else + { + DBGS_PRINT((_L("fDest.Open returned %d\n"), r)); + } + } + User::LeaveIfError(r); + CleanupClosePushL(fDest); + + TBool done; + TBuf8<512> content; + do + { + r = fDest.Read(content); + if (r!=KErrNone) + DBGS_PRINT((_L("fDest.Read returned %d\n"), r)); + User::LeaveIfError(r); + done = (content.Length() == 0); + if (! done) + sha1->Update(content); + } while (! done); + CleanupStack::PopAndDestroy(&fDest); + + // write hash to \sys\hash + TBuf8 hashVal = sha1->Final(); + + TFileName fnSrc(aFileName); + GetHashFileName(aFileName, fnSrc); + RFile fHash; + r = fHash.Replace(aFs, fnSrc, EFileWrite | EFileStream); + if (r != KErrNone) + DBGS_PRINT((_L("fHash.Replace returned %d\n"), r)); + User::LeaveIfError(r); + CleanupClosePushL(fHash); + r = fHash.Write(hashVal); + if (r != KErrNone) + DBGS_PRINT((_L("fHash.Write returned %d\n"), r)); + User::LeaveIfError(r); + + CleanupStack::PopAndDestroy(2, sha1); + } + +// +// CopyFileToMMc +// +// Copy a file to the MMC card and create a hash of it. +// + +TInt CopyFileToMMc(RFs& aFs,CFileMan* aFileMan, TPtrC aPath, TPtrC aOldFilename, TPtrC aNewFilename) + { + TInt retVal = aFs.MkDirAll(aPath); + RUNTEST1(retVal==KErrNone || retVal==KErrAlreadyExists); + + TFileName newPath; + TFileName oldPath; + + oldPath.Format(_L("%S%S"),&KRomPath, &aOldFilename); + newPath.Format(_L("%S%S"),&aPath, &aNewFilename); + DBGD_PRINT((_L("Copying %S to %S\n"), &oldPath, &newPath)); + retVal = aFileMan->Copy(oldPath, newPath, CFileMan::EOverWrite); + if (retVal == KErrNone) + { + retVal = aFileMan->Attribs(newPath, KEntryAttNormal, KEntryAttReadOnly, 0); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("%S : Attribs failed (%d)\n"), &newPath, retVal)); + } + TEntry anEntry; + retVal = aFs.Entry(newPath, anEntry); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("%S : aFs.Entry failed (%d)\n"), &newPath, retVal)); + } + TRAPD(r, HashFile(newPath, aFs)); + RUNTEST1(r == KErrNone); + } + else + DBGS_PRINT((_L("Failed to copy file %d\n"), retVal)); + DBGD_PRINT((_L("%S : now %S (%d)\n"), &newPath, EXISTS(retVal), retVal)); + return retVal; + } + +// +// CopyAndFragmentFiles +// +// Copy the test files to a specified location edeavouring to fragment as much as possible. +// + +TBool CopyAndFragmentFiles(RFs& aFs,CFileMan* aFileMan, TPtrC aPath, ETestMediaType aMediaType) + { + TInt retVal = aFs.MkDirAll(aPath); + RUNTEST1(retVal==KErrNone || retVal==KErrAlreadyExists); +#define FILECOUNTMAX (PAGELDRTST_MAX_DLLS + 2) + RFile theInFiles[FILECOUNTMAX]; + RFile theOutFiles[FILECOUNTMAX]; + TInt inFileSize[FILECOUNTMAX]; + TInt inFilePos[FILECOUNTMAX]; + TBool fileOk[FILECOUNTMAX]; + + TInt index; + TFileName newPath; + TFileName oldPath; + + for (index = 0; index < FILECOUNTMAX; index ++) + { + inFileSize[index] = 0; + inFilePos[index] = 0; + fileOk[index] = EFalse; + + if (index < PAGELDRTST_MAX_DLLS) + { + oldPath.Format(_L("%S%S%d%S"), &KRomPath, &KDllBaseName, index, &TestPlExtNames[KTestMediaBase]); + newPath.Format(_L("%S%S%d%S"), &aPath, &KDllBaseName, index, &TestPlExtNames[aMediaType]); + } + else if (index < (PAGELDRTST_MAX_DLLS + 1)) + { + oldPath.Format(_L("%S%S"), &KRomPath, &TestPsExeNames[KTestMediaBase]); + newPath.Format(_L("%S%S"), &aPath, &TestPsExeNames[aMediaType]); + } + else + { + oldPath.Format(_L("%S%S"), &KRomPath, &TestPlExeNames[KTestMediaBase]); + newPath.Format(_L("%S%S"), &aPath, &TestPlExeNames[aMediaType]); + } + + retVal = theInFiles[index].Open(aFs, oldPath, EFileRead); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("%S : Failed to open for read (%d)\n"), &oldPath, retVal)); + break; + } + retVal = theInFiles[index].Size(inFileSize[index]); + if (retVal != KErrNone) + { + theInFiles[index].Close(); + DBGS_PRINT((_L("%S : Failed to get file size (%d)\n"), &newPath, retVal)); + break; + } + retVal = theOutFiles[index].Replace(aFs, newPath, EFileWrite); + if (retVal != KErrNone) + { + theInFiles[index].Close(); + DBGS_PRINT((_L("%S : Failed to open for write (%d)\n"), &newPath, retVal)); + break; + } + + fileOk[index] = ETrue; + } + + const TInt KBufferSize = 3333; + TBuf8 buffer; + TBool stillGoing; + + do + { + stillGoing = EFalse; + for (index = 0; index < FILECOUNTMAX; index ++) + { + if (!fileOk[index]) + break; + if (inFilePos[index] < inFileSize[index]) + { + retVal = theInFiles[index].Read(buffer); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("theInFiles[%d] read failed (%d)\n"), index, retVal)); + break; + } + retVal = theOutFiles[index].Write(buffer); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("theOutFiles[%d] Write failed (%d)\n"), index, retVal)); + break; + } + retVal = theOutFiles[index].Flush(); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("theOutFiles[%d] flush failed (%d)\n"), index, retVal)); + break; + } + inFilePos[index] += buffer.Length(); + if (inFilePos[index] < inFileSize[index]) + stillGoing = ETrue; + } + } + } + while (stillGoing); + + TBool allOk = retVal == KErrNone; + for (index = 0; index < FILECOUNTMAX; index ++) + { + if (!fileOk[index]) + { + allOk = EFalse; + break; + } + theInFiles[index].Close(); + theOutFiles[index].Close(); + if (index < PAGELDRTST_MAX_DLLS) + { + newPath.Format(_L("%S%S%d%S"), &aPath, &KDllBaseName, index, &TestPlExtNames[aMediaType]); + } + else if (index < (PAGELDRTST_MAX_DLLS + 1)) + { + newPath.Format(_L("%S%S"), &aPath, &TestPsExeNames[aMediaType]); + } + else + { + newPath.Format(_L("%S%S"), &aPath, &TestPlExeNames[aMediaType]); + } + + retVal = aFileMan->Attribs(newPath, KEntryAttNormal, KEntryAttReadOnly, 0); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("%S : Attribs failed (%d)\n"), &newPath, retVal)); + allOk = EFalse; + } + TEntry anEntry; + retVal = aFs.Entry(newPath, anEntry); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("%S : aFs.Entry failed (%d)\n"), &newPath, retVal)); + allOk = EFalse; + } + TRAPD(r, HashFile(newPath, aFs)); + if (r != KErrNone) + { + allOk = EFalse; + } + DBGD_PRINT((_L("%S : %S!\n"), &newPath, EXISTS(!allOk))); + } + return allOk; + } + +// +// CheckFilePresence +// +// Checks all the files required for the test are present and copies some tests to the MMC card +// + +void CheckFilePresence(TBool aDoFileCopy) + { + TUint start = User::TickCount(); + + RFs fs; + if (KErrNone != fs.Connect()) + { + DBGS_PRINT(_L("CheckFilePresence : Can't connect to the FS\n")); + return ; + } + + TFileName filename; + TFileName newFilename; + TEntry anEntry; + TInt index; + TInt retVal; + TInt dllIndex; + + // now we need to add the MMC files + TInt drvNum = FindMMCDriveNumber(fs); + TBuf<32> mmcPath; + mmcPath.Format(_L("%S"),&KMmcDefaultPath); + if (drvNum >= 0) + mmcPath[0] = 'a' + drvNum; + + TBool allOk; + //TInt indexMax = aDoFileCopy ? KTestMediaMmc : KTestMediaCOUNT; + for (index = 0; index < TEST_MEDIA_COUNT_HACK; index ++) + { + allOk = ETrue; + filename.Format(_L("%S%S"),(index == KTestMediaMmc) ? & mmcPath : &KRomPath, &TestPsExeNames[index]); + if (KErrNone != fs.Entry(filename, anEntry)) + allOk = EFalse; + + filename.Format(_L("%S%S"),(index == KTestMediaMmc) ? & mmcPath : &KRomPath, &TestPlExeNames[index]); + if (KErrNone != fs.Entry(filename, anEntry)) + allOk = EFalse; + + for (dllIndex = 0; dllIndex < PAGELDRTST_MAX_DLLS; dllIndex ++) + { + filename.Format(_L("%S%S%d%S"), (index == KTestMediaMmc) ? & mmcPath : &KRomPath, &KDllBaseName, dllIndex, &TestPlExtNames[index]); + if (KErrNone != fs.Entry(filename, anEntry)) + allOk = EFalse; + } + TestDllExesExist[index] = allOk; + DBGS_PRINT((_L("%S : %S!\n"), &TestPsExeNames[index], EXISTS(!TestDllExesExist[index]))); + } + TInt nandDrvNum = FindFsNANDDrive(fs); + if (aDoFileCopy && (drvNum >= 0) && (nandDrvNum >= 0)) + { + CTrapCleanup* cleanupStack = CTrapCleanup::New(); + if(!cleanupStack) + DBGS_PRINT((_L("Cleanup stack failed\n"))); + CFileMan* pFileMan = NULL; + TRAP(retVal, pFileMan = CFileMan::NewL(fs)); + + // First make a clean copy of the DLLs to the MMC card. + allOk = ETrue; + if (KErrNone != CopyFileToMMc(fs, pFileMan, mmcPath, TestPsExeNames[KTestMediaBase], TestPsExeNames[KTestMediaMmc])) + allOk = EFalse; + if (KErrNone != CopyFileToMMc(fs, pFileMan, mmcPath, TestPlExeNames[KTestMediaBase], TestPlExeNames[KTestMediaMmc])) + allOk = EFalse; + for (dllIndex = 0; dllIndex < PAGELDRTST_MAX_DLLS; dllIndex ++) + { + filename.Format(_L("%S%d%S"), &KDllBaseName, dllIndex, &TestPlExtNames[KTestMediaBase]); + newFilename.Format(_L("%S%d%S"), &KDllBaseName, dllIndex, &TestPlExtNames[KTestMediaMmc]); + if (KErrNone != CopyFileToMMc(fs, pFileMan, mmcPath, filename, newFilename)) + allOk = EFalse; + } + TestDllExesExist[KTestMediaMmc] = allOk; + DBGS_PRINT((_L("%S : %S! (Drive %c)\n"), &TestPsExeNames[index], EXISTS(!TestDllExesExist[index]), mmcPath[0])); +#ifdef TEST_ADD_FRAGD_MEDIA + //now make some fragmented files on the MMC card. + TestDllExesExist[KTestMediaMmcFrag] = CopyAndFragmentFiles(fs, pFileMan, mmcPath, KTestMediaMmcFrag); + DBGS_PRINT((_L("%S : %S! (Drive %c)\n"), &TestPsExeNames[KTestMediaMmcFrag], EXISTS(!TestDllExesExist[KTestMediaMmcFrag]), mmcPath[0])); + + //now make some fragmented files on the NAND card. + if (nandDrvNum >= 0) + { + mmcPath[0] = 'a' + nandDrvNum; + TestDllExesExist[KTestMediaNandFrag] = CopyAndFragmentFiles(fs, pFileMan, mmcPath, KTestMediaNandFrag); + DBGS_PRINT((_L("%S : %S! (Drive %c)\n"), &TestPsExeNames[KTestMediaNandFrag], EXISTS(!TestDllExesExist[KTestMediaNandFrag]), mmcPath[0])); + } + else + DBGS_PRINT((_L("CheckFilePresence : Failed to get NAND drive number\n"))); +#endif // TEST_ADD_FRAGD_MEDIA + delete pFileMan; pFileMan = NULL; + delete cleanupStack; cleanupStack = NULL; + } + + fs.Close(); + + TUint end = User::TickCount(); + TUint time = TUint((TUint64)(end-start)*(TUint64)TickPeriod/(TUint64)1000000); + DBGS_PRINT((_L("CheckFilePresence : %d secs elapsed\n"), time)); + } + +// +// DoDeleteFile +// +// Delete a file and remove the hash +// + +void DoDeleteFile(CFileMan* aFileMan, TBool aSilent,TFileName& aFileName ) + { + TFileName hashName; + RLoader l; + test(l.Connect() == KErrNone); + + DBGD_PRINT((_L("Deleting %S ...\n"), &aFileName)); + if (!aSilent) + DBGD_PRINT((_L("Deleting %S\n"), &aFileName)); + TInt retVal = aFileMan->Delete(aFileName); + if (retVal != KErrNone) + { + if (TestingReaper) + { + aFileMan->Attribs(aFileName, KEntryAttNormal, KEntryAttReadOnly, 0); + retVal = l.Delete(aFileName); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("RLoader::Delete %S Failed %d\n"), &aFileName, retVal)); + } + } + else + { + if (!aSilent) + DBGS_PRINT((_L("Deleting %S Failed %d\n"), &aFileName, retVal)); + } + } + GetHashFileName(aFileName, hashName); + retVal = aFileMan->Delete(hashName); + if (retVal != KErrNone) + { + if (TestingReaper && (retVal == KErrInUse)) + { + retVal = l.Delete(hashName); + if (retVal != KErrNone) + { + DBGS_PRINT((_L("RLoader::Delete %S Failed %d\n"), &hashName, retVal)); + } + } + else + { + if (!aSilent) + DBGS_PRINT((_L("Deleting %S Failed %d\n"), &hashName, retVal)); + } + } + l.Close(); + } + +// +// CleanupFiles +// +// Remove any copied files and created directories. +// + +void CleanupFiles(TBool silent) + { + TUint start = User::TickCount(); + + RFs fs; + if (KErrNone != fs.Connect()) + { + DBGS_PRINT(_L("CleanupFiles : Can't connect to the FS\n")); + return ; + } + + CTrapCleanup* cleanupStack = CTrapCleanup::New(); + if(!cleanupStack) + if (!silent) + DBGS_PRINT((_L("Cleanup stack failed\n"))); + + CFileMan* pFileMan = NULL; + TInt retVal; + TRAP(retVal, pFileMan = CFileMan::NewL(fs)); + + TFileName newPath; + TInt index; + TInt dllIndex; + + TBuf<32> path; + path.Format(_L("%S"),&KMmcDefaultPath); + TInt mmcDrvNum = FindMMCDriveNumber(fs); + TInt nandDrvNum = FindFsNANDDrive(fs); + for (index = KTestMediaMmc; index < KTestMediaCOUNT; index ++) + { +#ifdef TEST_ADD_FRAGD_MEDIA + if (index == KTestMediaNandFrag) + { + if (nandDrvNum < 0) + continue; + path[0] = 'a' + nandDrvNum; + } + else + { + if (mmcDrvNum < 0) + continue; + path[0] = 'a' + mmcDrvNum; + } +#else + path[0] = 'a' + mmcDrvNum; +#endif + newPath.Format(_L("%S%S"),&path, &TestPsExeNames[index]); + DoDeleteFile(pFileMan, silent, newPath); + + newPath.Format(_L("%S%S"),&path, &TestPlExeNames[index]); + DoDeleteFile(pFileMan, silent, newPath); + + for (dllIndex = 0; dllIndex < PAGELDRTST_MAX_DLLS; dllIndex ++) + { + newPath.Format(_L("%S%S%d%S"), &path, &KDllBaseName, dllIndex, &TestPlExtNames[index]); + DoDeleteFile(pFileMan, silent, newPath); + } + } + if (nandDrvNum >= 0) + { + path[0] = 'a' + nandDrvNum; + fs.RmDir(path); + } + if (mmcDrvNum >= 0) + { + path[0] = 'a' + mmcDrvNum; + fs.RmDir(path); + } + + delete pFileMan; pFileMan = NULL; + delete cleanupStack; cleanupStack = NULL; + fs.Close(); + TUint end = User::TickCount(); + TUint time = TUint((TUint64)(end-start)*(TUint64)TickPeriod/(TUint64)1000000); + DBGS_PRINT((_L("CleanupFiles : %d secs elapsed\n"), time)); + } + +#ifdef _DEBUG + +// +// FindLocalDriveNumber +// +// Find the local drive +// + +TInt FindLocalDriveNumber(RFs &aFs, TInt aFsDrvNum) + { + RFile file; + TBuf<256> fileName; + fileName.Append((TChar)('A' + aFsDrvNum)); + fileName+=_L(":\\f32-tst\\"); + TInt r=aFs.MkDirAll(fileName); + TInt locDriveNumber = -1; + if (r==KErrNone || r== KErrAlreadyExists) + { + fileName += _L("tempy.txt"); + r=file.Replace(aFs,fileName,EFileWrite); + if (r!=KErrNone) + DBGS_PRINT((_L("FindLocalDriveNumber : Error %d: file '%S' could not be created\n"),r,&fileName)); + RUNTEST1(r==KErrNone); + r=file.Write(_L8("Flies as big as sparrows indoletly buzzing in the warm air, heavy with the stench of rotting carcasses")); + if (r!=KErrNone) + { + DBGS_PRINT((_L("FindLocalDriveNumber : Error %d: could not write to file %d (%S)\n"),r,aFsDrvNum, &fileName)); + } + else + { + // write caching may be enabled to flush the cache... + TRequestStatus flushStatus; + file.Flush(flushStatus); + User::WaitForRequest(flushStatus); + // get the block map + SBlockMapInfo info; + TInt64 start=0; + r=file.BlockMap(info, start, -1,ETestDebug); + if (r==KErrNone || r==KErrCompletion) + { + locDriveNumber=info.iLocalDriveNumber; + DBGD_PRINT((_L("FindLocalDriveNumber : locDriveNumber %d\n"), locDriveNumber)); + } + else + DBGS_PRINT((_L("FindLocalDriveNumber : Error %d: error getting blockmap for drive %d (%S)\n"),r,aFsDrvNum, &fileName)); + } + aFs.Delete(fileName); + file.Close(); + } + else + DBGS_PRINT((_L("FindLocalDriveNumber : Error %d: error creating dir \n"),r)); + return locDriveNumber; + } + +// +// ResetConcurrencyStats +// +// Reset the stats +// + +void ResetConcurrencyStats(RFs& aFs) + { + if(TestBootedFromMmc) + { + TInt fsDriveNum = FindMMCDriveNumber(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if (locDriveNumber >= 0) + { + RUNTEST(PagingInfo::ResetConcurrency(locDriveNumber,EMediaPagingStatsRomAndCode),KErrNone); + } + else + DBGS_PRINT((_L("ResetConcurrencyStats MMC : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("ResetConcurrencyStats MMC : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + else + { + TInt fsDriveNum = FindFsNANDDrive(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if (locDriveNumber >= 0) + { + RUNTEST(PagingInfo::ResetConcurrency(locDriveNumber,EMediaPagingStatsRomAndCode),KErrNone); + } + else + DBGS_PRINT((_L("ResetConcurrencyStats NAND : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("ResetConcurrencyStats NAND : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + } + +// +// ResetBenchmarks +// +// Reset the stats +// + +void ResetBenchmarks(RFs& aFs) + { + if(TestBootedFromMmc) + { + TInt fsDriveNum = FindMMCDriveNumber(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if (locDriveNumber >= 0) + { + RUNTEST(PagingInfo::ResetBenchmarks(locDriveNumber,EMediaPagingStatsRomAndCode),KErrNone); + } + else + DBGS_PRINT((_L("ResetBenchmarks MMC : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("ResetBenchmarks MMC : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + else + { + TInt fsDriveNum = FindFsNANDDrive(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if (locDriveNumber >= 0) + { + RUNTEST(PagingInfo::ResetBenchmarks(locDriveNumber,EMediaPagingStatsRomAndCode),KErrNone); + } + else + DBGS_PRINT((_L("ResetBenchmarks NAND : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("ResetBenchmarks NAND : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + } + +// +// DisplayConcurrencyStats +// +// Display the stats +// + +void DisplayConcurrencyStats(RFs& aFs) + { + if(TestBootedFromMmc) + { + TInt fsDriveNum = FindMMCDriveNumber(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if (locDriveNumber >= 0) + { + DBGS_PRINT((_L("MMC stats\n"))); + RUNTEST1(PagingInfo::PrintConcurrency(locDriveNumber,EMediaPagingStatsRomAndCode)==KErrNone); + } + else + DBGS_PRINT((_L("DisplayConcurrencyStats MMC : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("DisplayConcurrencyStats MMC : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + else + { + TInt fsDriveNum = FindFsNANDDrive(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + + if (locDriveNumber >= 0) + { + DBGS_PRINT((_L("NAND stats\n"))); + RUNTEST1(PagingInfo::PrintConcurrency(locDriveNumber,EMediaPagingStatsRomAndCode)==KErrNone); + } + else + DBGS_PRINT((_L("DisplayConcurrencyStats NAND : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("DisplayConcurrencyStats NAND : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + } + +void DisplayBenchmarks(RFs& aFs) + { + if(TestBootedFromMmc) + { + TInt fsDriveNum = FindMMCDriveNumber(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if(locDriveNumber>=0) + { + DBGS_PRINT((_L("MMC benchmarks\n"))); + RUNTEST1(PagingInfo::PrintBenchmarks(locDriveNumber,EMediaPagingStatsRomAndCode)==KErrNone); + } + else + DBGS_PRINT((_L("DisplayBenchmarks MMC : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("DisplayBenchmarks MMC : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + else + { + TInt fsDriveNum = FindFsNANDDrive(aFs); + if (fsDriveNum >= 0) + { + TInt locDriveNumber = FindLocalDriveNumber(aFs, fsDriveNum); + if(locDriveNumber>=0) + { + DBGS_PRINT((_L("NAND benchmarks\n"))); + RUNTEST1(PagingInfo::PrintBenchmarks(locDriveNumber,EMediaPagingStatsRomAndCode)==KErrNone); + } + else + DBGS_PRINT((_L("DisplayBenchmarks NAND : Failed to get locDriveNumber %d (%d)\n"), locDriveNumber, fsDriveNum)); + } + else + DBGS_PRINT((_L("DisplayBenchmarks NAND : Failed to get fsDriveNum %d\n"), fsDriveNum)); + } + } + +#endif + +void DoStats() + { + if (TestIsDemandPaged) + { + SVMCacheInfo tempPages; + UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0); + DBGS_PRINT((_L("DPC : min %d max %d curr %d\n"), + tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize)); + DBGS_PRINT((_L(" : maxFree %d freeRam %d\n"), + tempPages.iMaxFreeSize, FreeRam())); + } + +#ifdef _DEBUG + if (TestWeAreTheTestBase && !TestSilent) + { + RFs fs; + if (KErrNone != fs.Connect()) + { + DBGS_PRINT(_L("ResetConcurrencyStats : Can't connect to the FS\n")); + return; + } + +#ifndef TEST_MINIMAL_STATS + DisplayConcurrencyStats(fs); + DisplayBenchmarks(fs); +#endif +#ifndef TEST_DONT_RESET_STATS + ResetConcurrencyStats(fs); + ResetBenchmarks(fs); +#endif + fs.Close(); + } +#endif + } + + +// +// E32Main +// +// Main entry point. +// + +TInt E32Main() + { +#ifndef TEST_ON_UNPAGED + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); + if(!romHeader->iPageableRomStart) + { + TestIsDemandPaged = EFalse; + } +#endif + // Turn off lazy dll unloading + RLoader l; + if (l.Connect() == KErrNone) + { + l.CancelLazyDllUnload(); + l.Close(); + } + + HAL::Get(HAL::ESystemTickPeriod, TickPeriod); + + SVMCacheInfo tempPages; + memset(&tempPages, 0, sizeof(tempPages)); + + TBool parseResult = ParseCommandLine(); + + if (TestExit) + { + return KErrNone; + } + + TUint start = User::TickCount(); + + AreWeTheTestBase(); + + if (TestIsDemandPaged) + { + TInt minSize = TestMinCacheSize; + TInt maxSize = TestMaxCacheSize; + + SVMCacheInfo tempPages; + + // 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); + } + if (!TestSilent) + { + test.Title(); + test.Start(_L("Demand Paging loader stress tests...")); + test.Printf(_L("%S (%d)\n"), &TestNameBuffer, TestWeAreTheTestBase); + test.Printf(_L("TestBootedFromMmc %d\n"), TestBootedFromMmc); + + if (TestWeAreTheTestBase) + CleanupFiles(ETrue); + + CheckFilePresence(TestWeAreTheTestBase); + } + + if (parseResult) + { + if (TestLowMem) + { + DoLowMemTest(ETrue); + } + if (TestSingle) + { + RUNTEST(DoSingleTest(),KErrNone); + } + if (TestMultiple) + { + RUNTEST(DoMultipleTest(),KErrNone); + } + if (TestD_Exc) + { + RUNTEST(DoTestD_Exc(),KErrNone); + } + if (TestChunks) + { + DoChunkTests(); + } + if (TestReaper) + { + DoReaperTests(); + } + if (TestBtrace) + { + DoBtraceTest(); + } + if (TestDefrag) + { + DoDefragTest(); + } + } + else + { +#ifdef _DEBUG + if (TestWeAreTheTestBase) + { + RFs fs; + if (KErrNone == fs.Connect()) + { + //fs.SetDebugRegister(KCACHE); + ResetConcurrencyStats(fs); + ResetBenchmarks(fs); + fs.Close(); + } + } +#endif + + while (1) + { + if (TestIsDemandPaged) + { +#ifdef TEST_RUN_AUTOTEST + PerformAutoTest(); +#endif //TEST_RUN_AUTOTEST + +#ifndef TEST_SHORT_TEST +#ifdef TEST_RUN_LOWMEMTEST + DoLowMemTest(ETrue); +#endif //TEST_RUN_LOWMEMTEST +#ifdef TEST_RUN_CHUNKTEST + DoChunkTests(); +#endif //TEST_RUN_CHUNKTEST +#ifdef TEST_RUN_REAPERTEST + DoReaperTests(); +#endif //TEST_RUN_REAPERTEST +#endif //TEST_SHORT_TEST + } + +#ifdef TEST_RUN_DEFRAGTEST + DoDefragTest(); +#endif //TEST_RUN_DEFRAGTEST + + if (TestStressFree) + { + TInt minSize = 512 * 4096; + TInt maxSize = 32767 * 4096; + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + + test.Printf(_L("%S Stress Free!!\n"), &TestNameBuffer, TestWeAreTheTestBase); + TestStressFree = EFalse; + } + else + { + break; + } + } + +#ifndef TEST_SHORT_TEST +#ifndef TEST_NO_DEXC_IN_AUTO +#ifdef TEST_RUN_D_EXCTEST + RUNTEST(DoTestD_Exc(),KErrNone); +#endif //TEST_RUN_D_EXCTEST +#endif //TEST_NO_DEXC_IN_AUTO + if (TestWeAreTheTestBase && TestFullAutoTest && TestIsDemandPaged) + { + RProcess theProcess; + TRequestStatus status; + + TInt retVal = theProcess.Create(_L("t_pageldrtst_rom.exe"),_L("fullauto")); + if (retVal != KErrNotFound) + { + RUNTEST1(KErrNone == retVal); + theProcess.Logon(status); + RUNTEST1(status == KRequestPending); + theProcess.Resume(); +#ifdef TEST_THRASHING_TEST + while (1) + { + if (theProcess.ExitType() != EExitPending) + { + RUNTEST1(theProcess.ExitType() != EExitPanic); + break; + } + User::AfterHighRes(1); + } + User::WaitForRequest(status); +#else + User::WaitForRequest(status); + if (theProcess.ExitType() != EExitPending) + { + RUNTEST1(theProcess.ExitType() != EExitPanic); + } +#endif //TEST_THRASHING_TEST + theProcess.Close(); + } + } +#endif //TEST_SHORT_TEST +#ifdef _DEBUG + if (TestWeAreTheTestBase && !TestSilent) + { + RFs fs; + if (KErrNone == fs.Connect()) + { + DisplayConcurrencyStats(fs); + DisplayBenchmarks(fs); + fs.Close(); + } + } +#endif + } + + if (TestWeAreTheTestBase && !TestNoClean) + CleanupFiles(EFalse); + + if (TestIsDemandPaged) + { + TInt minSize = tempPages.iMinSize; + TInt maxSize = tempPages.iMaxSize; + // put the cache back to the the original values. + UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize); + } + if (!TestSilent) + { + TUint end = User::TickCount(); + TUint time = TUint((TUint64)(end-start)*(TUint64)TickPeriod/(TUint64)1000000); + test.Printf(_L("%S : Complete (%u seconds)\n"), &TestNameBuffer, time); + test.End(); + } + return KErrNone; + }