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