1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/f32test/demandpaging/t_nandpaging.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,865 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\mmu\t_nandpaging.cpp
1.18 +// Suite of tests specifically to test the demand paging subsystem when
1.19 +// booted from NAND.
1.20 +// 002 Read/Write and Page test
1.21 +// 003 Defering test
1.22 +//
1.23 +//
1.24 +
1.25 +//! @SYMTestCaseID KBASE-T_NANDPAGING-0332
1.26 +//! @SYMTestType UT
1.27 +//! @SYMPREQ PREQ1110
1.28 +//! @SYMTestCaseDesc Demand Paging Nand Paging tests.
1.29 +//! @SYMTestActions 001 Check that the rom is paged
1.30 +//! @SYMTestExpectedResults All tests should pass.
1.31 +//! @SYMTestPriority High
1.32 +//! @SYMTestStatus Implemented
1.33 +
1.34 +#include <e32test.h>
1.35 +RTest test(_L("T_NANDPAGING"));
1.36 +
1.37 +#include <e32rom.h>
1.38 +#include <e32svr.h>
1.39 +#include <u32hal.h>
1.40 +#include <f32file.h>
1.41 +#include <f32dbg.h>
1.42 +#include "testdefs.h"
1.43 +#include <hal.h>
1.44 +
1.45 +
1.46 +TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect.
1.47 +TInt locDriveNumber;
1.48 +
1.49 +TInt MaxDeferLoops=40; // Parameter - Defer test, for how long?
1.50 +TInt Maxloops=400; // Parameter - RW Soak, for how long?
1.51 +TBool Forever=EFalse; // Parameter - RW Soak forever?
1.52 +
1.53 +TBool Testing=ETrue; // Used to communicate when testing has finished between threads.
1.54 +
1.55 +RFs TheFs;
1.56 +TBusLocalDrive Drive;
1.57 +TLocalDriveCapsV4 DriveCaps;
1.58 +
1.59 +TInt PagedTrashCount=0; // Incremented by threads, is used to detect preemption.
1.60 +TInt GlobError=KErrNone; // To communicate an error between threads.
1.61 +TBool CtrlIoCollectGarbageSupported = ETrue;
1.62 +TBool CtrlIoGetDeferStatsSupported = ETrue;
1.63 +
1.64 +
1.65 +const TInt KDiskSectorShift=9;
1.66 +const TInt KBufSizeInSectors=8;
1.67 +const TInt KBufSizeInBytes=(KBufSizeInSectors<<KDiskSectorShift)*40;
1.68 +
1.69 +LOCAL_D TBuf8<KBufSizeInBytes> Buffer;
1.70 +
1.71 +
1.72 +
1.73 +// Three functions for the garbage test.
1.74 +// CreateFile creates a file, and sets up the buffer for WriteNumber.
1.75 +// After the code has finished writing numbers to the start,
1.76 +// CloseAndDestroy cleans up.
1.77 +
1.78 +void CreateFile(RFile &aFile,const TDesC& aFileName)
1.79 + {
1.80 + TBuf<256> fileName;
1.81 + fileName.Append((TChar)('A'+DriveNumber));
1.82 + fileName+=_L(":\\f32-tst\\");
1.83 + TInt r=TheFs.MkDirAll(fileName);
1.84 + test(r==KErrNone || r== KErrAlreadyExists);
1.85 +
1.86 + fileName += aFileName;
1.87 +
1.88 + r=aFile.Replace(TheFs,fileName,EFileWrite);
1.89 + if (r!=KErrNone)
1.90 + test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
1.91 + test(r==KErrNone);
1.92 + Buffer.SetLength(4);
1.93 + }
1.94 +
1.95 +void CloseAndDestroy(RFile &aFile)
1.96 + {
1.97 + TBuf<256> fileName;
1.98 + aFile.FullName(fileName);
1.99 + aFile.Close();
1.100 + TheFs.Delete(fileName);
1.101 + }
1.102 +
1.103 +TInt WriteNumber(RFile &aFile)
1.104 + {
1.105 + TInt r;
1.106 + Buffer[0]++;
1.107 + r = aFile.Write(0,Buffer);
1.108 + if (r==KErrNone)
1.109 + return aFile.Flush();
1.110 + else
1.111 + return r;
1.112 + }
1.113 +
1.114 +
1.115 +
1.116 +// The r/w soaktest leaves the drive in a mess.
1.117 +// Formatting is needed afterwards.
1.118 +
1.119 +void silentFormat(TInt driveNo)
1.120 + {
1.121 + TBuf<4> driveBuf=_L("?:\\");
1.122 + RFormat format;
1.123 + TInt count;
1.124 +
1.125 + driveBuf[0] = (TText)(driveNo + 'A');
1.126 +
1.127 + TInt r = format.Open(TheFs, driveBuf, EHighDensity, count);
1.128 + test(r == KErrNone);
1.129 +
1.130 + while(count)
1.131 + {
1.132 + r=format.Next(count);
1.133 + test(r == KErrNone);
1.134 + }
1.135 +
1.136 + format.Close();
1.137 + }
1.138 +
1.139 +// Finds the 1st r/w NAND drive, or checks the specified one fits requirements
1.140 +
1.141 +static TInt FindFsNANDDrive()
1.142 + {
1.143 + TDriveList driveList;
1.144 + TDriveInfo driveInfo;
1.145 + TInt r=TheFs.DriveList(driveList);
1.146 + test(r == KErrNone);
1.147 +
1.148 + for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum<KMaxDrives; ++drvNum)
1.149 + {
1.150 + if(!driveList[drvNum])
1.151 + continue; //-- skip unexisting drive
1.152 +
1.153 + test(TheFs.Drive(driveInfo, drvNum) == KErrNone);
1.154 +
1.155 + if ((driveInfo.iMediaAtt&KMediaAttPageable) &&
1.156 + (driveInfo.iType == EMediaNANDFlash) &&
1.157 + (driveInfo.iDriveAtt & KDriveAttInternal))
1.158 + {
1.159 + TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected; // skip ROFS partitions
1.160 + if(!readOnly)
1.161 + {
1.162 + if ((drvNum==DriveNumber) || (DriveNumber<0)) // only test if running on this drive
1.163 + {
1.164 + return (drvNum);
1.165 + }
1.166 + }
1.167 + }
1.168 + }
1.169 + return (-1);
1.170 + }
1.171 +
1.172 +
1.173 +//
1.174 +// Writes to main area for the entire disk and reads back to verify.
1.175 +// The function is called from TestNandAccuratcy, which will have also
1.176 +// started the background RepeatedPagingThread
1.177 +//
1.178 +void testWriteMain()
1.179 + {
1.180 + TInt i;
1.181 + TInt r;
1.182 + TInt changeCount=0;
1.183 + TInt totChangeCount=0;
1.184 + TInt cCount=0;
1.185 + TInt fullcCount=0;
1.186 + TInt oldPagedTrashCount=0;
1.187 + TInt delta=0;
1.188 + TInt high=0;
1.189 + TInt tot=0;
1.190 + TInt fullTot=0;
1.191 + TInt blockNo;
1.192 +
1.193 + // read size is 64K
1.194 + TInt readSize = (64*1024);
1.195 + TInt64 size = DriveCaps.iSize - (DriveCaps.iSize % readSize);
1.196 +
1.197 + // print position every 128K
1.198 + TInt64 printBlockPos = 128 * 1024;
1.199 + test (size > printBlockPos);
1.200 +
1.201 + // check for paging activity every 1MB
1.202 + TInt64 checkChangePos = 1024*1024;
1.203 + while (checkChangePos > size)
1.204 + checkChangePos>>= 1;
1.205 +
1.206 +
1.207 + SDeferStats stats;
1.208 + TInt pageGarbageCount=0;
1.209 + TInt pageOtherCount=0;
1.210 + TInt normalGarbageCount=0;
1.211 + TInt normalOtherCount=0;
1.212 +
1.213 +
1.214 + Buffer.SetLength(2*readSize);
1.215 +
1.216 + TPtr8 subBuf1(&Buffer[0],readSize);
1.217 + TPtrC8 subBuf2(&Buffer[readSize], readSize);
1.218 +
1.219 + test.Printf(_L("Page size = %d\n"), DriveCaps.iNumBytesMain);
1.220 + test.Printf(_L("Erase block size = %d\n"), DriveCaps.iEraseBlockSize);
1.221 + test.Printf(_L("Media size (rounded down) = %ld\n"), size);
1.222 +
1.223 + for(i = 0; i<readSize; i++)
1.224 + Buffer[readSize+i] = (char)(i%100);
1.225 +
1.226 + // Zero Stats
1.227 + if(CtrlIoGetDeferStatsSupported)
1.228 + {
1.229 + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
1.230 + test(Drive.ControlIO(KNandGetDeferStats,statsBuf,0)==KErrNone);
1.231 + }
1.232 +
1.233 +
1.234 + while (((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone))
1.235 + {
1.236 + for(TInt64 pos=0;
1.237 + (pos<size) && ((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone);
1.238 + pos+=(TUint)(readSize))
1.239 + {
1.240 + blockNo=I64LOW(pos / DriveCaps.iEraseBlockSize);
1.241 + if ((pos % printBlockPos) == 0)
1.242 + test.Printf(_L("Block %d at pos %lu \r"), blockNo, pos);
1.243 +
1.244 + //write the pattern
1.245 + r = Drive.Write(pos,subBuf2);
1.246 + test(r==KErrNone);
1.247 +
1.248 + //read back and verify
1.249 + r = Drive.Read(pos,readSize,subBuf1);
1.250 + test(r==KErrNone);
1.251 +
1.252 + for(i=0;i<readSize;i++)
1.253 + if(Buffer[i]!=Buffer[readSize+i])
1.254 + {
1.255 + r = KErrCorrupt;
1.256 + break;
1.257 + }
1.258 + delta = PagedTrashCount-oldPagedTrashCount;
1.259 + cCount++;
1.260 + if (delta)
1.261 + {
1.262 + if (delta>high)
1.263 + high=delta;
1.264 + tot+=delta;
1.265 +
1.266 + oldPagedTrashCount=PagedTrashCount;
1.267 + changeCount++;
1.268 + }
1.269 +
1.270 + if ((pos > 0) && (pos % checkChangePos) == 0)
1.271 + {
1.272 + totChangeCount+=changeCount;
1.273 + if(CtrlIoGetDeferStatsSupported)
1.274 + {
1.275 + test.Printf(_L("\nHigh%4d Avg%2d %d%% CC=%4d \n"), high, (TInt) (tot/cCount), (TInt)(changeCount*100)/cCount, totChangeCount);
1.276 +
1.277 + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
1.278 + Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
1.279 + 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);
1.280 +
1.281 + test(stats.iPageOther>0);
1.282 + pageGarbageCount+=stats.iPageGarbage;
1.283 + pageOtherCount+=stats.iPageOther;
1.284 + normalGarbageCount+=stats.iNormalGarbage;
1.285 + normalOtherCount+=stats.iNormalOther;
1.286 + }
1.287 +
1.288 + high=0;
1.289 +
1.290 + fullTot+=tot;
1.291 + tot=0;
1.292 +
1.293 + fullcCount+=cCount;
1.294 + cCount=0;
1.295 + changeCount=0;
1.296 + }
1.297 +
1.298 + test(r==KErrNone);
1.299 + } // for loop
1.300 +
1.301 + if (CtrlIoGetDeferStatsSupported)
1.302 + {
1.303 + test.Printf(_L("\nTotals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount);
1.304 + test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),pageGarbageCount, pageOtherCount,(TInt) (pageOtherCount*100/fullcCount), normalGarbageCount, normalOtherCount );
1.305 + }
1.306 +
1.307 + // If totChangeCount does not change, nand maybe busy waiting.
1.308 + test(totChangeCount>0);
1.309 + } // while ()
1.310 +
1.311 + if (GlobError!=KErrNone)
1.312 + {
1.313 + test.Printf(_L("\nPaging failed with %x\n"), GlobError);
1.314 + test(0);
1.315 + }
1.316 + else
1.317 + test.Printf(_L("\ndone\n"));
1.318 + }
1.319 +
1.320 +
1.321 +TUint8 ReadByte(volatile TUint8* aPtr)
1.322 + {
1.323 + return *aPtr;
1.324 + }
1.325 +
1.326 +#define READ(a) ReadByte((volatile TUint8*)(a))
1.327 +
1.328 +TUint32 RandomNo =0;
1.329 +
1.330 +TUint32 Random()
1.331 + {
1.332 + RandomNo = RandomNo*69069+1;
1.333 + return RandomNo;
1.334 + }
1.335 +
1.336 +
1.337 +// Many instances of this run while testWriteMain runs,
1.338 +// to cause random background paging.
1.339 +
1.340 +LOCAL_C TInt RepeatedPagingThread(TAny* aUseTb)
1.341 + {
1.342 + TBool trashBurst = EFalse;
1.343 + // This makes the paging system continually page stuff.
1.344 + // get info about a paged ROM...
1.345 +
1.346 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.347 + TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
1.348 + TUint size = romHeader->iPageableRomSize;
1.349 + TInt pageSize = 0;
1.350 + PagedTrashCount=1;
1.351 +
1.352 + UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0);
1.353 + RandomNo=123;
1.354 + PagedTrashCount++;
1.355 +
1.356 + while (Testing)
1.357 + {
1.358 + TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
1.359 + if (Random() & 1)
1.360 + User::AfterHighRes(500+Random() & 2047);
1.361 +
1.362 + if (r<0)
1.363 + {
1.364 + GlobError=r;
1.365 + PagedTrashCount=99;
1.366 + return (KErrNone);
1.367 + }
1.368 + if (trashBurst)
1.369 + {
1.370 + if ((Random() & 0xf) == 0xf)
1.371 + trashBurst=EFalse;
1.372 + PagedTrashCount++;
1.373 + }
1.374 + else
1.375 + {
1.376 +
1.377 + for(TInt i=size/(pageSize); (i>0) && !trashBurst; --i)
1.378 + {
1.379 + READ(start+((TInt64(Random())*TInt64(size))>>32));
1.380 + if ((RandomNo & 0x3f) == 0x3f)
1.381 + {
1.382 + trashBurst= (TBool) aUseTb;
1.383 + }
1.384 + PagedTrashCount++;
1.385 + if (RandomNo & 1)
1.386 + User::AfterHighRes(500+Random() & 2047);
1.387 + }
1.388 + }
1.389 +
1.390 + }
1.391 + return(KErrNone);
1.392 + }
1.393 +
1.394 +
1.395 +// This starts up multiple instances of repeatedPagingThread, and runs testWriteMain.
1.396 +// After its done, it calls format, to clean up the drive.
1.397 +
1.398 +void TestNandAccuratcy()
1.399 + {
1.400 + RThread thisThread;
1.401 + const TInt KNoThreads=10;
1.402 + TInt i;
1.403 + test.Printf(_L("Reset concurrency stats\n"));
1.404 +
1.405 + i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetConcurrencyInfo,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
1.406 + test(i==KErrNone || i==KErrNotSupported);
1.407 + if(i==KErrNotSupported)
1.408 + test.Printf(_L("Concurrency stats not supported on this build\n"));
1.409 + i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetPagingBenchmark,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
1.410 + test(i==KErrNone || i==KErrNotSupported);
1.411 + if(i==KErrNotSupported)
1.412 + test.Printf(_L("Benchmark stats not supported on this build\n"));
1.413 +
1.414 + if (Maxloops>0)
1.415 + {
1.416 + TRequestStatus stat[KNoThreads];
1.417 + // Start Read Test
1.418 + RThread repeatedPagingThread[KNoThreads];
1.419 +
1.420 + test.Next(_L("Read/Write and Page test"));
1.421 +
1.422 + Testing=ETrue;
1.423 + for (i=0; i<KNoThreads; i++)
1.424 + {
1.425 +
1.426 + test(repeatedPagingThread[i].Create(_L(""),RepeatedPagingThread,KDefaultStackSize,NULL,(TAny*) ETrue)==KErrNone);
1.427 + repeatedPagingThread[i].Logon(stat[i]);
1.428 + test(stat[i]==KRequestPending);
1.429 + repeatedPagingThread[i].Resume();
1.430 + }
1.431 + // Start repeated paging.
1.432 + thisThread.SetPriority(EPriorityMore);
1.433 + testWriteMain();
1.434 + Testing = 0;
1.435 + thisThread.SetPriority(EPriorityNormal);
1.436 + for (i=0; i<KNoThreads; i++)
1.437 + User::WaitForRequest(stat[i]);
1.438 +
1.439 + test.Printf(_L("Collect concurrency stats\n"));
1.440 + SMediaROMPagingConcurrencyInfo info;
1.441 + SPagingBenchmarkInfo infoBench;
1.442 + i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMConcurrencyInfo,(TAny*)locDriveNumber,&info);
1.443 + test(i==KErrNone || i==KErrNotSupported);
1.444 + TInt r=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMPagingBenchmark,(TAny*)locDriveNumber,&infoBench);
1.445 + test(r==KErrNone || r==KErrNotSupported);
1.446 + if(i==KErrNone)
1.447 + {
1.448 + test.Printf(_L("Media concurrency stats:\n\n"));
1.449 + test.Printf(_L("The total number of page in requests issued whilst processing other page in requests: %d\n"),info.iTotalConcurrentReqs);
1.450 + test.Printf(_L("The total number of page in requests issued with at least one queue not empty: %d\n"),info.iTotalReqIssuedNonEmptyQ);
1.451 + test.Printf(_L("The maximum number of pending page in requests in the main queue any time during this session: %d\n"),info.iMaxReqsInPending);
1.452 + test.Printf(_L("The maximum number of pending page in requests in the deferred queue any time during this session: %d\n"),info.iMaxReqsInDeferred);
1.453 + test.Printf(_L("The total number of page in requests first-time deferred during this session: %d\n"),info.iTotalFirstTimeDeferrals);
1.454 + test.Printf(_L("The total number of page in requests re-deferred during this session: %d\n"),info.iTotalReDeferrals);
1.455 + test.Printf(_L("The maximum number of deferrals of any single page in request during this session: %d\n"),info.iMaxDeferrals);
1.456 + 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);
1.457 + test.Printf(_L("The total number of page in requests serviced from main queue when completing an asynchronous request: %d\n"),info.iTotalSynchServicedFromMainQ);
1.458 + 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);
1.459 + 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);
1.460 + test.Printf(_L("The total number of dry runs of paging DFC avoided during this session: %d\n"),info.iTotalDryRunsAvoided);
1.461 + }
1.462 +
1.463 + if(r==KErrNone)
1.464 + {
1.465 + TInt freq = 0;
1.466 + r = HAL::Get(HAL::EFastCounterFrequency, freq);
1.467 + if (r==KErrNone)
1.468 + {
1.469 + TReal mult = 1000000.0 / freq;
1.470 + TReal min = 0.0;
1.471 + TReal max = 0.0;
1.472 + TReal avg = 0.0;
1.473 + if (infoBench.iCount != 0)
1.474 + {
1.475 + min = infoBench.iMinTime * mult;
1.476 + max = infoBench.iMaxTime * mult;
1.477 + avg = (infoBench.iTotalTime * mult) / infoBench.iCount;
1.478 + }
1.479 + test.Printf(_L("Media benchmarks:\n\n"));
1.480 + test.Printf(_L("The total number of page in requests issued: %d\n"),infoBench.iCount);
1.481 + test.Printf(_L("The average latency of any page in request in the Media subsystem: %9.1f(us)\n"),avg);
1.482 + test.Printf(_L("The maximum latency of any page in request in the Media subsystem: %9.1f(us)\n"),max);
1.483 + test.Printf(_L("The minimum latency of any page in request in the Media subsystem: %9.1f(us)\n"),min);
1.484 + }
1.485 + }
1.486 +
1.487 + test.Printf(_L("Formatting...\n"));
1.488 + silentFormat(DriveNumber);
1.489 + }
1.490 + else
1.491 + test.Next(_L("Read/Write test - Skipped!"));
1.492 +
1.493 + }
1.494 +
1.495 +
1.496 +// ************************************************************************************
1.497 +
1.498 +
1.499 +// This code causes a flush
1.500 +// It is done in a second thread to see if you really do get just
1.501 +// one deferral, with the other page requests just waiting in line.
1.502 +// (Paging is not re-entrant)
1.503 +
1.504 +TInt PagesBeingPaged=0;
1.505 +RMutex PageMutex;
1.506 +RSemaphore PageSemaphore;
1.507 +RSemaphore PageDoneSemaphore;
1.508 +
1.509 +LOCAL_C TInt CausePage(TAny*)
1.510 + {
1.511 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.512 + TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
1.513 + TUint size = romHeader->iPageableRomSize;
1.514 + TUint8* addr=NULL;
1.515 + TBool flush;
1.516 + while (Testing)
1.517 + {
1.518 + PageSemaphore.Wait(); // wait for main thread to want paging.
1.519 + flush = (PagesBeingPaged==0);
1.520 + addr=start+((TInt64(Random())*TInt64(size))>>32);
1.521 + PageDoneSemaphore.Signal(); // Acknolage request.
1.522 +
1.523 + PageMutex.Wait();
1.524 + PagesBeingPaged++;
1.525 + PageMutex.Signal();
1.526 +
1.527 + if (flush)
1.528 + UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
1.529 + READ(addr);
1.530 +
1.531 + PageMutex.Wait();
1.532 + PagesBeingPaged--;
1.533 + PageMutex.Signal();
1.534 + }
1.535 + return 0;
1.536 + }
1.537 +
1.538 +
1.539 +// TestDefered causes garbage collection, and then triggers paging to happen, which should be defered.
1.540 +// One would only expect one defered request, as the paging system is not reentrant, but this is checked.
1.541 +
1.542 +void TestDefered()
1.543 + {
1.544 + if (MaxDeferLoops==0)
1.545 + {
1.546 + test.Next(_L("Defering test - Skipped!"));
1.547 + return;
1.548 + }
1.549 +
1.550 + TInt timeout;
1.551 + TInt writesNeeded=100;
1.552 + TInt r = KErrNone;
1.553 + RFile tempFile;
1.554 + TInt i;
1.555 + TInt ii;
1.556 + TInt runs=0;
1.557 +
1.558 + SDeferStats stats;
1.559 + TInt pageGarbageCount=0;
1.560 + TInt pageOtherCount=0;
1.561 + TInt normalGarbageCount=0;
1.562 + TInt normalOtherCount=0;
1.563 +
1.564 +
1.565 + // Set up thread sync
1.566 + test(PageMutex.CreateLocal()==KErrNone);
1.567 + test(PageSemaphore.CreateLocal(0)==KErrNone);
1.568 + test(PageDoneSemaphore.CreateLocal(0)==KErrNone);
1.569 +
1.570 +
1.571 +
1.572 + const TInt KMaxPageThreads = 2;
1.573 + UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
1.574 + // Set up threads
1.575 + RThread pageThread[KMaxPageThreads];
1.576 + TRequestStatus stat[KMaxPageThreads];
1.577 + Testing=ETrue;
1.578 + for (i=0; i<KMaxPageThreads; i++)
1.579 + {
1.580 + test(pageThread[i].Create(_L(""),CausePage,KDefaultStackSize,NULL,NULL)==KErrNone);
1.581 + pageThread[i].Logon(stat[i]);
1.582 + test(stat[i]==KRequestPending);
1.583 + pageThread[i].SetPriority(EPriorityMore);
1.584 + pageThread[i].Resume();
1.585 + }
1.586 +
1.587 +
1.588 + test.Next(_L("Defering test"));
1.589 +
1.590 + // clear counters
1.591 + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
1.592 + test(Drive.ControlIO(KNandGetDeferStats,statsBuf,0)==KErrNone);
1.593 +
1.594 + CreateFile(tempFile,_L("nandpage.txt"));
1.595 +
1.596 +
1.597 + for (ii=0; ii<MaxDeferLoops; ii++) // Repeat the test, 'MaxDeferLoops' number of times. This can be set on cammand line.
1.598 + {
1.599 + timeout=20;
1.600 + do // while ((pageGarbageCount==0) && (timeout>0));
1.601 + // ie, while garbage collection hasn't happened, or timed out
1.602 + {
1.603 + timeout--;
1.604 + pageGarbageCount=0;
1.605 + pageOtherCount=0;
1.606 + normalGarbageCount=0;
1.607 + normalOtherCount=0;
1.608 +
1.609 + // Give somethng for garbage collector to collect
1.610 + for (i=0; i<writesNeeded; i++)
1.611 + test(WriteNumber(tempFile)==KErrNone);
1.612 +
1.613 + // Force Collection. (Normally only happens in Idle)
1.614 + r = Drive.ControlIO(KNandCollectGarbage,NULL,NULL);
1.615 + test(r==KErrNone);
1.616 +
1.617 + // Since garbage Colleciton should be going now, watch it, until its finished.
1.618 + do
1.619 + {
1.620 + runs = PagesBeingPaged;
1.621 + for (i=runs; i<KMaxPageThreads; i++)
1.622 + PageSemaphore.Signal(); // Trigger Paging.
1.623 +
1.624 + for (i=runs; i<KMaxPageThreads; i++)
1.625 + PageDoneSemaphore.Wait();
1.626 +
1.627 + TInt tries = 10;
1.628 + do { // If we get zero hits, maybe the page hasnt hit yet.
1.629 + tries--;
1.630 + User::AfterHighRes(1000+Random() & 2047); // Throw some uncertainly into things
1.631 +
1.632 + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
1.633 + r = Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
1.634 + test (r == KErrNone);
1.635 + pageGarbageCount+=stats.iPageGarbage;
1.636 + pageOtherCount+=stats.iPageOther;
1.637 + normalGarbageCount+=stats.iNormalGarbage;
1.638 + normalOtherCount+=stats.iNormalOther;
1.639 + } while ((pageGarbageCount==0) && (tries>0)); // If we get zero hits, maybe the page hasnt hit yet
1.640 + }
1.641 + while (stats.iPageGarbage>0); // Keep going until collection seems to have finished.
1.642 +
1.643 + // The paging system is not reentrant, so should never get more then one.
1.644 + test(stats.iPageGarbage<2);
1.645 +
1.646 + test.Printf(_L("%d: PG %d PO %d NG %d NO %d\n"),ii,pageGarbageCount, pageOtherCount, normalGarbageCount, normalOtherCount );
1.647 + // if no collection, probebly didnt write enough to trigger it, so up the quantity.
1.648 + if (pageGarbageCount==0)
1.649 + {
1.650 + writesNeeded+=writesNeeded/2;
1.651 + test.Printf(_L("Writes needed = %d\n"),writesNeeded);
1.652 + }
1.653 +
1.654 + }
1.655 + while ((pageGarbageCount==0) && (timeout>0));
1.656 + test(timeout>0);
1.657 +
1.658 + } // end for MaxDeferLoops.
1.659 +
1.660 + // Clean up. . . . .
1.661 +
1.662 + Testing=EFalse; // Setting this causes the CausePage threads to exit.
1.663 +
1.664 + // Wait for threads to exit, signaling the semaphore in case they where waiting on it.
1.665 + for (i=0; i<KMaxPageThreads; i++)
1.666 + PageSemaphore.Signal();
1.667 + for (i=0; i<KMaxPageThreads; i++)
1.668 + User::WaitForRequest(stat[i]);
1.669 +
1.670 + PageMutex.Close();
1.671 + PageSemaphore.Close();
1.672 + PageDoneSemaphore.Close();
1.673 + CloseAndDestroy(tempFile);
1.674 + }
1.675 +
1.676 +
1.677 +// ************************************************************************************
1.678 +
1.679 +//
1.680 +// The gubbins that starts all the tests
1.681 +//
1.682 +// ParseCommandLine reads the arguments and sets globals accordingly.
1.683 +//
1.684 +
1.685 +void ParseCommandLine()
1.686 + {
1.687 + TBuf<32> args;
1.688 + User::CommandLine(args);
1.689 + TLex lex(args);
1.690 +
1.691 + FOREVER
1.692 + {
1.693 +
1.694 + TPtrC token=lex.NextToken();
1.695 + if(token.Length()!=0)
1.696 + {
1.697 + if ((token.Length()==2) && (token[1]==':'))
1.698 + DriveNumber=User::UpperCase(token[0])-'A';
1.699 + else if (token.Length()==1)
1.700 + {
1.701 + TChar driveLetter = User::UpperCase(token[0]);
1.702 + if ((driveLetter>='A') && (driveLetter<='Z'))
1.703 + DriveNumber=driveLetter - (TChar) 'A';
1.704 + else
1.705 + test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
1.706 + }
1.707 + else if ((token==_L("help")) || (token==_L("-h")) || (token==_L("-?")))
1.708 + {
1.709 + test.Printf(_L("\nUsage: t_nandpaging <driveletter> [rwsoak <cc>] [defer <c>]\n'-' indicated infinity.\n\n"));
1.710 + test.Getch();
1.711 + Maxloops=0;
1.712 + }
1.713 + else if (token==_L("rwsoak"))
1.714 + {
1.715 + TPtrC val=lex.NextToken();
1.716 + TLex lexv(val);
1.717 + TInt v;
1.718 +
1.719 + if (val==_L("-"))
1.720 + Forever=ETrue;
1.721 + else
1.722 + if (lexv.Val(v)==KErrNone)
1.723 + Maxloops=v;
1.724 + else
1.725 + test.Printf(_L("Bad value for rwsoak '%S' was ignored.\n"), &val);
1.726 + }
1.727 + else if (token==_L("defer"))
1.728 + {
1.729 + TPtrC val=lex.NextToken();
1.730 + TLex lexv(val);
1.731 + TInt v;
1.732 +
1.733 + if (val==_L("-"))
1.734 + MaxDeferLoops=KMaxTInt;
1.735 + else
1.736 + if (lexv.Val(v)==KErrNone)
1.737 + MaxDeferLoops=v;
1.738 + else
1.739 + test.Printf(_L("Bad value for defer '%S' was ignored.\n"), &val);
1.740 + }
1.741 + else
1.742 + test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
1.743 + }
1.744 + else
1.745 + break;
1.746 +
1.747 + }
1.748 + }
1.749 +
1.750 +//
1.751 +// E32Main
1.752 +//
1.753 +
1.754 +TInt E32Main()
1.755 + {
1.756 + TInt r;
1.757 + test.Title();
1.758 +
1.759 + test.Printf(_L("key\n---\n"));
1.760 + test.Printf(_L("PG: Paging requests defered due to Garbage\n"));
1.761 + test.Printf(_L("PO: Paging requests defered due to other operations\n"));
1.762 + test.Printf(_L("NG: Normal requests defered due to Garbage\n"));
1.763 + test.Printf(_L("NO: Normal requests defered due to other operations\n\n"));
1.764 +
1.765 +
1.766 + test.Start(_L("Check that the rom is paged"));
1.767 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.768 +
1.769 + if (romHeader->iPageableRomStart==NULL)
1.770 + test.Printf(_L("Test ROM is not paged - test skipped!\r\n"));
1.771 + else
1.772 + {
1.773 + ParseCommandLine();
1.774 + test(TheFs.Connect()==KErrNone);
1.775 +
1.776 + r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
1.777 + if(r<0)
1.778 + {
1.779 + test.Printf(_L("DemandPagingFlushPages Error = %d\n"),r);
1.780 + test(0);
1.781 + }
1.782 +
1.783 + DriveNumber = FindFsNANDDrive();
1.784 +
1.785 + if(DriveNumber<0)
1.786 + test.Printf(_L("NAND Flash not found - test skipped!\r\n"));
1.787 + else
1.788 + {
1.789 + RFile file;
1.790 + TBuf<256> fileName;
1.791 + fileName.Append((TChar)('A'+DriveNumber));
1.792 + fileName+=_L(":\\f32-tst\\");
1.793 + TInt r=TheFs.MkDirAll(fileName);
1.794 + test(r==KErrNone || r== KErrAlreadyExists);
1.795 + fileName += _L("annoyingflies.txt");
1.796 + r=file.Replace(TheFs,fileName,EFileWrite);
1.797 + if (r!=KErrNone)
1.798 + test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
1.799 + test(r==KErrNone);
1.800 + r=file.Write(_L8("Flies as big as sparrows indoletly buzzing in the warm air, heavy with the stench of rotting carcasses"));
1.801 + if (r!=KErrNone)
1.802 + test.Printf(_L("Error %d: could not write to file\n"),r);
1.803 + test(r==KErrNone);
1.804 +
1.805 + test(file.Flush() == KErrNone);
1.806 +
1.807 + SBlockMapInfo info;
1.808 + TInt64 start=0;
1.809 + r=file.BlockMap(info,start, -1,ETestDebug);
1.810 + if (r!=KErrNone && r!=KErrCompletion)
1.811 + test.Printf(_L("Error %d: could not obtain block map\n"),r);
1.812 + test(r==KErrNone || r==KErrCompletion);
1.813 + locDriveNumber=info.iLocalDriveNumber;
1.814 + test.Printf(_L("Found drive: %c (NAND drive %d)\r\n"), DriveNumber+'A',locDriveNumber);
1.815 + file.Close();
1.816 +
1.817 + // Connect to device driver
1.818 + TBool changeFlag = EFalse;
1.819 + r = Drive.Connect(locDriveNumber,changeFlag);
1.820 + TPckg<TLocalDriveCapsV4> capsPack(DriveCaps);
1.821 + Drive.Caps(capsPack);
1.822 + test(r == KErrNone);
1.823 +
1.824 + r = Drive.ControlIO(KNandCollectGarbage,NULL,NULL);
1.825 + if (r!=KErrNone)
1.826 + {
1.827 + test.Printf(_L("LocalDrive does not support the KNandCollectGarbage ControlIO request\n"));
1.828 + CtrlIoCollectGarbageSupported = EFalse;
1.829 + }
1.830 +
1.831 + SDeferStats stats;
1.832 + TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
1.833 + r = Drive.ControlIO(KNandGetDeferStats,statsBuf,0);
1.834 + if (r == KErrNone)
1.835 + {
1.836 + if (stats.iSynchronousMediaDriver)
1.837 + {
1.838 + test.Printf(_L("Media drive is synchronous - test skipped!\r\n"));
1.839 + test.End();
1.840 + return 0;
1.841 + }
1.842 + }
1.843 + else
1.844 + {
1.845 + test.Printf(_L("LocalDrive does not support the KNandGetDeferStats ControlIO request\n"));
1.846 + CtrlIoGetDeferStatsSupported = EFalse;
1.847 + }
1.848 +
1.849 +
1.850 + test.Printf(_L("LocalDrive Connected\n"));
1.851 + //
1.852 + // Run tests
1.853 + //
1.854 + TestNandAccuratcy();
1.855 + if(CtrlIoCollectGarbageSupported && CtrlIoGetDeferStatsSupported)
1.856 + TestDefered();
1.857 + //
1.858 + // Free device and end test program
1.859 + //
1.860 + Drive.Disconnect();
1.861 + }
1.862 + }
1.863 +
1.864 + test.End();
1.865 + return 0;
1.866 + }
1.867 +
1.868 +