First public contribution.
1 // Copyright (c) 1996-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 // f32test\demandpaging\t_fragment.cpp
15 // This test exercises the fragmentation of write requests carried out
16 // by the Local Media subsystem, when the request is for a partition
17 // driven by a Media driver that supports paging.
18 // 002 Check if LFFS drive (Mount LFFS if required)
19 // 003 Testing Fragmentation of writes to writable drives in paging media
20 // 004 Testing concurrent Fragmentation of writes on the same media
25 //! @SYMTestCaseID KBASE-T_FRAGMENTDP-0333
28 //! @SYMTestCaseDesc Demand Paging Page cache fragmentation tests.
29 //! @SYMTestActions 001 Starting tests...
30 //! @SYMTestExpectedResults All tests should pass.
31 //! @SYMTestPriority High
32 //! @SYMTestStatus Implemented
45 // Solve compilation problem caused by non-English locale
46 #pragma setlocale("english")
49 const TInt KMuliplySize=10;
50 const TInt KFileSizeInBytes=302498;
52 LOCAL_D TBuf8<KMuliplySize*KFileSizeInBytes> Buffer;
53 LOCAL_D RSemaphore WriteSemaphore;
55 GLDEF_D RTest test(_L("T_FRAGMENTDP"));
57 void DoTestF(TInt aDrvNum, TBool aNand); // may want to do something weird on NAND later (e.g. trigger Garbage Collection)
58 void DoTestC(TInt aDrvNum, TInt aNotherDrvNum, TBool aNand); // may want to do something weird on NAND later (e.g. trigger Garbage Collection)
59 TInt CreateEmptyFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize);
60 TInt GetLocDrvNumber(TInt aDrvNo);
63 This plain looking test exercises the fragmentation of write requests carried out by the Local
64 Media subsystem, when the request is for a partition driven by a Media driver that supports
66 It indirectly tests that the ELOCD fragmentation and EKERN locking mechanisms work as specified
67 to prevent deadlocks. It also causes an awful lot of paging activity.
70 LOCAL_C TBool TestSimpleFragmentation()
72 // Find ROM address of file and write from it to another file in writable partition in the same media as the backing store for ROM
80 TInt r=TheFs.SessionPath(path);
83 r=RFs::CharToDrive(path[0],drv);
86 test(TheFs.Drive(driveInfo, drv) == KErrNone);
88 //-- select a suitable drive for the testing. It shall be a writable drive on a media that services paging
89 if(driveInfo.iMediaAtt&KMediaAttPageable)
91 TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected; // skip ROFS partitions
94 DoTestF(drv, (driveInfo.iType==EMediaNANDFlash)?(TBool)ETrue:(TBool)EFalse);
99 test.Printf(_L("Skipped T_FRAGMENTDP on drive %c\n"), path[0]);
104 void DoTestF(TInt aDrvNum, TBool aNand)
111 test.Next(_L("Testing Fragmentation of writes to writable drives in paging media"));
113 test.Printf(_L("Testing on NAND\n"));
115 fileName.Format(_L("Testing drive %c:\n"), 'A'+aDrvNum);
116 test.Printf(fileName);
118 _LIT(KTPagedCpp, "Z:\\test\\TEST_PAGED.cpp");
119 _LIT(KTUnpagedCpp, "Z:\\test\\TEST_UNPAGED.CPP");
121 if(TheFs.IsFileInRom(KTPagedCpp) != NULL && TheFs.IsFileInRom(KTUnpagedCpp) != NULL) // .oby must include these files
124 r=f.Open(TheFs,KTUnpagedCpp,EFileStream);
126 r=f.Seek(ESeekAddress,pos);
128 TText8* ptrPos=*(TText8**)&pos; // start address of unpaged file in ROM
129 test.Printf(_L("Start address of section to copy 0x%x\n"), ptrPos);
131 r=f.Size(size); // size of unpaged file
133 size+=((~(size&0xf)&0xf)+1); // adjust for ROM alignement (EABI, 8 bytes)
136 r=f.Open(TheFs,KTPagedCpp,EFileStream);
138 r=f.Size(size1); // size of paged file
140 size1+=((~(size1&0xf)&0xf)+1); // adjust for ROM alignement (EABI, 8 bytes)
144 test.Printf(_L("Set descriptor with size %d (paged+unpaged sections+ROMFS padding)\n"), size);
145 TPtrC8 ptr(ptrPos,size);
147 fileName.Format(_L("%c:\\TestFragFile.bin"), aDrvNum+'A');
148 TheFs.Delete(fileName); //-- just in case
150 test.Printf(_L("Create and open destination file\n"));
151 r = CreateEmptyFile(TheFs, fileName, (size)); // create file to hold both sizes
153 r=f.Open(TheFs,fileName,EFileRead|EFileWrite);
156 test.Printf(_L("Attempt to flush paged section\n"));
157 TInt r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
158 if(r==KErrNotSupported)
159 test.Printf(_L("Not Supported\n"));
161 test.Printf(_L("Write paged and unpaged sections, synchronoulsy\n"));
165 test.Printf(_L("Read back and compare\n"));
167 r=f.Seek(ESeekStart,pos);
169 TUint end=(TUint)ptrPos+(size);
171 TPtrC8 memBuf(ptrPos,1024);
173 while((TUint)ptrPos+1024<end)
177 test(readBuf.Length()==readBuf.MaxLength());
180 test.Printf(_L("Failed on descriptor starting at address %x\n"), ptrPos);
184 memBuf.Set(ptrPos,1024);
188 test(readBuf.Length()==(TInt)(end-(TUint)ptrPos));
189 memBuf.Set(ptrPos,(end-(TUint)ptrPos));
192 test.Printf(_L("Failed on descriptor starting at address %x\n"), ptrPos);
199 test.Printf(_L("Required test files not present\n"));
204 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
205 LOCAL_C TInt ConcurrThread(TAny* aArg);
207 This equally unimpressive looking test further exercises the fragmentation of write requests
208 carried out by the Local Media subsystem. This time write requests where the request source is
209 in paged out ROM are issued concurrently.
210 By having concurrent writes it indirectly tests both page in and fragment deferral mechaninsms.
213 LOCAL_C void TestConcurrentFragmentation()
215 // concurrently write from paged out ROM addresses to either files in separate writebla partitions or different locations in the same partition
216 TDriveList driveList;
217 TDriveInfo driveInfo;
218 TBool concurr=EFalse;
221 TInt r=TheFs.SessionPath(path);
224 r=RFs::CharToDrive(path[0],drvNum);
227 r=TheFs.DriveList(driveList);
230 test(TheFs.Drive(driveInfo, drvNum) == KErrNone);
232 //-- select suitable drives for the testing. They shall be writable drives on a media that services paging
233 if((driveInfo.iMediaAtt&KMediaAttPageable) && !(driveInfo.iMediaAtt&KMediaAttWriteProtected))
235 for (TInt drvNum1=drvNum+1; drvNum1<KMaxDrives; drvNum1++) // if yes search for more drives suitable for concurrent fragmentation
237 if(!driveList[drvNum1])
238 continue; //-- skip unexisting drive
240 TDriveInfo driveInfo2; // for second drive
241 test(TheFs.Drive(driveInfo2, drvNum1) == KErrNone);
242 if ((driveInfo2.iMediaAtt&KMediaAttPageable) &&
243 !(driveInfo2.iMediaAtt&KMediaAttWriteProtected) &&
244 (driveInfo.iType == driveInfo2.iType))
246 DoTestC(drvNum, drvNum1, (driveInfo.iType==EMediaNANDFlash)?(TBool)ETrue:(TBool)EFalse); // test concurrent
252 test.Printf(_L("Skipped concurrent test\n"));
256 void silentFormat(TInt driveNo)
258 TBuf<4> driveBuf=_L("?:\\");
262 driveBuf[0] = (TText)(driveNo + 'A');
264 TInt r = format.Open(TheFs, driveBuf, EHighDensity, count);
269 r=format.Next(count);
277 void DoTestC(TInt aDrvNum, TInt aNotherDrvNum, TBool aNand)
282 TRequestStatus logonStat;
283 RThread concurrThread;
285 TBusLocalDrive drive;
286 TLocalDriveCapsV4 driveCaps;
289 test.Next(_L("Testing concurrent Fragmentation of writes on the same media"));
291 test.Printf(_L("Testing on NAND\n"));
292 test.Printf(_L("Testing on writable drives %c and %c\n"), 'A'+aDrvNum,'A'+aNotherDrvNum);
294 _LIT(KTPagedCpp, "Z:\\test\\TEST_PAGED.cpp");
295 _LIT(KTPaged1Cpp, "Z:\\test\\TEST_PAGED1.cpp");
297 if(TheFs.IsFileInRom(KTPagedCpp) != NULL && TheFs.IsFileInRom(KTPaged1Cpp) != NULL) // .oby must include these files
300 r=f.Open(TheFs,KTPagedCpp,EFileStream); // source 1
302 r=f.Seek(ESeekAddress,pos);
304 TText8* ptrPos=*(TText8**)&pos; // start address of paged file 1 in ROM
305 test.Printf(_L("Main thread->Start address of paged out file 1 0x%x\n"), ptrPos);
306 r=f.Size(size); // size of paged file 1
310 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
311 TUint fsize=Min(KMuliplySize*size,romHeader->iPageableRomSize);
313 test.Printf(_L("Main thread->Set descriptor with size %d to point to paged out file 1 +...\n"), fsize);
314 TPtrC8 ptr(ptrPos,fsize);
316 Buffer.SetLength(fsize);
317 TPtr8 readBuf(&Buffer[0],fsize,fsize);
319 test.Printf(_L("Create and resume concurrent thread\n"));
320 const TInt KHeapSize=0x2000;
322 locDriveNumber = GetLocDrvNumber(aNotherDrvNum);
323 TInt r = concurrThread.Create(_L("ConcurrentWriteThread"),ConcurrThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)locDriveNumber);
325 concurrThread.Logon(logonStat);
327 locDriveNumber = GetLocDrvNumber(aDrvNum);
328 test.Printf(_L("Connect to local drive %d\n"),locDriveNumber);
329 TBool changeFlag = EFalse;
330 r = drive.Connect(locDriveNumber,changeFlag);
331 TPckg<TLocalDriveCapsV4> capsPack(driveCaps);
332 drive.Caps(capsPack);
335 test(WriteSemaphore.CreateLocal(0)==KErrNone);
337 // try to ensure there is no other thread activity as this may prevent the
338 // large write from being pre-empted by the ConcurrentWriteThread
339 test.Printf(_L("Waiting 2 secs for file server threads to quieten down...."));
340 User::After(2000000);
342 concurrThread.Resume();
344 WriteSemaphore.Wait();
345 WriteSemaphore.Signal();
348 // test.Printf(_L("Starting file 1 write\n"));
349 r = drive.Write(0,ptr);
352 test.Printf(_L("Main thread->Write 1 completed\n"));
356 test.Printf(_L("Read stats\n"));
357 TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
358 test(drive.ControlIO(KNandGetDeferStats, statsBuf, 0)==KErrNone);
359 test.Printf(_L("Fragmentation clashes %d Fragmentation deferrals %d Page In deferrals %d Other deferrals %d\n"),stats.iClashFragmenting, stats.iNormalFragmenting, stats.iPageOther, stats.iNormalOther);
362 test.Printf(_L("Read back file 1 and compare\n"));
363 r = drive.Read(0,fsize,readBuf);
366 test.Printf(_L("Verify file 1 OK\n"));
369 WriteSemaphore.Signal();
370 User::WaitForRequest(logonStat);
371 test(logonStat==KErrNone);
372 concurrThread.Close();
373 WriteSemaphore.Close();
375 silentFormat(aDrvNum);
376 silentFormat(aNotherDrvNum);
380 test.Printf(_L("Required test files not present\n"));
387 GLDEF_D RTest testT(_L("T_CONCURRENT_WRITE_THREAD"));
389 LOCAL_C TInt ConcurrThread(TAny* aArg)
391 // the whole test is dodgy and hangs if this thread fails an assert,
392 // so at least make sure thread panic takes out whole test process...
393 User::SetCritical(User::EProcessCritical);
399 TBusLocalDrive drive;
400 TLocalDriveCapsV4 driveCaps;
404 TInt r = TheFsT.Connect();
405 _LIT(KTPaged1Cpp, "Z:\\test\\TEST_PAGED1.cpp");
406 r=f.Open(TheFsT,KTPaged1Cpp,EFileStream); // source 2
408 r=f.Seek(ESeekAddress,pos);
410 TText8* ptrPos=*(TText8**)&pos; // start address of paged file 2 in ROM
411 testT.Printf(_L("ConcurrThread->Start address of paged out file 2 0x%x\n"), ptrPos);
412 r=f.Size(size); // size of paged file 2
416 testT.Printf(_L("ConcurrThread->Set descriptor with size %d to point to paged out file 2\n"), size);
417 TPtrC8 ptr(ptrPos,size);
419 TPtr8 readBuf(&Buffer[0],size,size);
421 locDriveNumber = (TInt)aArg;
422 testT.Printf(_L("Connect to local drive %d\n"),locDriveNumber);
423 TBool changeFlag = EFalse;
424 r = drive.Connect(locDriveNumber,changeFlag);
425 TPckg<TLocalDriveCapsV4> capsPack(driveCaps);
426 drive.Caps(capsPack);
427 testT(r == KErrNone);
429 if (driveCaps.iType == EMediaNANDFlash)
431 testT.Printf(_L("Zero stats\n"));
432 TPtr8 statsBuf((TUint8*) &stats, sizeof(stats));
433 testT(drive.ControlIO(KNandGetDeferStats, statsBuf, 0)==KErrNone);
436 r=UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
437 if(r==KErrNotSupported)
438 testT.Printf(_L("ConcurrThread->Flushing of paging not Supported\n"));
440 // pause one second to make sure main thread has executed WriteSemaphore.Wait();
441 User::After(1000000);
443 WriteSemaphore.Signal();
444 WriteSemaphore.Wait();
446 thisThread.SetPriority(EPriorityMore);
448 // wait a very short time to give the other thread a better chance to initiate the write
450 // testT.Printf(_L("Starting file 2 write\n"));
453 r = drive.Write(0,ptr);
456 r = drive.Read(0,size,readBuf);
459 r=drive.Format(0,size);
462 testT.Printf(_L("ConcurrThread->Write of file 2 completed\n"));
464 WriteSemaphore.Wait();
465 testT.Printf(_L("Read back file 2 and compare\n"));
467 testT.Printf(_L("Verify file 2 OK\n"));
474 #endif // #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
476 //--------------------------------------------------------
479 Create an empty file of specified size.
480 @param aFs ref. to the FS
481 @param aFileName name of the file
482 @param aFileSize size of the file to be created
483 @return KErrNone on success, system-wide error code otherwise
485 TInt CreateEmptyFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize)
490 nRes = file.Create(aFs, aFileName, EFileWrite);
494 nRes = file.SetSize(aFileSize);
503 TInt GetLocDrvNumber(TInt aDrvNo)
505 test.Printf(_L("GetLocDrvNumber\r\n"));
509 fileName.Append((TChar)('A'+aDrvNo));
510 fileName+=_L(":\\f32-tst\\");
511 TInt r=TheFs.MkDirAll(fileName);
512 test(r==KErrNone || r== KErrAlreadyExists);
513 fileName += _L("maggots.txt");
514 r=file.Replace(TheFs,fileName,EFileWrite|EFileWriteDirectIO);
516 test.Printf(_L("Error %d: file '%S' could not be created\n"),r,&fileName);
518 r=file.Write(_L8("Writhing bundles of maggots, this was truly their finest hour"));
520 test.Printf(_L("Error %d: could not write to file\n"),r);
525 r=file.BlockMap(info,start, -1,ETestDebug);
526 if (r!=KErrNone && r!=KErrCompletion)
527 test.Printf(_L("Error %d: could not obtain block map\n"),r);
528 test(r==KErrNone || r==KErrCompletion);
529 locDriveNumber=info.iLocalDriveNumber;
530 test.Printf(_L("From drive: %c to Local drive %d\r\n"), aDrvNo+'A',locDriveNumber);
532 return locDriveNumber;
535 GLDEF_C void CallTestsL()
537 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
538 if(!romHeader->iPageableRomStart)
540 test.Printf(_L("Test not supported (not a paged ROM)\n"));
541 return; // Not a paged ROM, skip test
545 TBool r=TestSimpleFragmentation();
548 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
549 TestConcurrentFragmentation();