diff -r 000000000000 -r 96e5fb8b040d kerneltest/f32test/demandpaging/t_nandpaging.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/demandpaging/t_nandpaging.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,864 @@ +// 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: +// e32test\mmu\t_nandpaging.cpp +// Suite of tests specifically to test the demand paging subsystem when +// booted from NAND. +// 002 Read/Write and Page test +// 003 Defering test +// +// + +//! @SYMTestCaseID KBASE-T_NANDPAGING-0332 +//! @SYMTestType UT +//! @SYMPREQ PREQ1110 +//! @SYMTestCaseDesc Demand Paging Nand Paging tests. +//! @SYMTestActions 001 Check that the rom is paged +//! @SYMTestExpectedResults All tests should pass. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented + +#include +RTest test(_L("T_NANDPAGING")); + +#include +#include +#include +#include +#include "testdefs.h" +#include + + +TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect. +TInt locDriveNumber; + +TInt MaxDeferLoops=40; // Parameter - Defer test, for how long? +TInt Maxloops=400; // Parameter - RW Soak, for how long? +TBool Forever=EFalse; // Parameter - RW Soak forever? + +TBool Testing=ETrue; // Used to communicate when testing has finished between threads. + +RFs TheFs; +TBusLocalDrive Drive; +TLocalDriveCapsV4 DriveCaps; + +TInt PagedTrashCount=0; // Incremented by threads, is used to detect preemption. +TInt GlobError=KErrNone; // To communicate an error between threads. +TBool CtrlIoCollectGarbageSupported = ETrue; +TBool CtrlIoGetDeferStatsSupported = ETrue; + + +const TInt KDiskSectorShift=9; +const TInt KBufSizeInSectors=8; +const TInt KBufSizeInBytes=(KBufSizeInSectors< Buffer; + + + +// Three functions for the garbage test. +// CreateFile creates a file, and sets up the buffer for WriteNumber. +// After the code has finished writing numbers to the start, +// CloseAndDestroy cleans up. + +void CreateFile(RFile &aFile,const TDesC& aFileName) + { + TBuf<256> fileName; + fileName.Append((TChar)('A'+DriveNumber)); + fileName+=_L(":\\f32-tst\\"); + TInt r=TheFs.MkDirAll(fileName); + test(r==KErrNone || r== KErrAlreadyExists); + + fileName += aFileName; + + r=aFile.Replace(TheFs,fileName,EFileWrite); + if (r!=KErrNone) + test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName); + test(r==KErrNone); + Buffer.SetLength(4); + } + +void CloseAndDestroy(RFile &aFile) + { + TBuf<256> fileName; + aFile.FullName(fileName); + aFile.Close(); + TheFs.Delete(fileName); + } + +TInt WriteNumber(RFile &aFile) + { + TInt r; + Buffer[0]++; + r = aFile.Write(0,Buffer); + if (r==KErrNone) + return aFile.Flush(); + else + return r; + } + + + +// The r/w soaktest leaves the drive in a mess. +// Formatting is needed afterwards. + +void silentFormat(TInt driveNo) + { + TBuf<4> driveBuf=_L("?:\\"); + RFormat format; + TInt count; + + driveBuf[0] = (TText)(driveNo + 'A'); + + TInt r = format.Open(TheFs, driveBuf, EHighDensity, count); + test(r == KErrNone); + + while(count) + { + r=format.Next(count); + test(r == KErrNone); + } + + format.Close(); + } + +// Finds the 1st r/w NAND drive, or checks the specified one fits requirements + +static TInt FindFsNANDDrive() + { + TDriveList driveList; + TDriveInfo driveInfo; + TInt r=TheFs.DriveList(driveList); + test(r == KErrNone); + + for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum printBlockPos); + + // check for paging activity every 1MB + TInt64 checkChangePos = 1024*1024; + while (checkChangePos > size) + checkChangePos>>= 1; + + + SDeferStats stats; + TInt pageGarbageCount=0; + TInt pageOtherCount=0; + TInt normalGarbageCount=0; + TInt normalOtherCount=0; + + + Buffer.SetLength(2*readSize); + + TPtr8 subBuf1(&Buffer[0],readSize); + TPtrC8 subBuf2(&Buffer[readSize], readSize); + + test.Printf(_L("Page size = %d\n"), DriveCaps.iNumBytesMain); + test.Printf(_L("Erase block size = %d\n"), DriveCaps.iEraseBlockSize); + test.Printf(_L("Media size (rounded down) = %ld\n"), size); + + for(i = 0; ihigh) + high=delta; + tot+=delta; + + oldPagedTrashCount=PagedTrashCount; + changeCount++; + } + + if ((pos > 0) && (pos % checkChangePos) == 0) + { + totChangeCount+=changeCount; + if(CtrlIoGetDeferStatsSupported) + { + test.Printf(_L("\nHigh%4d Avg%2d %d%% CC=%4d \n"), high, (TInt) (tot/cCount), (TInt)(changeCount*100)/cCount, totChangeCount); + + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); + Drive.ControlIO(KNandGetDeferStats,statsBuf,0); + test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),stats.iPageGarbage, stats.iPageOther, (TInt) ((stats.iPageOther*100)/cCount), stats.iNormalGarbage, stats.iNormalOther); + + test(stats.iPageOther>0); + pageGarbageCount+=stats.iPageGarbage; + pageOtherCount+=stats.iPageOther; + normalGarbageCount+=stats.iNormalGarbage; + normalOtherCount+=stats.iNormalOther; + } + + high=0; + + fullTot+=tot; + tot=0; + + fullcCount+=cCount; + cCount=0; + changeCount=0; + } + + test(r==KErrNone); + } // for loop + + if (CtrlIoGetDeferStatsSupported) + { + test.Printf(_L("\nTotals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount); + test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),pageGarbageCount, pageOtherCount,(TInt) (pageOtherCount*100/fullcCount), normalGarbageCount, normalOtherCount ); + } + + // If totChangeCount does not change, nand maybe busy waiting. + test(totChangeCount>0); + } // while () + + if (GlobError!=KErrNone) + { + test.Printf(_L("\nPaging failed with %x\n"), GlobError); + test(0); + } + else + test.Printf(_L("\ndone\n")); + } + + +TUint8 ReadByte(volatile TUint8* aPtr) + { + return *aPtr; + } + +#define READ(a) ReadByte((volatile TUint8*)(a)) + +TUint32 RandomNo =0; + +TUint32 Random() + { + RandomNo = RandomNo*69069+1; + return RandomNo; + } + + +// Many instances of this run while testWriteMain runs, +// to cause random background paging. + +LOCAL_C TInt RepeatedPagingThread(TAny* aUseTb) + { + TBool trashBurst = EFalse; + // This makes the paging system continually page stuff. + // get info about a paged ROM... + + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); + TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart; + TUint size = romHeader->iPageableRomSize; + TInt pageSize = 0; + PagedTrashCount=1; + + UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0); + RandomNo=123; + PagedTrashCount++; + + while (Testing) + { + TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); + if (Random() & 1) + User::AfterHighRes(500+Random() & 2047); + + if (r<0) + { + GlobError=r; + PagedTrashCount=99; + return (KErrNone); + } + if (trashBurst) + { + if ((Random() & 0xf) == 0xf) + trashBurst=EFalse; + PagedTrashCount++; + } + else + { + + for(TInt i=size/(pageSize); (i>0) && !trashBurst; --i) + { + READ(start+((TInt64(Random())*TInt64(size))>>32)); + if ((RandomNo & 0x3f) == 0x3f) + { + trashBurst= (TBool) aUseTb; + } + PagedTrashCount++; + if (RandomNo & 1) + User::AfterHighRes(500+Random() & 2047); + } + } + + } + return(KErrNone); + } + + +// This starts up multiple instances of repeatedPagingThread, and runs testWriteMain. +// After its done, it calls format, to clean up the drive. + +void TestNandAccuratcy() + { + RThread thisThread; + const TInt KNoThreads=10; + TInt i; + test.Printf(_L("Reset concurrency stats\n")); + + i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetConcurrencyInfo,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom); + test(i==KErrNone || i==KErrNotSupported); + if(i==KErrNotSupported) + test.Printf(_L("Concurrency stats not supported on this build\n")); + i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetPagingBenchmark,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom); + test(i==KErrNone || i==KErrNotSupported); + if(i==KErrNotSupported) + test.Printf(_L("Benchmark stats not supported on this build\n")); + + if (Maxloops>0) + { + TRequestStatus stat[KNoThreads]; + // Start Read Test + RThread repeatedPagingThread[KNoThreads]; + + test.Next(_L("Read/Write and Page test")); + + Testing=ETrue; + for (i=0; iiPageableRomStart; + TUint size = romHeader->iPageableRomSize; + TUint8* addr=NULL; + TBool flush; + while (Testing) + { + PageSemaphore.Wait(); // wait for main thread to want paging. + flush = (PagesBeingPaged==0); + addr=start+((TInt64(Random())*TInt64(size))>>32); + PageDoneSemaphore.Signal(); // Acknolage request. + + PageMutex.Wait(); + PagesBeingPaged++; + PageMutex.Signal(); + + if (flush) + UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); + READ(addr); + + PageMutex.Wait(); + PagesBeingPaged--; + PageMutex.Signal(); + } + return 0; + } + + +// TestDefered causes garbage collection, and then triggers paging to happen, which should be defered. +// One would only expect one defered request, as the paging system is not reentrant, but this is checked. + +void TestDefered() + { + if (MaxDeferLoops==0) + { + test.Next(_L("Defering test - Skipped!")); + return; + } + + TInt timeout; + TInt writesNeeded=100; + TInt r = KErrNone; + RFile tempFile; + TInt i; + TInt ii; + TInt runs=0; + + SDeferStats stats; + TInt pageGarbageCount=0; + TInt pageOtherCount=0; + TInt normalGarbageCount=0; + TInt normalOtherCount=0; + + + // Set up thread sync + test(PageMutex.CreateLocal()==KErrNone); + test(PageSemaphore.CreateLocal(0)==KErrNone); + test(PageDoneSemaphore.CreateLocal(0)==KErrNone); + + + + const TInt KMaxPageThreads = 2; + UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); + // Set up threads + RThread pageThread[KMaxPageThreads]; + TRequestStatus stat[KMaxPageThreads]; + Testing=ETrue; + for (i=0; i0)); + // ie, while garbage collection hasn't happened, or timed out + { + timeout--; + pageGarbageCount=0; + pageOtherCount=0; + normalGarbageCount=0; + normalOtherCount=0; + + // Give somethng for garbage collector to collect + for (i=0; i0)); // If we get zero hits, maybe the page hasnt hit yet + } + while (stats.iPageGarbage>0); // Keep going until collection seems to have finished. + + // The paging system is not reentrant, so should never get more then one. + test(stats.iPageGarbage<2); + + test.Printf(_L("%d: PG %d PO %d NG %d NO %d\n"),ii,pageGarbageCount, pageOtherCount, normalGarbageCount, normalOtherCount ); + // if no collection, probebly didnt write enough to trigger it, so up the quantity. + if (pageGarbageCount==0) + { + writesNeeded+=writesNeeded/2; + test.Printf(_L("Writes needed = %d\n"),writesNeeded); + } + + } + while ((pageGarbageCount==0) && (timeout>0)); + test(timeout>0); + + } // end for MaxDeferLoops. + + // Clean up. . . . . + + Testing=EFalse; // Setting this causes the CausePage threads to exit. + + // Wait for threads to exit, signaling the semaphore in case they where waiting on it. + for (i=0; i args; + User::CommandLine(args); + TLex lex(args); + + FOREVER + { + + TPtrC token=lex.NextToken(); + if(token.Length()!=0) + { + if ((token.Length()==2) && (token[1]==':')) + DriveNumber=User::UpperCase(token[0])-'A'; + else if (token.Length()==1) + { + TChar driveLetter = User::UpperCase(token[0]); + if ((driveLetter>='A') && (driveLetter<='Z')) + DriveNumber=driveLetter - (TChar) 'A'; + else + test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token); + } + else if ((token==_L("help")) || (token==_L("-h")) || (token==_L("-?"))) + { + test.Printf(_L("\nUsage: t_nandpaging [rwsoak ] [defer ]\n'-' indicated infinity.\n\n")); + test.Getch(); + Maxloops=0; + } + else if (token==_L("rwsoak")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt v; + + if (val==_L("-")) + Forever=ETrue; + else + if (lexv.Val(v)==KErrNone) + Maxloops=v; + else + test.Printf(_L("Bad value for rwsoak '%S' was ignored.\n"), &val); + } + else if (token==_L("defer")) + { + TPtrC val=lex.NextToken(); + TLex lexv(val); + TInt v; + + if (val==_L("-")) + MaxDeferLoops=KMaxTInt; + else + if (lexv.Val(v)==KErrNone) + MaxDeferLoops=v; + else + test.Printf(_L("Bad value for defer '%S' was ignored.\n"), &val); + } + else + test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token); + } + else + break; + + } + } + +// +// E32Main +// + +TInt E32Main() + { + TInt r; + test.Title(); + + test.Printf(_L("key\n---\n")); + test.Printf(_L("PG: Paging requests defered due to Garbage\n")); + test.Printf(_L("PO: Paging requests defered due to other operations\n")); + test.Printf(_L("NG: Normal requests defered due to Garbage\n")); + test.Printf(_L("NO: Normal requests defered due to other operations\n\n")); + + + test.Start(_L("Check that the rom is paged")); + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); + + if (romHeader->iPageableRomStart==NULL) + test.Printf(_L("Test ROM is not paged - test skipped!\r\n")); + else + { + ParseCommandLine(); + test(TheFs.Connect()==KErrNone); + + r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); + if(r<0) + { + test.Printf(_L("DemandPagingFlushPages Error = %d\n"),r); + test(0); + } + + DriveNumber = FindFsNANDDrive(); + + if(DriveNumber<0) + test.Printf(_L("NAND Flash not found - test skipped!\r\n")); + else + { + RFile file; + TBuf<256> fileName; + fileName.Append((TChar)('A'+DriveNumber)); + fileName+=_L(":\\f32-tst\\"); + TInt r=TheFs.MkDirAll(fileName); + test(r==KErrNone || r== KErrAlreadyExists); + fileName += _L("annoyingflies.txt"); + r=file.Replace(TheFs,fileName,EFileWrite); + if (r!=KErrNone) + test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName); + test(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) + test.Printf(_L("Error %d: could not write to file\n"),r); + test(r==KErrNone); + + test(file.Flush() == KErrNone); + + SBlockMapInfo info; + TInt64 start=0; + r=file.BlockMap(info,start, -1,ETestDebug); + if (r!=KErrNone && r!=KErrCompletion) + test.Printf(_L("Error %d: could not obtain block map\n"),r); + test(r==KErrNone || r==KErrCompletion); + locDriveNumber=info.iLocalDriveNumber; + test.Printf(_L("Found drive: %c (NAND drive %d)\r\n"), DriveNumber+'A',locDriveNumber); + file.Close(); + + // Connect to device driver + TBool changeFlag = EFalse; + r = Drive.Connect(locDriveNumber,changeFlag); + TPckg capsPack(DriveCaps); + Drive.Caps(capsPack); + test(r == KErrNone); + + r = Drive.ControlIO(KNandCollectGarbage,NULL,NULL); + if (r!=KErrNone) + { + test.Printf(_L("LocalDrive does not support the KNandCollectGarbage ControlIO request\n")); + CtrlIoCollectGarbageSupported = EFalse; + } + + SDeferStats stats; + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats)); + r = Drive.ControlIO(KNandGetDeferStats,statsBuf,0); + if (r == KErrNone) + { + if (stats.iSynchronousMediaDriver) + { + test.Printf(_L("Media drive is synchronous - test skipped!\r\n")); + test.End(); + return 0; + } + } + else + { + test.Printf(_L("LocalDrive does not support the KNandGetDeferStats ControlIO request\n")); + CtrlIoGetDeferStatsSupported = EFalse; + } + + + test.Printf(_L("LocalDrive Connected\n")); + // + // Run tests + // + TestNandAccuratcy(); + if(CtrlIoCollectGarbageSupported && CtrlIoGetDeferStatsSupported) + TestDefered(); + // + // Free device and end test program + // + Drive.Disconnect(); + } + } + + test.End(); + return 0; + } + +