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\mmu\t_mmcpaging.cpp sl@0: // Suite of tests specifically to test the demand paging subsystem when sl@0: // booted from MMC rather than NAND. sl@0: // 002 Read/Write and Page test sl@0: // sl@0: // sl@0: sl@0: //! @SYMTestCaseID KBASE-T_MMCPAGING-0331 sl@0: //! @SYMTestType UT sl@0: //! @SYMPREQ PREQ1110 sl@0: //! @SYMTestCaseDesc Demand Paging MMC Paging tests. sl@0: //! @SYMTestActions 001 Check that the rom is paged sl@0: //! @SYMTestExpectedResults All tests should pass. sl@0: //! @SYMTestPriority High sl@0: //! @SYMTestStatus Implemented sl@0: sl@0: #include sl@0: RTest test(_L("T_MMCPAGING")); sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #define __TEST_PAGING_MEDIA_DRIVER__ sl@0: #include "mmcdp.h" sl@0: sl@0: sl@0: sl@0: TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect. sl@0: TInt locDriveNumber; sl@0: sl@0: TInt MaxDeferLoops=40; // Parameter - Defer test, for how long? sl@0: TInt Maxloops=400; // Parameter - RW Soak, for how long? sl@0: TBool Forever=EFalse; // Parameter - RW Soak forever? sl@0: sl@0: TBool Testing=ETrue; // Used to communicate when testing has finished between threads. sl@0: sl@0: RFs TheFs; sl@0: TBusLocalDrive Drive; sl@0: TLocalDriveCapsV4 DriveCaps; sl@0: sl@0: TInt PagedTrashCount=0; // Incremented by threads, is used to detect preemption. sl@0: TInt GlobError=KErrNone; // To communicate an error between threads. sl@0: TBool CtrlIOSupported=ETrue; sl@0: sl@0: sl@0: //const TInt KDiskSectorShift = 9; sl@0: const TInt KBufSizeInBytes = (32 * 1024); sl@0: sl@0: LOCAL_D TBuf8 Buffer; sl@0: sl@0: sl@0: sl@0: // Three functions for the garbage test. sl@0: // CreateFile creates a file, and sets up the buffer for WriteNumber. sl@0: // After the code has finished writing numbers to the start, sl@0: // CloseAndDestroy cleans up. sl@0: sl@0: void CreateFile(RFile &aFile,const TDesC& aFileName) sl@0: { sl@0: TBuf<256> fileName; sl@0: fileName.Append((TChar)('A'+DriveNumber)); sl@0: fileName+=_L(":\\f32-tst\\"); sl@0: TInt r=TheFs.MkDirAll(fileName); sl@0: test(r==KErrNone || r== KErrAlreadyExists); sl@0: sl@0: fileName += aFileName; sl@0: sl@0: r=aFile.Replace(TheFs,fileName,EFileWrite); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName); sl@0: test(r==KErrNone); sl@0: Buffer.SetLength(4); sl@0: } sl@0: sl@0: void CloseAndDestroy(RFile &aFile) sl@0: { sl@0: TBuf<256> fileName; sl@0: aFile.FullName(fileName); sl@0: aFile.Close(); sl@0: TheFs.Delete(fileName); sl@0: } sl@0: sl@0: TInt WriteNumber(RFile &aFile) sl@0: { sl@0: TInt r; sl@0: Buffer[0]++; sl@0: r = aFile.Write(0,Buffer); sl@0: if (r==KErrNone) sl@0: return aFile.Flush(); sl@0: else sl@0: return r; sl@0: } sl@0: sl@0: sl@0: sl@0: // Finds the 1st MMC drive, or checks the specified one fits requirements sl@0: sl@0: static TInt FindFsMMCDrive() sl@0: { sl@0: TDriveList driveList; sl@0: TDriveInfo driveInfo; sl@0: TInt r=TheFs.DriveList(driveList); sl@0: test(r == KErrNone); sl@0: sl@0: TInt drvNum = DriveNumber; sl@0: if (drvNum<0) sl@0: drvNum = 0; sl@0: do sl@0: { sl@0: if(!driveList[drvNum]) sl@0: continue; //-- skip unexisting drive sl@0: sl@0: test(TheFs.Drive(driveInfo, drvNum) == KErrNone); sl@0: sl@0: if(driveInfo.iMediaAtt&KMediaAttPageable) sl@0: { sl@0: // Internal MMC ? sl@0: if (driveInfo.iType == EMediaHardDisk && sl@0: (driveInfo.iDriveAtt & KDriveAttInternal) && sl@0: (!(driveInfo.iDriveAtt & KDriveAttRemovable))) sl@0: return (drvNum); sl@0: } sl@0: } sl@0: while(DriveNumber<0 && ++drvNum KMaxTInt) ? KMaxTInt : (TInt) size; sl@0: sl@0: test.Printf(_L("Volume size %ld, free %ld maxFileSize %d file '%S'\n"), volInfo.iSize, volInfo.iFree, maxFileSize, &fileName); sl@0: sl@0: while (((totChangeCounthigh) sl@0: high=delta; sl@0: tot+=delta; sl@0: sl@0: oldPagedTrashCount=PagedTrashCount; sl@0: changeCount++; sl@0: } sl@0: if (pos % (writeSize) == 0) sl@0: { sl@0: sl@0: if ((blockNo%80==0) && (blockNo!=0)) sl@0: { sl@0: totChangeCount+=changeCount; sl@0: if(CtrlIOSupported) sl@0: { sl@0: test.Printf(_L("High%4d Avg%2d %d%% CC=%4d \n"), high, (TInt) (tot/cCount), (TInt)(changeCount*100)/cCount, totChangeCount); sl@0: sl@0: TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); sl@0: Drive.ControlIO(KMmcGetStats,statsBuf,0); sl@0: test.Printf(_L("PR %d(%d%%) NR %d\n"), stats.iReqPage, (TInt) ((stats.iReqPage*100)/cCount), stats.iReqNormal); sl@0: sl@0: test(stats.iReqPage>0); sl@0: reqPageCount+=stats.iReqPage; sl@0: reqNormalCount+=stats.iReqNormal; sl@0: } sl@0: sl@0: high=0; sl@0: sl@0: fullTot+=tot; sl@0: tot=0; sl@0: sl@0: fullcCount+=cCount; sl@0: cCount=0; sl@0: changeCount=0; sl@0: } sl@0: sl@0: } sl@0: test(r==KErrNone); sl@0: } sl@0: if(CtrlIOSupported) sl@0: { sl@0: test.Printf(_L("Totals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount); sl@0: test.Printf(_L("PR %d(%d%%) NR %d\n"), reqPageCount,(TInt) (reqPageCount*100/fullcCount), reqNormalCount ); sl@0: } sl@0: sl@0: // If totChangeCount does not change, mmc maybe busy waiting. sl@0: test(totChangeCount>0); sl@0: } sl@0: sl@0: sl@0: tempFile.Close(); sl@0: r = TheFs.Delete(fileName); sl@0: test (r == KErrNone); sl@0: sl@0: if (GlobError!=KErrNone) sl@0: { sl@0: test.Printf(_L("\nPageing failed with %x\n"), GlobError); sl@0: test(0); sl@0: } sl@0: else sl@0: test.Printf(_L("\ndone\n")); sl@0: } sl@0: sl@0: sl@0: TUint8 ReadByte(volatile TUint8* aPtr) sl@0: { sl@0: return *aPtr; sl@0: } sl@0: sl@0: #define READ(a) ReadByte((volatile TUint8*)(a)) sl@0: sl@0: TUint32 RandomNo =0; sl@0: sl@0: TUint32 Random() sl@0: { sl@0: RandomNo = RandomNo*69069+1; sl@0: return RandomNo; sl@0: } sl@0: sl@0: sl@0: // Many instances of this run while testWriteMain runs, sl@0: // to cause random background paging. sl@0: sl@0: LOCAL_C TInt RepeatedPagingThread(TAny* aUseTb) sl@0: { sl@0: // RTest test(_L("RepeatedPagingThread")); sl@0: TBool trashBurst = EFalse; sl@0: // This makes the paging system continually page stuff. sl@0: // get info about a paged ROM... sl@0: sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart; sl@0: TUint size = romHeader->iPageableRomSize; sl@0: TInt pageSize = 0; sl@0: PagedTrashCount=1; sl@0: sl@0: UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0); sl@0: RandomNo=123; sl@0: PagedTrashCount++; sl@0: sl@0: while (Testing) sl@0: { sl@0: TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); sl@0: if (Random() & 1) sl@0: User::AfterHighRes(500+Random() & 2047); sl@0: sl@0: if (r<0) sl@0: { sl@0: GlobError=r; sl@0: PagedTrashCount=99; sl@0: return (KErrNone); sl@0: } sl@0: if (trashBurst) sl@0: { sl@0: if ((Random() & 0xf) == 0xf) sl@0: trashBurst=EFalse; sl@0: PagedTrashCount++; sl@0: } sl@0: else sl@0: { sl@0: sl@0: for(TInt i=size/(pageSize); (i>0) && !trashBurst; --i) sl@0: { sl@0: READ(start+((TInt64(Random())*TInt64(size))>>32)); sl@0: if ((RandomNo & 0x3f) == 0x3f) sl@0: { sl@0: trashBurst= (TBool) aUseTb; sl@0: } sl@0: PagedTrashCount++; sl@0: if (RandomNo & 1) sl@0: User::AfterHighRes(500+Random() & 2047); sl@0: } sl@0: } sl@0: sl@0: } sl@0: return(KErrNone); sl@0: } sl@0: sl@0: sl@0: // This starts up multiple instances of repeatedPagingThread, and runs testWriteMain. sl@0: // After its done, it calls format, to clean up the drive. sl@0: sl@0: void TestMmcAccuratcy() sl@0: { sl@0: RThread thisThread; sl@0: const TInt KNoThreads=10; sl@0: TInt i; sl@0: test.Printf(_L("Reset stats\n")); sl@0: sl@0: i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetConcurrencyInfo,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom); sl@0: test(i==KErrNone || i==KErrNotSupported); sl@0: if(i==KErrNotSupported) sl@0: test.Printf(_L("Concurrency stats not supported on this build\n")); sl@0: i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetPagingBenchmark,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom); sl@0: test(i==KErrNone || i==KErrNotSupported); sl@0: if(i==KErrNotSupported) sl@0: test.Printf(_L("Benchmark stats not supported on this build\n")); sl@0: sl@0: if (Maxloops>0) sl@0: { sl@0: TRequestStatus stat[KNoThreads]; sl@0: // Start Read Test sl@0: RThread repeatedPagingThread[KNoThreads]; sl@0: sl@0: test.Next(_L("Read/Write and Page test")); sl@0: sl@0: for (i=0; iiPageableRomStart; sl@0: TUint size = romHeader->iPageableRomSize; sl@0: TUint8* addr=NULL; sl@0: TBool flush; sl@0: while (Testing) sl@0: { sl@0: // Wait on semaphore sl@0: PageSemaphore.Wait(); sl@0: flush = (PagesBeingPaged==0); sl@0: PagesBeingPaged++; sl@0: addr=start+((TInt64(Random())*TInt64(size))>>32); sl@0: PageDoneSemaphore.Signal(); sl@0: if (flush) sl@0: UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); sl@0: READ(addr); sl@0: PageMutex.Wait(); sl@0: PagesBeingPaged--; sl@0: PageMutex.Signal(); sl@0: } sl@0: return 0; sl@0: } sl@0: */ sl@0: sl@0: // ************************************************************************************ sl@0: sl@0: // sl@0: // The gubbins that starts all the tests sl@0: // sl@0: // ParseCommandLine reads the arguments and sets globals accordingly. sl@0: // sl@0: sl@0: void ParseCommandLine() sl@0: { sl@0: TBuf<32> args; sl@0: User::CommandLine(args); sl@0: TLex lex(args); sl@0: sl@0: FOREVER sl@0: { sl@0: sl@0: TPtrC token=lex.NextToken(); sl@0: if(token.Length()!=0) sl@0: { sl@0: if ((token.Length()==2) && (token[1]==':')) sl@0: DriveNumber=User::UpperCase(token[0])-'A'; sl@0: else if (token.Length()==1) sl@0: { sl@0: TChar driveLetter = User::UpperCase(token[0]); sl@0: if ((driveLetter>='A') && (driveLetter<='Z')) sl@0: DriveNumber=driveLetter - (TChar) 'A'; sl@0: else sl@0: test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token); sl@0: } sl@0: else if ((token==_L("help")) || (token==_L("-h")) || (token==_L("-?"))) sl@0: { sl@0: test.Printf(_L("\nUsage: t_mmcpaging [rwsoak ] [defer ]\n'-' indicated infinity.\n\n")); sl@0: test.Getch(); sl@0: Maxloops=0; sl@0: } sl@0: else if (token==_L("rwsoak")) sl@0: { sl@0: TPtrC val=lex.NextToken(); sl@0: TLex lexv(val); sl@0: TInt v; sl@0: sl@0: if (val==_L("-")) sl@0: Forever=ETrue; sl@0: else sl@0: if (lexv.Val(v)==KErrNone) sl@0: Maxloops=v; sl@0: else sl@0: test.Printf(_L("Bad value for rwsoak '%S' was ignored.\n"), &val); sl@0: } sl@0: else if (token==_L("defer")) sl@0: { sl@0: TPtrC val=lex.NextToken(); sl@0: TLex lexv(val); sl@0: TInt v; sl@0: sl@0: if (val==_L("-")) sl@0: MaxDeferLoops=KMaxTInt; sl@0: else sl@0: if (lexv.Val(v)==KErrNone) sl@0: MaxDeferLoops=v; sl@0: else sl@0: test.Printf(_L("Bad value for defer '%S' was ignored.\n"), &val); sl@0: } sl@0: else sl@0: test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token); sl@0: } sl@0: else sl@0: break; sl@0: sl@0: } sl@0: } sl@0: sl@0: // sl@0: // E32Main sl@0: // sl@0: sl@0: TInt E32Main() sl@0: { sl@0: TInt r; sl@0: test.Title(); sl@0: sl@0: test.Printf(_L("key\n---\n")); sl@0: test.Printf(_L("PR: Paging requests\n")); sl@0: test.Printf(_L("NR: Normal requests\n\n")); sl@0: sl@0: sl@0: test.Start(_L("Check that the rom is paged")); sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: if (romHeader->iPageableRomStart==NULL) sl@0: test.Printf(_L("Test ROM is not paged - test skipped!\r\n")); sl@0: else sl@0: { sl@0: ParseCommandLine(); sl@0: test(TheFs.Connect()==KErrNone); sl@0: sl@0: r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); sl@0: if(r<0) sl@0: { sl@0: test.Printf(_L("DemandPagingFlushPages Error = %d\n"),r); sl@0: test(0); sl@0: } sl@0: sl@0: DriveNumber = FindFsMMCDrive(); sl@0: sl@0: if(DriveNumber<0) sl@0: test.Printf(_L("MMC Flash not found - test skipped!\r\n")); sl@0: else sl@0: { sl@0: RFile file; sl@0: TBuf<256> fileName; sl@0: fileName.Append((TChar)('A'+DriveNumber)); sl@0: fileName+=_L(":\\f32-tst\\"); sl@0: TInt r=TheFs.MkDirAll(fileName); sl@0: test(r==KErrNone || r== KErrAlreadyExists); sl@0: fileName += _L("redglare.txt"); sl@0: r=file.Replace(TheFs,fileName,EFileWrite); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName); sl@0: test(r==KErrNone); sl@0: r=file.Write(_L8("The red glare of an ancient sun reflecting on the leaden surface of a primeval soup of decomposing matter")); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error %d: could not write to file\n"),r); sl@0: test(r==KErrNone); sl@0: sl@0: test(file.Flush() == KErrNone); sl@0: sl@0: SBlockMapInfo info; sl@0: TInt64 start=0; sl@0: r=file.BlockMap(info,start, -1,ETestDebug); sl@0: if (r!=KErrNone && r!=KErrCompletion) sl@0: test.Printf(_L("Error %d: could not obtain block map\n"),r); sl@0: test(r==KErrNone || r==KErrCompletion); sl@0: locDriveNumber=info.iLocalDriveNumber; sl@0: test.Printf(_L("Found drive: %c (MMC drive %d)\r\n"), DriveNumber+'A',locDriveNumber); sl@0: file.Close(); sl@0: sl@0: TDriveInfo driveInfo; sl@0: test(TheFs.Drive(driveInfo, DriveNumber) == KErrNone); sl@0: sl@0: // Connect to device driver sl@0: TBool changeFlag = EFalse; sl@0: r = Drive.Connect(locDriveNumber,changeFlag); sl@0: TPckg capsPack(DriveCaps); sl@0: Drive.Caps(capsPack); sl@0: test(r == KErrNone); sl@0: sl@0: SMmcStats stats; sl@0: TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); sl@0: r = Drive.ControlIO(KMmcGetStats,statsBuf,0); sl@0: sl@0: sl@0: if (r!=KErrNone) sl@0: { sl@0: test.Printf(_L("LocalDrive does not support testing IO Requests\n")); sl@0: CtrlIOSupported=EFalse; sl@0: } sl@0: test.Printf(_L("LocalDrive Connected\n")); sl@0: // sl@0: // Run tests sl@0: // sl@0: TestMmcAccuratcy(); sl@0: // sl@0: // Free device and end test program sl@0: // sl@0: Drive.Disconnect(); sl@0: } sl@0: } sl@0: sl@0: test.End(); sl@0: return 0; sl@0: } sl@0: