First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\mmu\t_mmcpaging.cpp
15 // Suite of tests specifically to test the demand paging subsystem when
16 // booted from MMC rather than NAND.
17 // 002 Read/Write and Page test
21 //! @SYMTestCaseID KBASE-T_MMCPAGING-0331
24 //! @SYMTestCaseDesc Demand Paging MMC Paging tests.
25 //! @SYMTestActions 001 Check that the rom is paged
26 //! @SYMTestExpectedResults All tests should pass.
27 //! @SYMTestPriority High
28 //! @SYMTestStatus Implemented
31 RTest test(_L("T_MMCPAGING"));
40 #define __TEST_PAGING_MEDIA_DRIVER__
45 TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect.
48 TInt MaxDeferLoops=40; // Parameter - Defer test, for how long?
49 TInt Maxloops=400; // Parameter - RW Soak, for how long?
50 TBool Forever=EFalse; // Parameter - RW Soak forever?
52 TBool Testing=ETrue; // Used to communicate when testing has finished between threads.
56 TLocalDriveCapsV4 DriveCaps;
58 TInt PagedTrashCount=0; // Incremented by threads, is used to detect preemption.
59 TInt GlobError=KErrNone; // To communicate an error between threads.
60 TBool CtrlIOSupported=ETrue;
63 //const TInt KDiskSectorShift = 9;
64 const TInt KBufSizeInBytes = (32 * 1024);
66 LOCAL_D TBuf8<KBufSizeInBytes> Buffer;
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.
75 void CreateFile(RFile &aFile,const TDesC& aFileName)
78 fileName.Append((TChar)('A'+DriveNumber));
79 fileName+=_L(":\\f32-tst\\");
80 TInt r=TheFs.MkDirAll(fileName);
81 test(r==KErrNone || r== KErrAlreadyExists);
83 fileName += aFileName;
85 r=aFile.Replace(TheFs,fileName,EFileWrite);
87 test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
92 void CloseAndDestroy(RFile &aFile)
95 aFile.FullName(fileName);
97 TheFs.Delete(fileName);
100 TInt WriteNumber(RFile &aFile)
104 r = aFile.Write(0,Buffer);
106 return aFile.Flush();
113 // Finds the 1st MMC drive, or checks the specified one fits requirements
115 static TInt FindFsMMCDrive()
117 TDriveList driveList;
118 TDriveInfo driveInfo;
119 TInt r=TheFs.DriveList(driveList);
122 TInt drvNum = DriveNumber;
127 if(!driveList[drvNum])
128 continue; //-- skip unexisting drive
130 test(TheFs.Drive(driveInfo, drvNum) == KErrNone);
132 if(driveInfo.iMediaAtt&KMediaAttPageable)
135 if (driveInfo.iType == EMediaHardDisk &&
136 (driveInfo.iDriveAtt & KDriveAttInternal) &&
137 (!(driveInfo.iDriveAtt & KDriveAttRemovable)))
141 while(DriveNumber<0 && ++drvNum<KMaxDrives);
148 // Writes to main area for the entire disk and reads back to verify.
149 // The function is called from TestMmcAccuratcy, which will have also
150 // started the background RepeatedPagingThread
157 TInt totChangeCount=0;
160 TInt oldPagedTrashCount=0;
169 TInt reqNormalCount=0;
172 TInt readSize = KBufSizeInBytes/2;
173 TInt writeSize = KBufSizeInBytes/2;
175 Buffer.SetLength(2*readSize);
177 TPtr8 subBuf1(&Buffer[0],readSize);
178 TPtrC8 subBuf2(&Buffer[readSize], readSize);
180 test.Printf(_L("writeSize = %d\n"), writeSize);
182 // TInt64 size = DriveCaps.iSize - (DriveCaps.iSize % readSize);
184 for(i = 0; i<readSize; i++)
185 Buffer[readSize+i] = (char)(i%100);
190 TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
191 test(Drive.ControlIO(KMmcGetStats,statsBuf,0) == KErrNone);
195 TFileName fileName = _L("?:\\f32-tst\\mmcpage.txt");
196 fileName[0] = (TText) ('A'+DriveNumber);
199 r = TheFs.MkDirAll(fileName);
200 test(r==KErrNone || r== KErrAlreadyExists);
201 // fileName += KTempFileName;
203 r=tempFile.Replace(TheFs,fileName,EFileWrite);
205 test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
209 r = TheFs.Volume(volInfo, DriveNumber);
210 test (r == KErrNone);
213 TInt64 size = volInfo.iFree - (volInfo.iFree % readSize);
214 TInt maxFileSize = (size > KMaxTInt) ? KMaxTInt : (TInt) size;
216 test.Printf(_L("Volume size %ld, free %ld maxFileSize %d file '%S'\n"), volInfo.iSize, volInfo.iFree, maxFileSize, &fileName);
218 while (((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone))
222 ((pos+writeSize) < maxFileSize) && ((totChangeCount<Maxloops) || Forever) && (GlobError==KErrNone);
223 pos+=(TUint)(readSize))
225 blockNo=I64LOW(pos / writeSize);
226 if (pos % (writeSize) == 0)
227 test.Printf(_L("Block %d at %u \r"), blockNo, I64LOW(pos));
230 r = tempFile.Write(pos,subBuf2);
232 test.Printf(_L("Write failed %d"), r);
235 //read back and verify
236 r = tempFile.Read(pos,subBuf1,readSize);
239 for(i=0;i<readSize;i++)
240 if(Buffer[i]!=Buffer[readSize+i])
245 delta = PagedTrashCount-oldPagedTrashCount;
253 oldPagedTrashCount=PagedTrashCount;
256 if (pos % (writeSize) == 0)
259 if ((blockNo%80==0) && (blockNo!=0))
261 totChangeCount+=changeCount;
264 test.Printf(_L("High%4d Avg%2d %d%% CC=%4d \n"), high, (TInt) (tot/cCount), (TInt)(changeCount*100)/cCount, totChangeCount);
266 TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
267 Drive.ControlIO(KMmcGetStats,statsBuf,0);
268 test.Printf(_L("PR %d(%d%%) NR %d\n"), stats.iReqPage, (TInt) ((stats.iReqPage*100)/cCount), stats.iReqNormal);
270 test(stats.iReqPage>0);
271 reqPageCount+=stats.iReqPage;
272 reqNormalCount+=stats.iReqNormal;
290 test.Printf(_L("Totals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount);
291 test.Printf(_L("PR %d(%d%%) NR %d\n"), reqPageCount,(TInt) (reqPageCount*100/fullcCount), reqNormalCount );
294 // If totChangeCount does not change, mmc maybe busy waiting.
295 test(totChangeCount>0);
300 r = TheFs.Delete(fileName);
301 test (r == KErrNone);
303 if (GlobError!=KErrNone)
305 test.Printf(_L("\nPageing failed with %x\n"), GlobError);
309 test.Printf(_L("\ndone\n"));
313 TUint8 ReadByte(volatile TUint8* aPtr)
318 #define READ(a) ReadByte((volatile TUint8*)(a))
324 RandomNo = RandomNo*69069+1;
329 // Many instances of this run while testWriteMain runs,
330 // to cause random background paging.
332 LOCAL_C TInt RepeatedPagingThread(TAny* aUseTb)
334 // RTest test(_L("RepeatedPagingThread"));
335 TBool trashBurst = EFalse;
336 // This makes the paging system continually page stuff.
337 // get info about a paged ROM...
339 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
340 TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
341 TUint size = romHeader->iPageableRomSize;
345 UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0);
351 TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
353 User::AfterHighRes(500+Random() & 2047);
363 if ((Random() & 0xf) == 0xf)
370 for(TInt i=size/(pageSize); (i>0) && !trashBurst; --i)
372 READ(start+((TInt64(Random())*TInt64(size))>>32));
373 if ((RandomNo & 0x3f) == 0x3f)
375 trashBurst= (TBool) aUseTb;
379 User::AfterHighRes(500+Random() & 2047);
388 // This starts up multiple instances of repeatedPagingThread, and runs testWriteMain.
389 // After its done, it calls format, to clean up the drive.
391 void TestMmcAccuratcy()
394 const TInt KNoThreads=10;
396 test.Printf(_L("Reset stats\n"));
398 i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetConcurrencyInfo,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
399 test(i==KErrNone || i==KErrNotSupported);
400 if(i==KErrNotSupported)
401 test.Printf(_L("Concurrency stats not supported on this build\n"));
402 i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalResetPagingBenchmark,(TAny*)locDriveNumber,(TAny*)EMediaPagingStatsRom);
403 test(i==KErrNone || i==KErrNotSupported);
404 if(i==KErrNotSupported)
405 test.Printf(_L("Benchmark stats not supported on this build\n"));
409 TRequestStatus stat[KNoThreads];
411 RThread repeatedPagingThread[KNoThreads];
413 test.Next(_L("Read/Write and Page test"));
415 for (i=0; i<KNoThreads; i++)
417 test(repeatedPagingThread[i].Create(_L(""),RepeatedPagingThread,KDefaultStackSize,NULL,(TAny*) ETrue)==KErrNone);
418 repeatedPagingThread[i].Logon(stat[i]);
419 test(stat[i]==KRequestPending);
420 repeatedPagingThread[i].Resume();
422 // Start repeated paging.
423 thisThread.SetPriority(EPriorityMore);
427 thisThread.SetPriority(EPriorityNormal);
428 for (i=0; i<KNoThreads; i++)
429 User::WaitForRequest(stat[i]);
431 test.Printf(_L("Collect concurrency stats\n"));
432 SMediaROMPagingConcurrencyInfo info;
433 SPagingBenchmarkInfo infoBench;
434 i=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMConcurrencyInfo,(TAny*)locDriveNumber,&info);
435 test(i==KErrNone || i==KErrNotSupported);
436 TInt r=UserSvr::HalFunction(EHalGroupMedia,EMediaHalGetROMPagingBenchmark,(TAny*)locDriveNumber,&infoBench);
437 test(r==KErrNone || r==KErrNotSupported);
440 test.Printf(_L("Media concurrency stats:\n\n"));
441 test.Printf(_L("The total number of page in requests issued whilst processing other page in requests: %d\n"),info.iTotalConcurrentReqs);
442 test.Printf(_L("The total number of page in requests issued with at least one queue not empty: %d\n"),info.iTotalReqIssuedNonEmptyQ);
443 test.Printf(_L("The maximum number of pending page in requests in the main queue any time during this session: %d\n"),info.iMaxReqsInPending);
444 test.Printf(_L("The maximum number of pending page in requests in the deferred queue any time during this session: %d\n"),info.iMaxReqsInDeferred);
445 test.Printf(_L("The total number of page in requests first-time deferred during this session: %d\n"),info.iTotalFirstTimeDeferrals);
446 test.Printf(_L("The total number of page in requests re-deferred during this session: %d\n"),info.iTotalReDeferrals);
447 test.Printf(_L("The maximum number of deferrals of any single page in request during this session: %d\n"),info.iMaxDeferrals);
448 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);
449 test.Printf(_L("The total number of page in requests serviced from main queue when completing an asynchronous request: %d\n"),info.iTotalSynchServicedFromMainQ);
450 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);
451 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);
452 test.Printf(_L("The total number of dry runs of paging DFC avoided during this session: %d\n"),info.iTotalDryRunsAvoided);
458 r = HAL::Get(HAL::EFastCounterFrequency, freq);
461 TReal mult = 1000000.0 / freq;
465 if (infoBench.iCount != 0)
467 min = infoBench.iMinTime * mult;
468 max = infoBench.iMaxTime * mult;
469 avg = (infoBench.iTotalTime * mult) / infoBench.iCount;
471 test.Printf(_L("Media benchmarks:\n\n"));
472 test.Printf(_L("The total number of page in requests issued: %d\n"),infoBench.iCount);
473 test.Printf(_L("The average latency of any page in request in the Media subsystem: %9.1f(us)\n"),avg);
474 test.Printf(_L("The maximum latency of any page in request in the Media subsystem: %9.1f(us)\n"),max);
475 test.Printf(_L("The minimum latency of any page in request in the Media subsystem: %9.1f(us)\n"),min);
480 test.Next(_L("Read/Write test - Skipped!"));
485 // ************************************************************************************
489 // This code causes a flush
490 // It is done in a second thread to see if you really do get just
491 // one deferral, with the other page requests just waiting in line.
492 // (Paging is not re-entrant)
494 TInt PagesBeingPaged=0;
496 RSemaphore PageSemaphore;
497 RSemaphore PageDoneSemaphore;
499 LOCAL_C TInt CausePage(TAny*)
501 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
502 TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
503 TUint size = romHeader->iPageableRomSize;
509 PageSemaphore.Wait();
510 flush = (PagesBeingPaged==0);
512 addr=start+((TInt64(Random())*TInt64(size))>>32);
513 PageDoneSemaphore.Signal();
515 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
525 // ************************************************************************************
528 // The gubbins that starts all the tests
530 // ParseCommandLine reads the arguments and sets globals accordingly.
533 void ParseCommandLine()
536 User::CommandLine(args);
542 TPtrC token=lex.NextToken();
543 if(token.Length()!=0)
545 if ((token.Length()==2) && (token[1]==':'))
546 DriveNumber=User::UpperCase(token[0])-'A';
547 else if (token.Length()==1)
549 TChar driveLetter = User::UpperCase(token[0]);
550 if ((driveLetter>='A') && (driveLetter<='Z'))
551 DriveNumber=driveLetter - (TChar) 'A';
553 test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
555 else if ((token==_L("help")) || (token==_L("-h")) || (token==_L("-?")))
557 test.Printf(_L("\nUsage: t_mmcpaging <driveletter> [rwsoak <cc>] [defer <c>]\n'-' indicated infinity.\n\n"));
561 else if (token==_L("rwsoak"))
563 TPtrC val=lex.NextToken();
570 if (lexv.Val(v)==KErrNone)
573 test.Printf(_L("Bad value for rwsoak '%S' was ignored.\n"), &val);
575 else if (token==_L("defer"))
577 TPtrC val=lex.NextToken();
582 MaxDeferLoops=KMaxTInt;
584 if (lexv.Val(v)==KErrNone)
587 test.Printf(_L("Bad value for defer '%S' was ignored.\n"), &val);
590 test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
607 test.Printf(_L("key\n---\n"));
608 test.Printf(_L("PR: Paging requests\n"));
609 test.Printf(_L("NR: Normal requests\n\n"));
612 test.Start(_L("Check that the rom is paged"));
613 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
614 if (romHeader->iPageableRomStart==NULL)
615 test.Printf(_L("Test ROM is not paged - test skipped!\r\n"));
619 test(TheFs.Connect()==KErrNone);
621 r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
624 test.Printf(_L("DemandPagingFlushPages Error = %d\n"),r);
628 DriveNumber = FindFsMMCDrive();
631 test.Printf(_L("MMC Flash not found - test skipped!\r\n"));
636 fileName.Append((TChar)('A'+DriveNumber));
637 fileName+=_L(":\\f32-tst\\");
638 TInt r=TheFs.MkDirAll(fileName);
639 test(r==KErrNone || r== KErrAlreadyExists);
640 fileName += _L("redglare.txt");
641 r=file.Replace(TheFs,fileName,EFileWrite);
643 test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
645 r=file.Write(_L8("The red glare of an ancient sun reflecting on the leaden surface of a primeval soup of decomposing matter"));
647 test.Printf(_L("Error %d: could not write to file\n"),r);
650 test(file.Flush() == KErrNone);
654 r=file.BlockMap(info,start, -1,ETestDebug);
655 if (r!=KErrNone && r!=KErrCompletion)
656 test.Printf(_L("Error %d: could not obtain block map\n"),r);
657 test(r==KErrNone || r==KErrCompletion);
658 locDriveNumber=info.iLocalDriveNumber;
659 test.Printf(_L("Found drive: %c (MMC drive %d)\r\n"), DriveNumber+'A',locDriveNumber);
662 TDriveInfo driveInfo;
663 test(TheFs.Drive(driveInfo, DriveNumber) == KErrNone);
665 // Connect to device driver
666 TBool changeFlag = EFalse;
667 r = Drive.Connect(locDriveNumber,changeFlag);
668 TPckg<TLocalDriveCapsV4> capsPack(DriveCaps);
669 Drive.Caps(capsPack);
673 TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
674 r = Drive.ControlIO(KMmcGetStats,statsBuf,0);
679 test.Printf(_L("LocalDrive does not support testing IO Requests\n"));
680 CtrlIOSupported=EFalse;
682 test.Printf(_L("LocalDrive Connected\n"));
688 // Free device and end test program