diff -r 41f0cfe18c80 -r c734af59ce98 kerneltest/e32test/demandpaging/t_thrash.cpp --- a/kerneltest/e32test/demandpaging/t_thrash.cpp Tue Apr 27 18:02:57 2010 +0300 +++ b/kerneltest/e32test/demandpaging/t_thrash.cpp Tue May 11 17:28:22 2010 +0300 @@ -27,6 +27,7 @@ #include #include #include +#include #include "t_dpcmn.h" #include "../mmu/mmudetect.h" @@ -39,11 +40,12 @@ _LIT(KChunkName, "t_thrash chunk"); -class TRandom +class TPRNG { public: - TRandom(); - TUint32 Next(); + TPRNG(); + TUint32 IntRand(); + TReal FloatRand(); private: enum @@ -54,17 +56,178 @@ TUint32 iV; }; -TRandom::TRandom() +TPRNG::TPRNG() { iV = (TUint32)this + RThread().Id() + User::FastCounter() + 23; } -TUint32 TRandom::Next() +TUint32 TPRNG::IntRand() { iV = KA * iV + KB; return iV; } +TReal TPRNG::FloatRand() + { + return (TReal)IntRand() / KMaxTUint32; + } + +class TRandom + { +public: + virtual ~TRandom() { } + virtual TUint32 Next() = 0; + }; + + class TUniformRandom : public TRandom + { +public: + void SetParams(TUint aMax) { iMax = aMax; } + virtual TUint32 Next(); + +private: + TPRNG iRand; + TUint iMax; + }; + +TUint32 TUniformRandom::Next() + { + return iRand.IntRand() % iMax; + } + +class TNormalRandom : public TRandom + { +public: + void SetParams(TInt aMax, TInt aSd); + virtual TUint32 Next(); + +private: + TUint32 GetNext(); + +private: + TPRNG iRand; + TInt iMax; + TInt iExpectation; + TInt iSd; + TUint32 iCached; + }; + +void TNormalRandom::SetParams(TInt aMax, TInt aSd) + { + iMax = aMax; + iExpectation = aMax / 2; + iSd = aSd; + iCached = KMaxTUint32; + } + +TUint32 TNormalRandom::Next() + { + TUint32 r; + do + { + r = GetNext(); + } + while (r > (TUint)iMax); + return r; + } + +TUint32 TNormalRandom::GetNext() + { + if (iCached != KMaxTUint32) + { + TUint32 r = iCached; + iCached = KMaxTUint32; + return r; + } + + // box-muller transform + // from http://www.taygeta.com/random/gaussian.html + + TReal x1, x2, w, ln_w, y1, y2; + do + { + x1 = 2.0 * iRand.FloatRand() - 1.0; + x2 = 2.0 * iRand.FloatRand() - 1.0; + w = x1 * x1 + x2 * x2; + } + while ( w >= 1.0 ); + + TInt r = Math::Ln(ln_w, w); + __ASSERT_ALWAYS(r == KErrNone, User::Invariant()); + w = (-2.0 * ln_w ) / w; + TReal w2; + r = Math::Sqrt(w2, w); + __ASSERT_ALWAYS(r == KErrNone, User::Invariant()); + y1 = x1 * w2; + y2 = x2 * w2; + + y1 = y1 * iSd + iExpectation; + y2 = y2 * iSd + iExpectation; + + iCached = (TUint32)y2; + + return (TUint32)y1; + } + +static TBool BenchmarksSupported = EFalse; +static TReal BenchmarkMultiplier; + +static TInt InitBenchmarks() + { + BenchmarksSupported = UserSvr::HalFunction(EHalGroupVM, EVMHalResetPagingBenchmark, (TAny*)EPagingBmReadRomPage, NULL) == KErrNone; + if (!BenchmarksSupported) + return KErrNone; + + TInt freq = 0; + TInt r = HAL::Get(HAL::EFastCounterFrequency, freq); + if (r != KErrNone) + return r; + BenchmarkMultiplier = 1000000.0 / freq; + return KErrNone; + } + +static void ResetBenchmarks() + { + if (!BenchmarksSupported) + return; + for (TInt i = 0 ; i < EMaxPagingBm ; ++i) + { + TInt r = UserSvr::HalFunction(EHalGroupVM, EVMHalResetPagingBenchmark, (TAny*)i, NULL); + if (r != KErrNone) + test.Printf(_L("Error resetting benchmark %d\n"), i); + test_KErrNone(r); + } + } + +static TInt GetBenchmark(TPagingBenchmark aBenchmark, TInt& aCountOut, TInt& aTotalTimeInMicrosOut) + { + + SPagingBenchmarkInfo info; + TInt r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetPagingBenchmark, (TAny*)aBenchmark, &info); + if (r!=KErrNone) + return r; + + aCountOut = info.iCount; + aTotalTimeInMicrosOut = (TInt)(info.iTotalTime * BenchmarkMultiplier); + return KErrNone; + } + +static TInt GetAllBenchmarks(TInt aTestLengthInSeconds, TInt aCountOut[EMaxPagingBm], TInt aTimeOut[EMaxPagingBm]) + { + for (TInt i = 0 ; i < EMaxPagingBm ; ++i) + { + TInt count = 0; + TInt timeInMicros = 0; + TInt r = GetBenchmark((TPagingBenchmark)i, count, timeInMicros); + if (r != KErrNone) + return r; + + aCountOut[i] = count / aTestLengthInSeconds; + aTimeOut[i] = timeInMicros / aTestLengthInSeconds; + } + return KErrNone; + } + void CreatePagedChunk(TInt aSizeInPages) { test_Equal(0,gChunk.Handle()); @@ -84,11 +247,70 @@ return (TUint32*)(gChunk.Base() + (gPageSize * aPage)); } +TInt EnsureSystemIdleThread(TAny*) + { + RThread::Rendezvous(KErrNone); + for (;;) + { + // Spin + } + } + +void EnsureSystemIdle() + { + const TInt KMaxWait = 60 * 1000000; + const TInt KSampleTime = 1 * 1000000; + const TInt KWaitTime = 5 * 1000000; + + test.Printf(_L("Waiting for system to become idle\n")); + TInt totalTime = 0; + TBool idle; + do + { + RThread thread; + test_KErrNone(thread.Create(_L("EnsureSystemIdleThread"), EnsureSystemIdleThread, 1024, NULL, NULL)); + thread.SetPriority(EPriorityLess); + thread.Resume(); + + TRequestStatus status; + thread.Rendezvous(status); + User::WaitForRequest(status); + test_KErrNone(status.Int()); + + User::After(KSampleTime); + thread.Suspend(); + + TTimeIntervalMicroSeconds time; + test_KErrNone(thread.GetCpuTime(time)); + TReal error = (100.0 * Abs(time.Int64() - KSampleTime)) / KSampleTime; + test.Printf(_L(" time == %ld, error == %f%%\n"), time.Int64(), error); + + idle = error < 2.0; + + thread.Kill(KErrNone); + thread.Logon(status); + User::WaitForRequest(status); + test_KErrNone(status.Int()); + CLOSE_AND_WAIT(thread); + + if (!idle) + User::After(KWaitTime); // Allow system to finish whatever it's doing + + totalTime += KSampleTime + KWaitTime; + test(totalTime < KMaxWait); + } + while(!idle); + } + enum TWorkload { EWorkloadSequential, - EWorkloadRandom, - EWorkloadShuffle + EWorkloadUniformRandom, + EWorkloadNormalRandom1, + EWorkloadNormalRandom2, + EWorkloadShuffle, + + EMaxWorkloads }; struct SThrashTestArgs @@ -105,55 +327,86 @@ { SThrashTestArgs* args = (SThrashTestArgs*)aArg; - TRandom random; + TPRNG random; + TUniformRandom uniformRand; + TNormalRandom normalRand; + TInt startPage = args->iThreadGroup * args->iGroupSize; TInt* ptr = (TInt*)(args->iBasePtr + startPage * gPageSize); + + switch (args->iWorkload) { case EWorkloadSequential: while (gRunThrashTest) { - TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); - for (TInt i = 0 ; i < size && gRunThrashTest ; ++i) + for (TUint i = 0 ; + gRunThrashTest && i < (args->iPageCount * gPageSize) / sizeof(TInt) ; + ++i) { - ptr[i] = random.Next(); + ptr[i] = 1; __e32_atomic_add_ord64(&args->iAccesses, 1); } } break; - case EWorkloadRandom: + case EWorkloadUniformRandom: + case EWorkloadNormalRandom1: + case EWorkloadNormalRandom2: { TInt acc = 0; + TInt oldSize = -1; + TUint32 writeMask = 0; + switch (args->iWorkload) + { + case EWorkloadUniformRandom: + case EWorkloadNormalRandom1: + writeMask = 0x80000000; break; + case EWorkloadNormalRandom2: + writeMask = 0xc0000000; break; + default: test(EFalse); break; + } while (gRunThrashTest) { - TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); - for (TInt i = 0 ; i < size && gRunThrashTest ; ++i) + TInt size = args->iPageCount; + if (size != oldSize) { - TUint32 rand = random.Next(); - TInt action = rand >> 31; - TInt r = rand % size; - if (action == 0) - acc += ptr[r]; - else - ptr[r] = acc; - __e32_atomic_add_ord64(&args->iAccesses, 1); + switch (args->iWorkload) + { + case EWorkloadUniformRandom: + uniformRand.SetParams(size); break; + case EWorkloadNormalRandom1: + case EWorkloadNormalRandom2: + normalRand.SetParams(size, size / 8); break; + default: test(EFalse); break; + } + oldSize = size; } + + TInt page = args->iWorkload == EWorkloadUniformRandom ? + uniformRand.Next() : normalRand.Next(); + TInt index = page * (gPageSize / sizeof(TInt)); + TBool write = (random.IntRand() & writeMask) == 0; + if (write) + ptr[index] = acc; + else + acc += ptr[index]; + __e32_atomic_add_ord64(&args->iAccesses, 1); } } break; case EWorkloadShuffle: { - TInt i; + TInt i = 0; while (gRunThrashTest) { TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); - for (i = 0 ; gRunThrashTest && i < (size - 1) ; ++i) - { - Mem::Swap(&ptr[i], &ptr[i + random.Next() % (size - i - 1) + 1], sizeof(TInt)); - __e32_atomic_add_ord64(&args->iAccesses, 2); - } + Mem::Swap(&ptr[i], &ptr[i + random.IntRand() % (size - i - 1) + 1], sizeof(TInt)); + __e32_atomic_add_ord64(&args->iAccesses, 2); + ++i; + if (i >= size - 1) + i = 0; } } break; @@ -172,17 +425,32 @@ SThrashTestArgs iArgs; }; -void ThrashTest(TInt aThreads, // number of threads to run +void ThrashTest(const TDesC& aTestName, // name and description + TInt aThreads, // number of threads to run TBool aSharedData, // whether all threads share the same data TWorkload aWorkload, TInt aBeginPages, // number of pages to start with for last/all threads TInt aEndPages, // number of pages to end with for last/all threads TInt aOtherPages) // num of pages for other threads, or zero to use same value for all { - RDebug::Printf("\nPages Accesses ThL"); + const TInt KTestLengthInSeconds = 2; + + test.Next(_L("Thrash test")); + + DPTest::FlushCache(); + EnsureSystemIdle(); - DPTest::FlushCache(); - User::After(1000000); + TInt i; + test.Printf(_L("Table: %S\n"), &aTestName); + test.Printf(_L("totalPages, totalAccesses, thrashLevel")); + if (BenchmarksSupported) + test.Printf(_L(", rejuveCount, rejuveTime, codePageInCount, codePageInTime, initCount, initTime, readCount, readTime, writePages, writeCount, writeTime")); + if (aThreads > 1) + { + for (TInt i = 0 ; i < aThreads ; ++i) + test.Printf(_L(", Thread%dPages, Thread%dAccesses"), i, i); + } + test.Printf(_L("\n")); TInt pagesNeeded; TInt maxPages = Max(aBeginPages, aEndPages); @@ -208,11 +476,10 @@ test_NotNull(threads); gRunThrashTest = ETrue; - TInt pageCount = aBeginPages; const TInt maxSteps = 30; TInt step = aEndPages >= aBeginPages ? Max((aEndPages - aBeginPages) / maxSteps, 1) : Min((aEndPages - aBeginPages) / maxSteps, -1); + TInt pageCount = aBeginPages - 5 * step; // first run ignored - TInt i; for (i = 0 ; i < aThreads ; ++i) { SThrashThreadData& thread = threads[i]; @@ -242,8 +509,10 @@ for (i = 0 ; i < aThreads ; ++i) __e32_atomic_store_ord64(&threads[i].iArgs.iAccesses, 0); + ResetBenchmarks(); - User::After(2000000); + User::After(KTestLengthInSeconds * 1000 * 1000); + TInt thrashLevel = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); test(thrashLevel >= 0 && thrashLevel <= 255); @@ -257,20 +526,50 @@ else totalPages += threads[i].iArgs.iPageCount; } + TInt accessesPerSecond = (TInt)(totalAccesses / KTestLengthInSeconds); - test.Printf(_L("%5d %12ld %3d"), totalPages, totalAccesses, thrashLevel); - for (i = 0 ; i < aThreads ; ++i) + TBool warmingUp = (step > 0) ? pageCount < aBeginPages : pageCount > aBeginPages; + if (!warmingUp) { - test.Printf(_L(" %5d %12ld"), - threads[i].iArgs.iPageCount, - __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses)); - test_Equal(KRequestPending, threads[i].iStatus.Int()); + test.Printf(_L("%10d, %13d, %11.2f"), totalPages, accessesPerSecond, (TReal)thrashLevel / 255); + + if (BenchmarksSupported) + { + TInt benchmarkCount[EMaxPagingBm]; + TInt benchmarkTime[EMaxPagingBm]; + test_KErrNone(GetAllBenchmarks(KTestLengthInSeconds, benchmarkCount, benchmarkTime)); + + TInt otherPageInCount = benchmarkCount[EPagingBmReadRomPage] + benchmarkCount[EPagingBmReadCodePage]; + TInt otherPageInTime = benchmarkTime[EPagingBmReadRomPage] + benchmarkTime[EPagingBmReadCodePage]; + + TInt initCount = benchmarkCount[EPagingBmReadDataPage] - benchmarkCount[EPagingBmReadDataMedia]; + TInt initTime = benchmarkTime[EPagingBmReadDataPage] - benchmarkTime[EPagingBmReadDataMedia]; + + test.Printf(_L(", %11d, %10d, %15d, %14d, %9d, %8d, %9d, %8d, %10d, %10d, %9d"), + benchmarkCount[EPagingBmRejuvenate], benchmarkTime[EPagingBmRejuvenate], + otherPageInCount, otherPageInTime, + initCount, initTime, + benchmarkCount[EPagingBmReadDataMedia], benchmarkTime[EPagingBmReadDataMedia], + benchmarkCount[EPagingBmWriteDataPage], + benchmarkCount[EPagingBmWriteDataMedia], benchmarkTime[EPagingBmWriteDataMedia]); + } + + if (aThreads > 1) + { + for (i = 0 ; i < aThreads ; ++i) + { + test.Printf(_L(", %12d, %15ld"), + threads[i].iArgs.iPageCount, + __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses)); + test_Equal(KRequestPending, threads[i].iStatus.Int()); + } + } + test.Printf(_L("\n")); } - test.Printf(_L("\n")); + pageCount += step; if (aEndPages >= aBeginPages ? pageCount >= aEndPages : pageCount < aEndPages) break; - pageCount += step; } gRunThrashTest = EFalse; @@ -285,7 +584,7 @@ } gChunk.Close(); - RDebug::Printf("\n"); + test.Printf(_L("\n")); } void TestThrashing() @@ -298,47 +597,96 @@ TInt maxPages4 = (5 * gMaxCacheSize) / 16; // Single thread increasing in size - test.Next(_L("Thrash test: single thread, sequential workload")); - ThrashTest(1, ETrue, EWorkloadSequential, minPages, maxPages, 0); + ThrashTest(_L("single thread, sequential workload"), + 1, ETrue, EWorkloadSequential, minPages, maxPages, 0); - test.Next(_L("Thrash test: single thread, random workload")); - ThrashTest(1, ETrue, EWorkloadRandom, minPages, maxPages, 0); + ThrashTest(_L("single thread, random workload"), + 1, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); - test.Next(_L("Thrash test: single thread, shuffle workload")); - ThrashTest(1, ETrue, EWorkloadShuffle, minPages, maxPages, 0); + ThrashTest(_L("single thread, shuffle workload"), + 1, ETrue, EWorkloadShuffle, minPages, maxPages, 0); // Multiple threads with shared data, one thread incresing in size - test.Next(_L("Thrash test: two threads with shared data, one thread increasing, random workload")); - ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, minPages); + ThrashTest(_L("two threads with shared data, one thread increasing, random workload"), + 2, ETrue, EWorkloadUniformRandom, minPages, maxPages, minPages); - test.Next(_L("Thrash test: four threads with shared data, one thread increasing, random workload")); - ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, minPages); + ThrashTest(_L("four threads with shared data, one thread increasing, random workload"), + 4, ETrue, EWorkloadUniformRandom, minPages, maxPages, minPages); // Multiple threads with shared data, all threads incresing in size - test.Next(_L("Thrash test: two threads with shared data, all threads increasing, random workload")); - ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, 0); + ThrashTest(_L("two threads with shared data, all threads increasing, random workload"), + 2, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); - test.Next(_L("Thrash test: four threads with shared data, all threads increasing, random workload")); - ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, 0); + ThrashTest(_L("four threads with shared data, all threads increasing, random workload"), + 4, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); // Multiple threads with independent data, one thread incresing in size - test.Next(_L("Thrash test: two threads with independent data, one thread increasing, random workload")); - ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, gMaxCacheSize / 2); + ThrashTest(_L("two threads with independent data, one thread increasing, random workload"), + 2, EFalse, EWorkloadUniformRandom, minPages2, maxPages2, gMaxCacheSize / 2); - test.Next(_L("Thrash test: four threads with independent data, one thread increasing, random workload")); - ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, gMaxCacheSize / 4); + ThrashTest(_L("four threads with independent data, one thread increasing, random workload"), + 4, EFalse, EWorkloadUniformRandom, minPages4, maxPages4, gMaxCacheSize / 4); // Multiple threads with independant data, all threads incresing in size - test.Next(_L("Thrash test: two threads with independent data, all threads increasing, random workload")); - ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, 0); + ThrashTest(_L("two threads with independent data, all threads increasing, random workload"), + 2, EFalse, EWorkloadUniformRandom, minPages2, maxPages2, 0); - test.Next(_L("Thrash test: four threads with independent data, all threads increasing, random workload")); - ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, 0); + ThrashTest(_L("four threads with independent data, all threads increasing, random workload"), + 4, EFalse, EWorkloadUniformRandom, minPages4, maxPages4, 0); // Attempt to create thrash state where there is sufficient cache - test.Next(_L("Thrash test: two threads with independent data, one threads decreasing, random workload")); TInt halfCacheSize = gMaxCacheSize / 2; - ThrashTest(2, EFalse, EWorkloadRandom, halfCacheSize + 10, halfCacheSize - 30, halfCacheSize); + ThrashTest(_L("two threads with independent data, one threads decreasing, random workload"), + 2, EFalse, EWorkloadUniformRandom, halfCacheSize + 10, halfCacheSize - 30, halfCacheSize); + } + +void TestDistribution(TRandom& aRandom, TInt aSamples) + { + TUint32* data = new TUint32[aSamples]; + test_NotNull(data); + + TInt i; + TReal mean = 0.0; + for (i = 0 ; i < aSamples ; ++i) + { + data[i] = aRandom.Next(); + mean += (TReal)data[i] / aSamples; + } + + TReal sum2 = 0.0; + for (i = 0 ; i < aSamples ; ++i) + { + TReal d = (TReal)data[i] - mean; + sum2 += d * d; + } + TReal variance = sum2 / (aSamples - 1); + + test.Printf(_L(" mean == %f\n"), mean); + test.Printf(_L(" variance == %f\n"), variance); + + delete [] data; + } + +void BenchmarkReplacement() + { + test.Next(_L("Test uniform distribution")); + TUniformRandom rand1; + rand1.SetParams(100); + TestDistribution(rand1, 10000); + + test.Next(_L("Test normal distribution")); + TNormalRandom rand2; + rand2.SetParams(100, 25); + TestDistribution(rand2, 10000); + + ThrashTest(_L("Thrash test: single thread, normal random workload 1"), + 1, ETrue, EWorkloadNormalRandom1, (2 * gMaxCacheSize) / 3, 2 * gMaxCacheSize, 0); + + ThrashTest(_L("Thrash test: single thread, normal random workload 2"), + 1, ETrue, EWorkloadNormalRandom2, (2 * gMaxCacheSize) / 3, 2 * gMaxCacheSize, 0); + + ThrashTest(_L("Thrash test: single thread, uniform random workload"), + 1, ETrue, EWorkloadUniformRandom, (2 * gMinCacheSize) / 3, (3 * gMaxCacheSize) / 2, 0); } void TestThrashHal() @@ -369,27 +717,44 @@ test_Equal(KRequestPending, status.Int()); // stress system and check thrash level and notification - ThrashTest(1, ETrue, EWorkloadRandom, gMaxCacheSize * 2, gMaxCacheSize * 2 + 5, 0); + ThrashTest(_L("stress system"), + 1, ETrue, EWorkloadUniformRandom, gMaxCacheSize * 2, gMaxCacheSize * 2 + 5, 0); r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); test(r >= 0 && r <= 255); test.Printf(_L("Thrash level == %d\n"), r); test(r > 200); // should indicate thrashing - test_Equal(EChangesThrashLevel, status.Int()); - User::WaitForAnyRequest(); - // wait for system to calm down and check notification again - test_KErrNone(notifier.Logon(status)); - User::WaitForAnyRequest(); - test_Equal(EChangesThreadDeath, status.Int()); - - test_KErrNone(notifier.Logon(status)); + TBool gotThrashNotification = EFalse; + + // wait for EChangesThrashLevel notification + while(status.Int() != KRequestPending) + { + gotThrashNotification = (status.Int() & EChangesThrashLevel) != 0; + User::WaitForAnyRequest(); + test_KErrNone(notifier.Logon(status)); + User::After(1); + } + test(gotThrashNotification); + User::After(2000000); r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); test(r >= 0 && r <= 255); test.Printf(_L("Thrash level == %d\n"), r); test(r <= 10); // should indicate lightly loaded system - test_Equal(EChangesThrashLevel, status.Int()); + + // wait for EChangesThrashLevel notification + gotThrashNotification = EFalse; + while(status.Int() != KRequestPending) + { + gotThrashNotification = (status.Int() & EChangesThrashLevel) != 0; + User::WaitForAnyRequest(); + test_KErrNone(notifier.Logon(status)); + User::After(1); + } + test(gotThrashNotification); + test_KErrNone(notifier.LogonCancel()); User::WaitForAnyRequest(); + notifier.Close(); } void TestThrashHalNotSupported() @@ -398,45 +763,105 @@ test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, 0, 0)); } +_LIT(KUsageMessage, "usage: t_thrash [ test ] [ thrashing ] [ benchmarks ]\n"); + +enum TTestAction + { + EActionTest = 1 << 0, + EActionThrashing = 1 << 1, + EActionBenchmarks = 1 << 2 + }; + +void BadUsage() + { + test.Printf(KUsageMessage); + test(EFalse); + } + +TInt ParseCommandLine() + { + const TInt KMaxLineLength = 64; + + if (User::CommandLineLength() > KMaxLineLength) + BadUsage(); + TBuf buffer; + User::CommandLine(buffer); + + if (buffer == KNullDesC) + return EActionTest; + + TLex lex(buffer); + TInt result = 0; + while (!lex.Eos()) + { + TPtrC word = lex.NextToken(); + if (word == _L("test")) + result |= EActionTest; + else if (word == _L("thrashing")) + result |= EActionThrashing; + else if (word == _L("benchmarks")) + result |= EActionBenchmarks; + else + { + test.Printf(_L("bad token '%S'\n"), &word); + BadUsage(); + } + } + + return result; + } + TInt E32Main() { test.Title(); test.Start(_L("Test thrashing monitor")); + + test_KErrNone(InitBenchmarks()); + TInt actions = ParseCommandLine(); + test_KErrNone(GetGlobalPolicies()); TUint cacheOriginalMin = 0; TUint cacheOriginalMax = 0; - TUint cacheCurrentSize = 0; if (gDataPagingSupported) { - test.Next(_L("Thrash test: change maximum cache size to minimal")); - //store original values + test.Next(_L("Thrash test: change cache size to maximum 2Mb")); + TUint cacheCurrentSize = 0; DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize); - gMaxCacheSize = 256; - gMinCacheSize = 64; + gMinCacheSize = 512; + gMaxCacheSize = 520; test_KErrNone(DPTest::SetCacheSize(gMinCacheSize * gPageSize, gMaxCacheSize * gPageSize)); } + + if (actions & EActionTest) + { + TBool flexibleMemoryModel = (MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible; + if (flexibleMemoryModel) + TestThrashHal(); + else + TestThrashHalNotSupported(); + } - TBool flexibleMemoryModel = (MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible; - if (flexibleMemoryModel) - TestThrashHal(); - else - TestThrashHalNotSupported(); - - if (gDataPagingSupported && User::CommandLineLength() > 0) - { + if (actions & EActionThrashing) + { test.Next(_L("Extended thrashing tests")); TestThrashing(); } + + if (actions & EActionBenchmarks) + { + test.Next(_L("Benchmarking page replacement")); + BenchmarkReplacement(); + } + if (gDataPagingSupported) { - //Reset the cache size to normal test.Next(_L("Thrash test: Reset cache size to normal")); test_KErrNone(DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax)); } - + test.End(); return 0; }