sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test/defrag/perf/t_perf.cpp sl@0: // t_pagemove loads and opens the logical device driver ("D_PAGEMOVE.LDD"). sl@0: // Following this, it requests that the driver attempt to move various kinds of pages sl@0: // directly amd notes time taken for each of the moves. sl@0: // Platforms/Drives/Compatibility: sl@0: // Hardware only. No defrag support on emulator. sl@0: // 2 - Test the performance of moving user chunk pages sl@0: // 3 - Test the performance of moving dll pages sl@0: // 4 - Test the performance of moving kernel stack pages sl@0: // sl@0: // sl@0: sl@0: //! @SYMTestCaseID KBASE-T_DEFRAGPERF-0601 sl@0: //! @SYMTestType CT sl@0: //! @SYMPREQ PREQ308 sl@0: //! @SYMTestCaseDesc Testing performace of page moving sl@0: //! @SYMTestActions 1 - Test the performance of moving code chunk pages sl@0: //! @SYMTestExpectedResults Finishes if the system behaves as expected, panics otherwise sl@0: //! @SYMTestPriority High sl@0: //! @SYMTestStatus Implemented sl@0: //-------------------------------------------------------------------------------------------------- sl@0: #define __E32TEST_EXTENSION__ sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "..\d_pagemove.h" sl@0: #include "..\..\mmu\mmudetect.h" sl@0: #include "t_perf.h" sl@0: sl@0: sl@0: LOCAL_D RTest test(_L("T_DEFRAGPERF")); sl@0: sl@0: const TPtrC KLddFileName=_L("D_PAGEMOVE.LDD"); sl@0: sl@0: const TUint KRepetitions=50; sl@0: const TUint KPageMoves = 2000; // default to moving a page 2000 times sl@0: sl@0: sl@0: TInt gPageSize; sl@0: sl@0: #define DEFRAG_CHUNK_MAX (4 * 1024 * 1024) sl@0: #define DEFRAG_CHUNK_MIN (1 * 1024 * 1024) sl@0: sl@0: #define MIN_PROCS 10 sl@0: #define MAX_PROCS 50 sl@0: #define PROC_INCREMENTS 10 sl@0: sl@0: _LIT(BaseFileName, "t_defragtestperf"); sl@0: _LIT(BaseFileNameExt, ".exe"); sl@0: sl@0: LOCAL_C void TestUserDataMove(RPageMove& pagemove) sl@0: { sl@0: RChunk chunk; sl@0: TInt size; sl@0: TInt r = KErrGeneral; sl@0: sl@0: DefragLatency timer; sl@0: timer.CalibrateTimer(test); sl@0: sl@0: size = DEFRAG_CHUNK_MAX; sl@0: sl@0: while (size > DEFRAG_CHUNK_MIN) sl@0: { sl@0: /* Create a local chunk */ sl@0: r = chunk.CreateLocal(size,size); sl@0: if (r == KErrNone) sl@0: { sl@0: TEST_PRINTF(_L("Created %dMB chunk\n"), size/(1024 * 1024)); sl@0: break; sl@0: } sl@0: size = size / 2; sl@0: } sl@0: sl@0: test(r == KErrNone); sl@0: sl@0: /* Initialise the Chunk */ sl@0: TUint8* base = (TUint8 *)chunk.Base(); sl@0: for (TUint i = 0; i < size/sizeof(*base); i++) sl@0: { sl@0: base[i] = i; sl@0: } sl@0: sl@0: sl@0: TEST_PRINTF(_L("Starting to move chunk pages (%x %d) ...\n"), chunk.Base(), size); sl@0: TUint j = 0; sl@0: for (; j < KRepetitions; j++) sl@0: { sl@0: TInt size2 = size; sl@0: base = (TUint8 *)chunk.Base(); sl@0: timer.StartTimer(); sl@0: while (size2) sl@0: { sl@0: test_KErrNone(pagemove.TryMovingUserPage(base)); sl@0: base += gPageSize; sl@0: size2 -= gPageSize; sl@0: } sl@0: sl@0: test(timer.StopTimer(test) > 0); sl@0: } sl@0: sl@0: DTime_t average, max, min, delay; sl@0: TEST_PRINTF(_L("Finished moving chunk pages\n")); sl@0: average = timer.GetResult(max, min, delay); sl@0: test.Printf(_L("Fast counter ticks to move %d chunk pages: Av %d Min %d Max %d (Overhead %d)\n"), size/gPageSize, average, min, max, delay); sl@0: test.Printf(_L("Average of %d ticks to move one page\n\n"), average / (size/gPageSize)); sl@0: sl@0: base = (TUint8 *)chunk.Base(); sl@0: for (TUint i = 0; i < size/sizeof(*base); i++) sl@0: { sl@0: test_Equal((TUint8)i, base[i]); sl@0: } sl@0: } sl@0: sl@0: TInt CreateProc(RProcess& aProcess, TInt aIndex) sl@0: { sl@0: TFileName filename; sl@0: TRequestStatus status; sl@0: TBuf<64> command; sl@0: sl@0: filename.Format(_L("%S%S"), &BaseFileName, &BaseFileNameExt); sl@0: TInt r=aProcess.Create(filename, command); sl@0: sl@0: if (r!=KErrNone) sl@0: { sl@0: test.Printf(_L("Process %d could not be loaded!\n"), aIndex); sl@0: return r; sl@0: } sl@0: sl@0: aProcess.Rendezvous(status); sl@0: aProcess.Resume(); sl@0: User::WaitForRequest(status); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void KillAllProcs(RProcess *aProcess, TInt aNum, TInt aError) sl@0: { sl@0: TInt i; sl@0: for (i = 0; i < aNum; i++) sl@0: { sl@0: aProcess[i].Kill(aError); sl@0: } sl@0: } sl@0: sl@0: TInt TestDLL(int aNumProcess, RPageMove& aPageMove) sl@0: { sl@0: RProcess *process; sl@0: TInt retVal; sl@0: sl@0: process = new RProcess[aNumProcess]; sl@0: sl@0: if (process == NULL) sl@0: return KErrGeneral; sl@0: sl@0: TEST_PRINTF(_L("Starting %d processes\n"), aNumProcess); sl@0: for (TInt i = 0; i < aNumProcess; i++) sl@0: { sl@0: retVal = CreateProc(process[i], i); sl@0: if (retVal != KErrNone) sl@0: { sl@0: // More Cleanup ? sl@0: KillAllProcs(process, i, KErrNone); sl@0: delete[] process; sl@0: return retVal; sl@0: } sl@0: } sl@0: sl@0: /* Now Map the DLL to this process and Run the tests */ sl@0: DllDefrag dll; sl@0: TEST_PRINTF(_L("Main Proc Loading The DLL ... \n")); sl@0: retVal = dll.LoadTheLib(0, test); sl@0: sl@0: if (retVal != KErrNone) sl@0: { sl@0: KillAllProcs(process, aNumProcess, retVal); sl@0: test.Printf(_L("Error (%d) Loading The DLLs!\n"), retVal); sl@0: delete[] process; sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: retVal = dll.TestDLLPerformance(0, aPageMove, test); sl@0: KillAllProcs(process, aNumProcess, KErrNone); sl@0: delete[] process; sl@0: sl@0: return retVal; sl@0: } sl@0: sl@0: /* sl@0: * Is this portable .. Hell No, so dont ask. sl@0: */ sl@0: #define isNum(a) ((a) >= '0' && (a) <= '9') sl@0: sl@0: TInt atoi(const TBuf<64>& buf, TInt pos) sl@0: { sl@0: TInt i = pos; sl@0: TInt num = 0; sl@0: TInt len = User::CommandLineLength(); sl@0: while(i < len) sl@0: { sl@0: TInt8 ch = buf[i++]; sl@0: if (!isNum(ch)) sl@0: { sl@0: test.Printf(_L("Invalid Argument!\n")); sl@0: return KErrGeneral; sl@0: } sl@0: num = (num * 10) + (ch - '0'); sl@0: } sl@0: return num; sl@0: } sl@0: sl@0: void TestCodeChunkMoving(RPageMove aPageMove) sl@0: { sl@0: _LIT(ELOCL_DEFAULT, ""); sl@0: _LIT(ELOCLUS, "T_LOCLUS_RAM"); sl@0: sl@0: // Change locale and move the locale page repeatedly sl@0: // On multiple memmodel this is the easiest way to move CodeChunk pages. sl@0: sl@0: sl@0: // Setup the RAM loaded US Locale DLL sl@0: test_KErrNone(UserSvr::ChangeLocale(ELOCLUS)); sl@0: TLocale locale; sl@0: locale.Refresh(); sl@0: sl@0: sl@0: // Now get a pointer to some data in the DLL. This will be used to move a sl@0: // page from the dll sl@0: SLocaleLanguage localeLanguage; sl@0: TPckg localeLanguageBuf(localeLanguage); sl@0: TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf); sl@0: test_KErrNone(r); sl@0: TAny* localeAddr = (TAny *) localeLanguage.iDateSuffixTable; sl@0: test(localeAddr != NULL); sl@0: sl@0: sl@0: // Now we have a RAM loaded locale page determine the performance sl@0: TEST_PRINTF(_L("Start moving a RAM loaded locale page\n")); sl@0: // Setup the timer sl@0: DefragLatency timer; sl@0: timer.CalibrateTimer(test); sl@0: TUint reps = 0; sl@0: for (; reps < KRepetitions; reps++) sl@0: { sl@0: timer.StartTimer(); sl@0: TUint i = 0; sl@0: for (; i < KPageMoves; i++) sl@0: { sl@0: test_KErrNone(aPageMove.TryMovingLocaleDll(localeAddr)); sl@0: } sl@0: test_Compare(timer.StopTimer(test), >, 0); sl@0: } sl@0: DTime_t max, min, delay; sl@0: TUint average = timer.GetResult(max, min, delay); sl@0: test.Printf(_L("Fast counter ticks to move code chunk page %d times: Av %d Min %d Max %d (Overhead %d)\n"), KPageMoves, average, min, max, delay); sl@0: test.Printf(_L("Average of %d ticks to move one page\n\n"), average/ KPageMoves); sl@0: sl@0: sl@0: // Reset the Locale to the default sl@0: r=UserSvr::ChangeLocale(ELOCL_DEFAULT); sl@0: test(r==KErrNone); sl@0: locale.Refresh(); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: TInt procs = 1; sl@0: _LIT(KStart,"-procs="); sl@0: const TInt offset = KStart().Length(); sl@0: sl@0: TBuf<64> cmd; sl@0: User::CommandLine(cmd); sl@0: sl@0: if (!HaveMMU()) sl@0: { sl@0: test.Printf(_L("This test requires an MMU\n")); sl@0: return KErrNone; sl@0: } sl@0: test.Start(_L("Load test LDD")); sl@0: TInt r=User::LoadLogicalDevice(KLddFileName); sl@0: test(r==KErrNone || r==KErrAlreadyExists); sl@0: sl@0: r=UserHal::PageSizeInBytes(gPageSize); sl@0: test_KErrNone(r); sl@0: sl@0: RPageMove pagemove; sl@0: test.Next(_L("Open test LDD")); sl@0: r=pagemove.Open(); sl@0: test_KErrNone(r); sl@0: sl@0: DefragLatency timer; sl@0: timer.CalibrateTimer(test); sl@0: test.Printf(_L("\nFast Counter Frequency = %dHz \n\n"), timer.iFastCounterFreq); sl@0: sl@0: sl@0: test.Next(_L("Test performance of moving code chunk pages")); sl@0: TestCodeChunkMoving(pagemove); sl@0: sl@0: /* sl@0: * Test User Data. sl@0: * Create a large chunk ~ 4MB (> L2 Cache) and move pages from that chunk sl@0: */ sl@0: test.Next(_L("Test performance of moving user chunk pages")); sl@0: TestUserDataMove(pagemove); sl@0: sl@0: /* Test DLL Move */ sl@0: test.Next(_L("Test performance of moving dll pages")); sl@0: TInt pos = cmd.FindF(KStart); sl@0: if (pos >= 0) sl@0: { sl@0: pos += offset; sl@0: procs = atoi(cmd, pos); sl@0: } sl@0: sl@0: if (procs < MIN_PROCS) sl@0: procs = MIN_PROCS; sl@0: else if (procs > MAX_PROCS) sl@0: procs = MAX_PROCS; sl@0: sl@0: for (TInt i = 1; ; ) sl@0: { sl@0: test.Printf(_L("Testing with %d Processes mapping a DLL\n"), i); sl@0: TestDLL(i, pagemove); sl@0: sl@0: if (i >= procs) sl@0: break; sl@0: sl@0: if (i + PROC_INCREMENTS >= procs) sl@0: i = procs; sl@0: else sl@0: i += PROC_INCREMENTS; sl@0: } sl@0: sl@0: if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible) sl@0: { sl@0: test.Next(_L("Test performance of moving kernel stack pages")); sl@0: r = pagemove.TestKernelDataMovePerformance(); sl@0: test_KErrNone(r); sl@0: } sl@0: sl@0: test.Next(_L("Close test LDD")); sl@0: sl@0: pagemove.Close(); sl@0: User::FreeLogicalDevice(KLddFileName); sl@0: test.End(); sl@0: return(KErrNone); sl@0: }