kerneltest/f32test/demandpaging/t_nandpaging.cpp
changeset 0 a41df078684a
child 6 0173bcd7697c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\mmu\t_nandpaging.cpp
       
    15 // Suite of tests specifically to test the demand paging subsystem when
       
    16 // booted from NAND.
       
    17 // 002 Read/Write and Page test
       
    18 // 003 Defering test
       
    19 // 
       
    20 //
       
    21 
       
    22 //! @SYMTestCaseID			KBASE-T_NANDPAGING-0332
       
    23 //! @SYMTestType			UT
       
    24 //! @SYMPREQ				PREQ1110
       
    25 //! @SYMTestCaseDesc		Demand Paging Nand Paging tests.
       
    26 //! @SYMTestActions			001 Check that the rom is paged
       
    27 //! @SYMTestExpectedResults All tests should pass.
       
    28 //! @SYMTestPriority        High
       
    29 //! @SYMTestStatus          Implemented
       
    30 
       
    31 #include <e32test.h>
       
    32 RTest test(_L("T_NANDPAGING"));
       
    33 
       
    34 #include <e32rom.h>
       
    35 #include <u32hal.h>
       
    36 #include <f32file.h>
       
    37 #include <f32dbg.h>
       
    38 #include "testdefs.h"
       
    39 #include <hal.h>
       
    40 
       
    41 
       
    42 TInt DriveNumber=-1;   // Parameter - Which drive?  -1 = autodetect.
       
    43 TInt locDriveNumber;
       
    44 
       
    45 TInt MaxDeferLoops=40; // Parameter - Defer test, for how long?
       
    46 TInt Maxloops=400;	   // Parameter - RW Soak, for how long?
       
    47 TBool Forever=EFalse;  // Parameter - RW Soak forever?
       
    48 
       
    49 TBool Testing=ETrue;	// Used to communicate when testing has finished between threads.
       
    50 
       
    51 RFs TheFs;
       
    52 TBusLocalDrive Drive;
       
    53 TLocalDriveCapsV4 DriveCaps;
       
    54 
       
    55 TInt PagedTrashCount=0; // Incremented by threads, is used to detect preemption.
       
    56 TInt GlobError=KErrNone; // To communicate an error between threads.
       
    57 TBool CtrlIoCollectGarbageSupported = ETrue;
       
    58 TBool CtrlIoGetDeferStatsSupported = ETrue;
       
    59 
       
    60 
       
    61 const TInt KDiskSectorShift=9;
       
    62 const TInt KBufSizeInSectors=8;
       
    63 const TInt KBufSizeInBytes=(KBufSizeInSectors<<KDiskSectorShift)*40;
       
    64 
       
    65 LOCAL_D TBuf8<KBufSizeInBytes> Buffer;
       
    66 
       
    67 
       
    68 
       
    69 // Three functions for the garbage test.
       
    70 // CreateFile creates a file, and sets up the buffer for WriteNumber.
       
    71 // After the code has finished writing numbers to the start,
       
    72 // CloseAndDestroy cleans up.
       
    73 
       
    74 void CreateFile(RFile &aFile,const TDesC& aFileName)
       
    75 	{
       
    76 	TBuf<256> fileName;	
       
    77 	fileName.Append((TChar)('A'+DriveNumber));
       
    78 	fileName+=_L(":\\f32-tst\\");
       
    79 	TInt r=TheFs.MkDirAll(fileName);
       
    80 	test(r==KErrNone || r== KErrAlreadyExists);
       
    81 
       
    82 	fileName += aFileName;	
       
    83 
       
    84 	r=aFile.Replace(TheFs,fileName,EFileWrite);
       
    85 	if (r!=KErrNone)
       
    86 		test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
       
    87 	test(r==KErrNone);	
       
    88 	Buffer.SetLength(4);
       
    89 	}
       
    90 	
       
    91 void CloseAndDestroy(RFile &aFile)
       
    92 	{
       
    93 	TBuf<256> fileName;	
       
    94 	aFile.FullName(fileName);
       
    95 	aFile.Close();
       
    96 	TheFs.Delete(fileName);
       
    97 	}
       
    98 
       
    99 TInt WriteNumber(RFile &aFile)
       
   100 	{
       
   101 	TInt r;
       
   102 	Buffer[0]++;
       
   103 	r = aFile.Write(0,Buffer);
       
   104 	if (r==KErrNone)
       
   105 		return aFile.Flush();
       
   106 	else
       
   107 		return r; 
       
   108 	}
       
   109 
       
   110 
       
   111 
       
   112 // The r/w soaktest leaves the drive in a mess.
       
   113 // Formatting is needed afterwards.
       
   114 
       
   115 void silentFormat(TInt driveNo) 
       
   116 	{    
       
   117     TBuf<4> driveBuf=_L("?:\\");
       
   118     RFormat format;
       
   119     TInt    count;
       
   120     
       
   121 	driveBuf[0] = (TText)(driveNo + 'A');
       
   122     
       
   123     TInt r = format.Open(TheFs, driveBuf, EHighDensity, count);
       
   124     test(r == KErrNone);
       
   125     
       
   126     while(count) 
       
   127 		{
       
   128         r=format.Next(count);
       
   129         test(r == KErrNone);
       
   130 		}
       
   131     
       
   132     format.Close();
       
   133 	}
       
   134 
       
   135 // Finds the 1st r/w NAND drive, or checks the specified one fits requirements  
       
   136 
       
   137 static TInt FindFsNANDDrive()
       
   138 	{
       
   139 	TDriveList driveList;
       
   140 	TDriveInfo driveInfo;
       
   141 	TInt r=TheFs.DriveList(driveList);
       
   142     test(r == KErrNone);
       
   143 	
       
   144 	for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum<KMaxDrives; ++drvNum)
       
   145 		{
       
   146 	    if(!driveList[drvNum])
       
   147 	        continue;   //-- skip unexisting drive
       
   148 
       
   149 	    test(TheFs.Drive(driveInfo, drvNum) == KErrNone);
       
   150 
       
   151 		if ((driveInfo.iMediaAtt&KMediaAttPageable) &&
       
   152 			(driveInfo.iType == EMediaNANDFlash) && 
       
   153 			(driveInfo.iDriveAtt & KDriveAttInternal))
       
   154 			{
       
   155 			TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected;		// skip ROFS partitions
       
   156 			if(!readOnly)
       
   157 				{
       
   158 				if ((drvNum==DriveNumber) || (DriveNumber<0))		// only test if running on this drive
       
   159 					{
       
   160 					return (drvNum);
       
   161 					}
       
   162 				}
       
   163 			}
       
   164 		}
       
   165 	return (-1);
       
   166 	}
       
   167 
       
   168 
       
   169 //
       
   170 // Writes to main area for the entire disk and reads back to verify.
       
   171 // The function is called from TestNandAccuratcy, which will have also
       
   172 // started the background RepeatedPagingThread
       
   173 //
       
   174 void testWriteMain()
       
   175 	{
       
   176 	TInt i;
       
   177 	TInt r;
       
   178 	TInt changeCount=0;
       
   179 	TInt totChangeCount=0;
       
   180 	TInt cCount=0;
       
   181 	TInt fullcCount=0;
       
   182 	TInt oldPagedTrashCount=0;
       
   183 	TInt delta=0;
       
   184 	TInt high=0;
       
   185 	TInt tot=0;
       
   186 	TInt fullTot=0;
       
   187 	TInt blockNo;
       
   188 
       
   189 	// read size is 64K
       
   190 	TInt readSize = (64*1024);	
       
   191 	TInt64 size = DriveCaps.iSize - (DriveCaps.iSize % readSize);
       
   192 	
       
   193 	// print position every 128K
       
   194 	TInt64 printBlockPos = 128 * 1024;
       
   195 	test (size > printBlockPos);
       
   196 
       
   197 	// check for paging activity every 1MB
       
   198 	TInt64 checkChangePos = 1024*1024;
       
   199 	while (checkChangePos > size)
       
   200 		checkChangePos>>= 1;
       
   201 
       
   202 	
       
   203 	SDeferStats stats;
       
   204 	TInt pageGarbageCount=0;
       
   205 	TInt pageOtherCount=0;	
       
   206 	TInt normalGarbageCount=0;
       
   207 	TInt normalOtherCount=0;
       
   208 	
       
   209 	
       
   210 	Buffer.SetLength(2*readSize);
       
   211 
       
   212 	TPtr8 subBuf1(&Buffer[0],readSize);
       
   213 	TPtrC8 subBuf2(&Buffer[readSize], readSize);
       
   214 	
       
   215 	test.Printf(_L("Page size = %d\n"), DriveCaps.iNumBytesMain);
       
   216 	test.Printf(_L("Erase block size = %d\n"), DriveCaps.iEraseBlockSize);
       
   217 	test.Printf(_L("Media size (rounded down) = %ld\n"), size);
       
   218 
       
   219 	for(i = 0; i<readSize; i++)
       
   220 		Buffer[readSize+i] = (char)(i%100);
       
   221 
       
   222 	// Zero Stats
       
   223 	if(CtrlIoGetDeferStatsSupported)
       
   224 		{
       
   225 		TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
       
   226  		test(Drive.ControlIO(KNandGetDeferStats,statsBuf,0)==KErrNone);
       
   227 		}
       
   228 
       
   229 
       
   230 	while (((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone))
       
   231 		{
       
   232 		for(TInt64 pos=0;
       
   233 			(pos<size) && ((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone);
       
   234 			pos+=(TUint)(readSize))
       
   235 			{
       
   236 			blockNo=I64LOW(pos / DriveCaps.iEraseBlockSize);
       
   237 			if ((pos % printBlockPos) == 0)
       
   238 				test.Printf(_L("Block %d at pos %lu \r"), blockNo, pos);
       
   239 
       
   240 			//write the pattern
       
   241 			r = Drive.Write(pos,subBuf2);
       
   242 			test(r==KErrNone);
       
   243 
       
   244 			//read back and verify
       
   245 			r = Drive.Read(pos,readSize,subBuf1);
       
   246 			test(r==KErrNone);
       
   247 
       
   248 			for(i=0;i<readSize;i++)
       
   249 				if(Buffer[i]!=Buffer[readSize+i])
       
   250 					{
       
   251 					r = KErrCorrupt;
       
   252 					break;
       
   253 					}
       
   254 			delta = PagedTrashCount-oldPagedTrashCount;
       
   255 			cCount++;
       
   256 			if (delta)
       
   257 				{	
       
   258 				if (delta>high)
       
   259 					high=delta;
       
   260 				tot+=delta;
       
   261 				
       
   262 				oldPagedTrashCount=PagedTrashCount;
       
   263 				changeCount++;
       
   264 				}
       
   265 
       
   266 			if ((pos > 0) && (pos % checkChangePos) == 0)
       
   267 				{
       
   268 				totChangeCount+=changeCount;
       
   269 				if(CtrlIoGetDeferStatsSupported)
       
   270 					{
       
   271 					test.Printf(_L("\nHigh%4d Avg%2d %d%% CC=%4d \n"), high, (TInt) (tot/cCount), (TInt)(changeCount*100)/cCount, totChangeCount);
       
   272 				
       
   273 					TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
       
   274 					Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
       
   275 					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);
       
   276 
       
   277 					test(stats.iPageOther>0);
       
   278 				 	pageGarbageCount+=stats.iPageGarbage; 
       
   279 				 	pageOtherCount+=stats.iPageOther;			 	
       
   280 				 	normalGarbageCount+=stats.iNormalGarbage; 
       
   281 				 	normalOtherCount+=stats.iNormalOther;			 	
       
   282 					}
       
   283 
       
   284 				high=0;
       
   285 				
       
   286 				fullTot+=tot;
       
   287 				tot=0;
       
   288 				
       
   289 				fullcCount+=cCount;
       
   290 				cCount=0;
       
   291 				changeCount=0;
       
   292 				}
       
   293 
       
   294 			test(r==KErrNone);
       
   295 			}	// for loop
       
   296 
       
   297 		if (CtrlIoGetDeferStatsSupported)
       
   298 			{
       
   299 			test.Printf(_L("\nTotals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount);
       
   300 			test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),pageGarbageCount,  pageOtherCount,(TInt) (pageOtherCount*100/fullcCount), normalGarbageCount,  normalOtherCount );
       
   301 			}
       
   302 
       
   303 		// If totChangeCount does not change, nand maybe busy waiting.
       
   304 		test(totChangeCount>0);
       
   305 		}	// while ()
       
   306 
       
   307 	if (GlobError!=KErrNone)
       
   308 		{
       
   309 		test.Printf(_L("\nPaging failed with %x\n"), GlobError);
       
   310 		test(0);
       
   311 		}
       
   312 	else
       
   313 		test.Printf(_L("\ndone\n"));
       
   314 	}
       
   315 
       
   316 
       
   317 TUint8 ReadByte(volatile TUint8* aPtr)
       
   318 	{
       
   319 	return *aPtr;
       
   320 	}
       
   321 
       
   322 #define READ(a) ReadByte((volatile TUint8*)(a))
       
   323 
       
   324 TUint32 RandomNo =0;
       
   325 
       
   326 TUint32 Random()
       
   327 	{
       
   328 	RandomNo = RandomNo*69069+1;
       
   329 	return RandomNo;
       
   330 	}
       
   331 
       
   332 
       
   333 // Many instances of this run while testWriteMain runs,
       
   334 // to cause random background paging.
       
   335 
       
   336 LOCAL_C TInt RepeatedPagingThread(TAny* aUseTb)
       
   337 	{
       
   338 	TBool trashBurst = EFalse;
       
   339 	// This makes the paging system continually page stuff.
       
   340 	// get info about a paged ROM...
       
   341 	
       
   342 	TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
       
   343 	TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
       
   344 	TUint size = romHeader->iPageableRomSize;
       
   345 	TInt pageSize = 0;
       
   346 	PagedTrashCount=1;
       
   347 
       
   348 	UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0);
       
   349 	RandomNo=123;
       
   350 	PagedTrashCount++;
       
   351 
       
   352 	while (Testing)
       
   353 		{
       
   354 		TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
       
   355 		if (Random() & 1)
       
   356 			User::AfterHighRes(500+Random() & 2047);
       
   357 
       
   358 		if (r<0)
       
   359 			{
       
   360 			GlobError=r;
       
   361 			PagedTrashCount=99;
       
   362 			return (KErrNone);
       
   363 			}
       
   364 		if (trashBurst)
       
   365 			{
       
   366 			if ((Random() & 0xf) == 0xf)
       
   367 				trashBurst=EFalse;
       
   368 			PagedTrashCount++;
       
   369 			}
       
   370 		else 
       
   371 			{
       
   372 			
       
   373 			for(TInt i=size/(pageSize); (i>0) && !trashBurst; --i)
       
   374 				{
       
   375 				READ(start+((TInt64(Random())*TInt64(size))>>32));
       
   376 				if ((RandomNo & 0x3f) == 0x3f)
       
   377 					{
       
   378 					trashBurst= (TBool) aUseTb;
       
   379 					}
       
   380 				PagedTrashCount++;
       
   381 				if (RandomNo & 1)
       
   382 					User::AfterHighRes(500+Random() & 2047);
       
   383 				}
       
   384 			}
       
   385 	
       
   386 		}
       
   387 	return(KErrNone);
       
   388 	}
       
   389 	
       
   390 
       
   391 // This starts up multiple instances of repeatedPagingThread, and runs testWriteMain.
       
   392 // After its done, it calls format, to clean up the drive.
       
   393 
       
   394 void TestNandAccuratcy()
       
   395 	{
       
   396 	RThread thisThread;
       
   397 	const TInt KNoThreads=10;
       
   398 	TInt i;
       
   399 	test.Printf(_L("Reset concurrency stats\n"));
       
   400 
       
   401 	i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetConcurrencyInfo,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
       
   402 	test(i==KErrNone || i==KErrNotSupported);
       
   403 	if(i==KErrNotSupported)
       
   404 		test.Printf(_L("Concurrency stats not supported on this build\n"));
       
   405 	i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetPagingBenchmark,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
       
   406 	test(i==KErrNone || i==KErrNotSupported);
       
   407 	if(i==KErrNotSupported)
       
   408 		test.Printf(_L("Benchmark stats not supported on this build\n"));
       
   409 
       
   410 	if (Maxloops>0)
       
   411 		{
       
   412 		TRequestStatus stat[KNoThreads];
       
   413 		// Start Read Test
       
   414 		RThread repeatedPagingThread[KNoThreads];
       
   415 		
       
   416 		test.Next(_L("Read/Write and Page test"));
       
   417 
       
   418 		Testing=ETrue;
       
   419 		for (i=0; i<KNoThreads; i++)
       
   420 			{
       
   421 			
       
   422 			test(repeatedPagingThread[i].Create(_L(""),RepeatedPagingThread,KDefaultStackSize,NULL,(TAny*) ETrue)==KErrNone);
       
   423 			repeatedPagingThread[i].Logon(stat[i]);
       
   424 			test(stat[i]==KRequestPending);	
       
   425 			repeatedPagingThread[i].Resume();
       
   426 			}
       
   427 		// Start repeated paging.
       
   428 		thisThread.SetPriority(EPriorityMore);
       
   429 		testWriteMain();
       
   430 		Testing = 0;
       
   431 		thisThread.SetPriority(EPriorityNormal);
       
   432 		for (i=0; i<KNoThreads; i++)
       
   433 	 		User::WaitForRequest(stat[i]);
       
   434 
       
   435 		test.Printf(_L("Collect concurrency stats\n"));
       
   436 		SMediaROMPagingConcurrencyInfo info;
       
   437 		SPagingBenchmarkInfo infoBench;
       
   438 		i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMConcurrencyInfo,(TAny*)locDriveNumber,&info);
       
   439 		test(i==KErrNone || i==KErrNotSupported);
       
   440 		TInt r=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMPagingBenchmark,(TAny*)locDriveNumber,&infoBench);
       
   441 		test(r==KErrNone || r==KErrNotSupported);
       
   442 		if(i==KErrNone)
       
   443 			{
       
   444 			test.Printf(_L("Media concurrency stats:\n\n"));
       
   445 			test.Printf(_L("The total number of page in requests issued whilst processing other page in requests: %d\n"),info.iTotalConcurrentReqs);
       
   446 			test.Printf(_L("The total number of page in requests issued with at least one queue not empty: %d\n"),info.iTotalReqIssuedNonEmptyQ);
       
   447 			test.Printf(_L("The maximum number of pending page in requests in the main queue any time during this session: %d\n"),info.iMaxReqsInPending);
       
   448 			test.Printf(_L("The maximum number of pending page in requests in the deferred queue any time during this session: %d\n"),info.iMaxReqsInDeferred);
       
   449 			test.Printf(_L("The total number of page in requests first-time deferred during this session: %d\n"),info.iTotalFirstTimeDeferrals);
       
   450 			test.Printf(_L("The total number of page in requests re-deferred during this session: %d\n"),info.iTotalReDeferrals);
       
   451 			test.Printf(_L("The maximum number of deferrals of any single page in request during this session: %d\n"),info.iMaxDeferrals);
       
   452 			test.Printf(_L("The total number of times the main queue was emptied when completing an asynchronous request during this session: %d\n"),info.iTotalSynchEmptiedMainQ);
       
   453 			test.Printf(_L("The total number of page in requests serviced from main queue when completing an asynchronous request: %d\n"),info.iTotalSynchServicedFromMainQ);
       
   454 			test.Printf(_L("The total number of page in requests deferred after being picked out of main queue when completing an asynchronous request: %d\n"),info.iTotalSynchDeferredFromMainQ);
       
   455 			test.Printf(_L("The total number of times the page in DFC run with an empty main queue during this session: %d\n"),info.iTotalRunDry);
       
   456 			test.Printf(_L("The total number of dry runs of paging DFC avoided during this session: %d\n"),info.iTotalDryRunsAvoided);
       
   457 			}
       
   458 
       
   459 		if(r==KErrNone)
       
   460 			{
       
   461 			TInt freq = 0;
       
   462 			r = HAL::Get(HAL::EFastCounterFrequency, freq);
       
   463 			if (r==KErrNone)
       
   464 				{
       
   465 				TReal mult = 1000000.0 / freq;
       
   466 				TReal min = 0.0;
       
   467 				TReal max = 0.0;
       
   468 				TReal avg = 0.0;
       
   469 				if (infoBench.iCount != 0)
       
   470 					{
       
   471 					min = infoBench.iMinTime * mult;
       
   472 					max = infoBench.iMaxTime * mult;
       
   473 					avg = (infoBench.iTotalTime * mult) / infoBench.iCount;
       
   474 					}
       
   475 				test.Printf(_L("Media benchmarks:\n\n"));
       
   476 				test.Printf(_L("The total number of page in requests issued: %d\n"),infoBench.iCount);
       
   477 				test.Printf(_L("The average latency of any page in request in the Media subsystem: %9.1f(us)\n"),avg);
       
   478 				test.Printf(_L("The maximum latency of any page in request in the Media subsystem: %9.1f(us)\n"),max);
       
   479 				test.Printf(_L("The minimum latency of any page in request in the Media subsystem: %9.1f(us)\n"),min);
       
   480 				}
       
   481 			}
       
   482 
       
   483 		test.Printf(_L("Formatting...\n"));
       
   484 		silentFormat(DriveNumber);
       
   485 		}
       
   486 		else
       
   487 			test.Next(_L("Read/Write test - Skipped!"));
       
   488 
       
   489 	}
       
   490 	
       
   491 
       
   492 // ************************************************************************************
       
   493 	
       
   494 	
       
   495 // This code causes a flush
       
   496 // It is done in a second thread to see if you really do get just
       
   497 // one deferral, with the other page requests just waiting in line.
       
   498 // (Paging is not re-entrant)
       
   499 
       
   500 TInt PagesBeingPaged=0;
       
   501 RMutex PageMutex;
       
   502 RSemaphore PageSemaphore;
       
   503 RSemaphore PageDoneSemaphore;
       
   504  
       
   505 LOCAL_C TInt CausePage(TAny*)
       
   506 	{	
       
   507 	TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
       
   508 	TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
       
   509 	TUint size = romHeader->iPageableRomSize;
       
   510 	TUint8* addr=NULL;
       
   511 	TBool flush;
       
   512 	while (Testing)
       
   513 		{
       
   514 			PageSemaphore.Wait(); // wait for main thread to want paging.
       
   515 			flush = (PagesBeingPaged==0);
       
   516 			addr=start+((TInt64(Random())*TInt64(size))>>32);	
       
   517 			PageDoneSemaphore.Signal(); // Acknolage request.
       
   518 
       
   519 			PageMutex.Wait();
       
   520 			PagesBeingPaged++;
       
   521 			PageMutex.Signal();
       
   522 
       
   523 			if (flush)
       
   524 				UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
       
   525 			READ(addr);
       
   526 
       
   527 			PageMutex.Wait();
       
   528 			PagesBeingPaged--;
       
   529 			PageMutex.Signal();
       
   530 		}
       
   531 	return 0;
       
   532 	}
       
   533 
       
   534 
       
   535 // TestDefered causes garbage collection, and then triggers paging to happen, which should be defered.
       
   536 // One would only expect one defered request, as the paging system is not reentrant, but this is checked.
       
   537 
       
   538 void TestDefered()
       
   539 	{
       
   540 	if (MaxDeferLoops==0)
       
   541 		{
       
   542 		test.Next(_L("Defering test - Skipped!"));
       
   543 		return;
       
   544 		}
       
   545 		
       
   546 	TInt timeout;
       
   547 	TInt writesNeeded=100;
       
   548 	TInt r = KErrNone;
       
   549 	RFile tempFile;
       
   550 	TInt i;
       
   551 	TInt ii;
       
   552 	TInt runs=0;
       
   553 
       
   554 	SDeferStats stats;
       
   555 	TInt pageGarbageCount=0;
       
   556 	TInt pageOtherCount=0;	
       
   557 	TInt normalGarbageCount=0;
       
   558 	TInt normalOtherCount=0;
       
   559 
       
   560 
       
   561 	// Set up thread sync
       
   562 	test(PageMutex.CreateLocal()==KErrNone);
       
   563 	test(PageSemaphore.CreateLocal(0)==KErrNone);
       
   564 	test(PageDoneSemaphore.CreateLocal(0)==KErrNone);
       
   565 
       
   566 		
       
   567 
       
   568 	const TInt KMaxPageThreads = 2;
       
   569 	UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
       
   570 	// Set up threads
       
   571 	RThread pageThread[KMaxPageThreads];
       
   572 	TRequestStatus stat[KMaxPageThreads];
       
   573 	Testing=ETrue;
       
   574 	for (i=0; i<KMaxPageThreads; i++)
       
   575 		{
       
   576 		test(pageThread[i].Create(_L(""),CausePage,KDefaultStackSize,NULL,NULL)==KErrNone);
       
   577 		pageThread[i].Logon(stat[i]);
       
   578 		test(stat[i]==KRequestPending);
       
   579 		pageThread[i].SetPriority(EPriorityMore);
       
   580 		pageThread[i].Resume();
       
   581 		}
       
   582 		
       
   583 		
       
   584 	test.Next(_L("Defering test"));
       
   585 
       
   586 	// clear counters
       
   587 	TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
       
   588 	test(Drive.ControlIO(KNandGetDeferStats,statsBuf,0)==KErrNone);
       
   589 	
       
   590 	CreateFile(tempFile,_L("nandpage.txt"));
       
   591 		
       
   592 	 	
       
   593 	for (ii=0; ii<MaxDeferLoops; ii++)  // Repeat the test, 'MaxDeferLoops' number of times.  This can be set on cammand line.
       
   594 		{
       
   595 		timeout=20;
       
   596 		do  // while ((pageGarbageCount==0) && (timeout>0));
       
   597 			// ie, while garbage collection hasn't happened, or timed out
       
   598 			{
       
   599 			timeout--;
       
   600 			pageGarbageCount=0;
       
   601 			pageOtherCount=0;
       
   602 			normalGarbageCount=0;
       
   603 			normalOtherCount=0;
       
   604 			
       
   605 			// Give somethng for garbage collector to collect	
       
   606 			for (i=0; i<writesNeeded; i++)
       
   607 		 		test(WriteNumber(tempFile)==KErrNone);
       
   608 			 
       
   609 			// Force Collection.  (Normally only happens in Idle) 		
       
   610 		 	r = Drive.ControlIO(KNandCollectGarbage,NULL,NULL);
       
   611 		 	test(r==KErrNone);
       
   612 			 	
       
   613 		 	// Since garbage Colleciton should be going now, watch it, until its finished. 
       
   614 			do
       
   615 		 		{
       
   616 				runs = PagesBeingPaged;
       
   617 				for (i=runs; i<KMaxPageThreads; i++)
       
   618 		 			PageSemaphore.Signal(); // Trigger Paging.
       
   619 
       
   620 				for (i=runs; i<KMaxPageThreads; i++)
       
   621 		 			PageDoneSemaphore.Wait();
       
   622 					
       
   623 				TInt tries = 10;
       
   624 				do { // If we get zero hits, maybe the page hasnt hit yet.
       
   625 					tries--;
       
   626 					User::AfterHighRes(1000+Random() & 2047);  // Throw some uncertainly into things
       
   627 				
       
   628 					TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
       
   629 			 		r = Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
       
   630 					test (r == KErrNone);
       
   631 			 		pageGarbageCount+=stats.iPageGarbage; 
       
   632 			 		pageOtherCount+=stats.iPageOther;			 	
       
   633 			 		normalGarbageCount+=stats.iNormalGarbage; 
       
   634 			 		normalOtherCount+=stats.iNormalOther;
       
   635 					} while ((pageGarbageCount==0) && (tries>0)); // If we get zero hits, maybe the page hasnt hit yet
       
   636 		 		}
       
   637 		 	while (stats.iPageGarbage>0); // Keep going until collection seems to have finished.
       
   638 		 	
       
   639 		 	// The paging system is not reentrant, so should never get more then one.
       
   640 		 	test(stats.iPageGarbage<2);
       
   641 		 	
       
   642 			test.Printf(_L("%d: PG %d PO %d NG %d NO %d\n"),ii,pageGarbageCount,  pageOtherCount, normalGarbageCount,  normalOtherCount );
       
   643 			// if no collection, probebly didnt write enough to trigger it, so up the quantity.
       
   644 			if (pageGarbageCount==0)
       
   645 				{		
       
   646 				writesNeeded+=writesNeeded/2;
       
   647 				test.Printf(_L("Writes needed = %d\n"),writesNeeded);
       
   648 				}
       
   649 				
       
   650 			}
       
   651 		while ((pageGarbageCount==0) && (timeout>0));
       
   652 		test(timeout>0);
       
   653 			
       
   654 		} // end for MaxDeferLoops.
       
   655 
       
   656 	// Clean up. . . . .
       
   657 
       
   658 	Testing=EFalse;  // Setting this causes the CausePage threads to exit.
       
   659 
       
   660 	// Wait for threads to exit, signaling the semaphore in case they where waiting on it.
       
   661 	for (i=0; i<KMaxPageThreads; i++)
       
   662 		PageSemaphore.Signal();
       
   663 	for (i=0; i<KMaxPageThreads; i++)
       
   664 		User::WaitForRequest(stat[i]);
       
   665 
       
   666 	PageMutex.Close();	
       
   667 	PageSemaphore.Close();
       
   668 	PageDoneSemaphore.Close();
       
   669 	CloseAndDestroy(tempFile);
       
   670 	}
       
   671 
       
   672 
       
   673 // ************************************************************************************
       
   674 
       
   675 //
       
   676 // The gubbins that starts all the tests
       
   677 //
       
   678 // ParseCommandLine reads the arguments and sets globals accordingly.
       
   679 //
       
   680 
       
   681 void ParseCommandLine()
       
   682 	{
       
   683 	TBuf<32> args;
       
   684 	User::CommandLine(args);
       
   685 	TLex lex(args);
       
   686 	
       
   687 	FOREVER
       
   688 		{
       
   689 		
       
   690 		TPtrC token=lex.NextToken();
       
   691 		if(token.Length()!=0)
       
   692 			{
       
   693 			if ((token.Length()==2) && (token[1]==':'))
       
   694 				DriveNumber=User::UpperCase(token[0])-'A';
       
   695 			else if (token.Length()==1)
       
   696 				{
       
   697 				TChar driveLetter = User::UpperCase(token[0]); 
       
   698 				if ((driveLetter>='A') && (driveLetter<='Z'))
       
   699 					DriveNumber=driveLetter - (TChar) 'A';
       
   700 				else 
       
   701 					test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
       
   702 				}
       
   703 			else if ((token==_L("help")) || (token==_L("-h")) || (token==_L("-?")))
       
   704 				{
       
   705 				test.Printf(_L("\nUsage:  t_nandpaging <driveletter> [rwsoak <cc>] [defer <c>]\n'-' indicated infinity.\n\n"));
       
   706 				test.Getch();
       
   707 				Maxloops=0;
       
   708 				}
       
   709 			else if (token==_L("rwsoak"))
       
   710 				{
       
   711 				TPtrC val=lex.NextToken();
       
   712 				TLex lexv(val);
       
   713 				TInt v;
       
   714 
       
   715 				if (val==_L("-"))
       
   716 					Forever=ETrue;
       
   717 				else
       
   718 					if (lexv.Val(v)==KErrNone)
       
   719 						Maxloops=v;
       
   720 					else
       
   721 						test.Printf(_L("Bad value for rwsoak '%S' was ignored.\n"), &val);
       
   722 				}
       
   723 			else if (token==_L("defer"))
       
   724 				{
       
   725 				TPtrC val=lex.NextToken();
       
   726 				TLex lexv(val);
       
   727 				TInt v;
       
   728 
       
   729 				if (val==_L("-"))
       
   730 					MaxDeferLoops=KMaxTInt;
       
   731 				else
       
   732 					if (lexv.Val(v)==KErrNone)
       
   733 						MaxDeferLoops=v;
       
   734 					else
       
   735 						test.Printf(_L("Bad value for defer '%S' was ignored.\n"), &val);
       
   736 				}	
       
   737 			else
       
   738 				test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
       
   739 			}
       
   740 		else
       
   741 			break;
       
   742 		
       
   743 		}
       
   744 	}
       
   745 
       
   746 //
       
   747 // E32Main
       
   748 //
       
   749 
       
   750 TInt E32Main()
       
   751 	{
       
   752 	TInt r;
       
   753 	test.Title();
       
   754 
       
   755 	test.Printf(_L("key\n---\n"));	
       
   756 	test.Printf(_L("PG: Paging requests defered due to Garbage\n"));
       
   757 	test.Printf(_L("PO: Paging requests defered due to other operations\n"));
       
   758 	test.Printf(_L("NG: Normal requests defered due to Garbage\n"));
       
   759 	test.Printf(_L("NO: Normal requests defered due to other operations\n\n"));
       
   760 
       
   761 	
       
   762 	test.Start(_L("Check that the rom is paged"));
       
   763 	TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
       
   764 
       
   765 	if (romHeader->iPageableRomStart==NULL)
       
   766 		test.Printf(_L("Test ROM is not paged - test skipped!\r\n"));
       
   767 	else
       
   768 		{
       
   769 		ParseCommandLine();	
       
   770 		test(TheFs.Connect()==KErrNone);
       
   771 
       
   772 		r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
       
   773 		if(r<0)
       
   774 			{
       
   775 			test.Printf(_L("DemandPagingFlushPages Error = %d\n"),r);
       
   776 			test(0);
       
   777 			}
       
   778 
       
   779 		DriveNumber = FindFsNANDDrive();	
       
   780 		
       
   781 		if(DriveNumber<0)
       
   782 			test.Printf(_L("NAND Flash not found - test skipped!\r\n"));
       
   783 		else
       
   784 			{
       
   785 			RFile file;
       
   786 			TBuf<256> fileName;	
       
   787 			fileName.Append((TChar)('A'+DriveNumber));
       
   788 			fileName+=_L(":\\f32-tst\\");
       
   789 			TInt r=TheFs.MkDirAll(fileName);
       
   790 			test(r==KErrNone || r== KErrAlreadyExists);
       
   791 			fileName += _L("annoyingflies.txt");
       
   792 			r=file.Replace(TheFs,fileName,EFileWrite);
       
   793 			if (r!=KErrNone)
       
   794 				test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
       
   795 			test(r==KErrNone);
       
   796 			r=file.Write(_L8("Flies as big as sparrows indoletly buzzing in the warm air, heavy with the stench of rotting carcasses"));
       
   797 			if (r!=KErrNone)
       
   798 				test.Printf(_L("Error %d: could not write to file\n"),r);
       
   799 			test(r==KErrNone);
       
   800 
       
   801 			test(file.Flush() == KErrNone);
       
   802 
       
   803 			SBlockMapInfo info;
       
   804 			TInt64 start=0;
       
   805 			r=file.BlockMap(info,start, -1,ETestDebug);
       
   806 			if (r!=KErrNone && r!=KErrCompletion)
       
   807 				test.Printf(_L("Error %d: could not obtain block map\n"),r);
       
   808 			test(r==KErrNone || r==KErrCompletion);
       
   809 			locDriveNumber=info.iLocalDriveNumber;
       
   810 			test.Printf(_L("Found drive: %c (NAND drive %d)\r\n"), DriveNumber+'A',locDriveNumber);
       
   811 			file.Close();
       
   812 			
       
   813 			// Connect to device driver
       
   814 			TBool changeFlag = EFalse;
       
   815 			r = Drive.Connect(locDriveNumber,changeFlag);
       
   816 			TPckg<TLocalDriveCapsV4>	capsPack(DriveCaps);
       
   817 			Drive.Caps(capsPack);
       
   818 			test(r == KErrNone);
       
   819 
       
   820 			r = Drive.ControlIO(KNandCollectGarbage,NULL,NULL);
       
   821 			if (r!=KErrNone)
       
   822 				{
       
   823 				test.Printf(_L("LocalDrive does not support the KNandCollectGarbage ControlIO request\n"));
       
   824 				CtrlIoCollectGarbageSupported = EFalse;
       
   825 				}
       
   826 
       
   827 			SDeferStats stats;
       
   828 			TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
       
   829 	 		r = Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
       
   830 			if (r == KErrNone)
       
   831 				{
       
   832 				if (stats.iSynchronousMediaDriver)
       
   833 					{
       
   834 					test.Printf(_L("Media drive is synchronous - test skipped!\r\n"));
       
   835 					test.End();
       
   836 					return 0;
       
   837 					}
       
   838 				}
       
   839 			else
       
   840 				{
       
   841 				test.Printf(_L("LocalDrive does not support the KNandGetDeferStats ControlIO request\n"));
       
   842 				CtrlIoGetDeferStatsSupported = EFalse;
       
   843 				}
       
   844 
       
   845 
       
   846 			test.Printf(_L("LocalDrive Connected\n"));
       
   847 			//
       
   848 			// Run tests	
       
   849 			//
       
   850 			TestNandAccuratcy();
       
   851 			if(CtrlIoCollectGarbageSupported && CtrlIoGetDeferStatsSupported)
       
   852 				TestDefered();
       
   853 			// 
       
   854 			// Free device and end test program
       
   855 			//
       
   856 			Drive.Disconnect();
       
   857 			}	
       
   858 		}
       
   859 		
       
   860 	test.End();
       
   861 	return 0;
       
   862 	}
       
   863 
       
   864