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 // f32test\server\t_rcache.cpp
22 #define __E32TEST_EXTENSION__
27 #include <e32const_private.h>
35 const TInt KTotalCacheSize = 32 * 1024 * 1024;
36 const TInt KDefaultCacheSize = (128 + 12) * 1024;
37 const TInt KFilesNeededToFillCache = (KTotalCacheSize / KDefaultCacheSize) + 2;
40 //----------------------------------------------------------------------------------------------
41 //! @SYMTestCaseID PBASE-T_RCACHE-0190
44 //! @SYMTestCaseDesc This test case is exercising the Read Caching functionality added to
45 //! the File Server. There are negative and positive tests.
46 //! @SYMTestActions 0 setup the environment to execute the tests
47 //! 1 TestNegative creates situations where the cached content needs to be
48 //! flushed or removed from the cache by corrupting files and verifies
49 //! the cache behaviour
50 //! 2 TestSimpleRead ensures that the cache is working in the simple cases,
51 //! with a combination of sync and async reads:
52 //! a. The file fits in the cache
53 //! b. The file doesn't fit in the cache
54 //! 3 TestRepeatedRead verifies the cache behaviour when a file is read an
55 //! arbitrary number of times, with and without other operations ongoing
56 //! 4 TestReadAhead reads 3 times from a file and verifies that the read
57 //! ahead functionality acts afterwards.
58 //! 5 TestConcurrent reads files concurrently and verifies how the cache
60 //! 6 TestFillCache fills the cache and then executes TestSimpleRead.
62 //! @SYMTestExpectedResults finishes if the read cache behaves as expected, panics otherwise
63 //! @SYMTestPriority High
64 //! @SYMTestStatus Implemented
65 //----------------------------------------------------------------------------------------------
68 ////////////////////////////////////////////////////////////
69 // Template functions encapsulating ControlIo magic
71 GLDEF_D template <class C>
72 GLDEF_C TInt controlIo(RFs &fs, TInt drv, TInt fkn, C &c)
74 TPtr8 ptrC((TUint8 *)&c, sizeof(C), sizeof(C));
76 TInt r = fs.ControlIo(drv, fkn, ptrC);
81 GLDEF_D RTest test(_L("T_RCACHE"));
85 GLDEF_D TFileName gSessionPath;
86 GLDEF_D TChar gDriveToTest;
87 TThreadId gMainThreadId;
89 LOCAL_D HBufC8* gBuf = NULL;
90 LOCAL_D TPtr8 gBufReadPtr(NULL, 0);
91 LOCAL_D HBufC8* gBufSec = NULL;
92 LOCAL_D TPtr8 gBufWritePtr(NULL, 0);
94 LOCAL_D const TInt KOneK = 1024;
95 LOCAL_D const TInt KOneMeg = KOneK * 1024;
96 LOCAL_D const TInt KBlockSize = KOneK;
97 LOCAL_D const TInt KWaitRequestsTableSize = 256;
99 LOCAL_D TInt gSecondFileSize = 0;
100 LOCAL_D TInt gFirstFileSize = 0;
101 LOCAL_D TInt gCurrentFileSize = 0;
103 LOCAL_D TInt64 gMediaSize = 0;
105 LOCAL_D TTimeIntervalMicroSeconds gTimeTakenBigFile(0);
106 LOCAL_D TBuf16<25> gFirstFile;
107 LOCAL_D TBuf16<25> gSecondFile;
108 LOCAL_D TBuf16<25> gCurrentFile;
110 LOCAL_D TInt gNextFile = 0;
111 LOCAL_D TTime gTime1;
112 LOCAL_D TTime gTime2;
113 _LIT(KMsg1, "1st read timing: %d\n");
114 _LIT(KMsg2, "2nd read timing: %d\n");
115 _LIT(KMsg3, "3rd read timing: %d\n");
117 LOCAL_D RSemaphore gSync;
119 // Concurrent Threads
120 LOCAL_D RThread gThread1;
121 LOCAL_D RThread gThread2;
122 LOCAL_D RSemaphore client;
123 LOCAL_D const TInt KHeapSize = 0x4000;
124 LOCAL_D const TInt KMaxHeapSize = 0x100000;
125 LOCAL_D TBool gPagedRom = EFalse;
134 /** Formats the drive
136 @param aDrive Drive to be formatted
137 @param aFormatMode Mode for the format operation
139 LOCAL_C void Formatting(TInt aDrive, TUint aFormatMode )
142 test.Next(_L("Format"));
143 TBuf<4> driveBuf = _L("?:\\");
144 driveBuf[0]=(TText)(aDrive+'A');
147 TInt r = format.Open(TheFs,driveBuf,aFormatMode,count);
151 TInt r = format.Next(count);
157 /** Verifies the content of a buffer (all the letters are like the first one)
159 @param aBuffer Buffer to be verified
161 @return KErrNone if all the letters are the same, KErrCorrupt otherwise
163 LOCAL_C TInt VerifyBuffer(TDes8& aBuffer)
165 TChar c = aBuffer[0];
167 for(TInt i = 1; i < aBuffer.Length(); i++)
171 if(c != (TChar)(aBuffer[i] - 1))
176 if(aBuffer[i] != aBuffer[0])
185 /** Fills a buffer with character aC, aC+1, aC+2, ..., aC+20, aC, etc
187 @param aBuffer Buffer to be filled, output
188 @param aLength Length to be filled
189 @param aC Character to be used to fill the buffer
191 LOCAL_C void FillBuffer(TDes8& aBuffer, TInt aLength, TChar aC)
193 test (aBuffer.MaxLength() >= aLength);
194 for(TInt i = 0; i < aLength; i++)
196 aBuffer.Append((i%32) + aC);
200 /** Returns true if fat filesystem present on aDrive
202 @param aFsSession Session on the File Server
203 @param aDrive Drive to be looked at
205 LOCAL_C TBool IsFSFAT(RFs &aFsSession,TInt aDrive)
208 TInt r = aFsSession.FileSystemName(f,aDrive);
212 test.Printf(_L("Unable to get file system name\n"));
216 return (f.CompareF(_L("Fat")) == 0);
219 /** Generates a file name of the form FFFFF*<aPos>.TXT (aLong.3)
221 @param aBuffer The filename will be returned here
222 @param aLong Defines the longitude of the file name
223 @param aPos Defines the number that will be attached to the filename
225 GLDEF_C void FileNameGen(TDes16& aBuffer, TInt aLong, TInt aPos)
232 tempbuf.Format(KNumber,aPos);
233 padding = aLong-tempbuf.Size()/2;
240 aBuffer.Append(tempbuf);
242 _LIT(KExtension1, ".TXT");
243 aBuffer.Append(KExtension1);
246 /** Delete content of directory
248 @param aDir Target directory
250 @return Error returned if any, otherwise KErrNone
252 LOCAL_C TInt DeleteAll(TDes16& aDir)
255 CFileMan* fMan = CFileMan::NewL(TheFs);
259 dir.Append(_L("F*.*"));
260 r = fMan->Delete(dir);
266 /** Waits for all the TRequestStatus in status[] to complete
268 @param status Array of TRequestStatus
269 @param aLength Length to be filled
270 @param aC Character to be used to fill the buffer
272 LOCAL_C void WaitForAll(TRequestStatus* status, TInt aSize)
276 RTest test(_L("T_RCACHE"));
280 User::WaitForRequest(status[i]);
281 test(status[i] == KErrNone);
288 /** Reads the parameters from the comand line
289 and updates the appropriate variables
291 LOCAL_C void parseCommandLine()
294 User::CommandLine(cmd);
296 TPtrC token = lex.NextToken();
299 if(token.Length() != 0)
301 gDriveToTest = token[0];
302 gDriveToTest.UpperCase();
309 r = TheFs.CharToDrive(gDriveToTest,gDrive);
311 gSessionPath = _L("?:\\F32-TST\\");
312 gSessionPath[0] = (TUint16) gDriveToTest;
313 test.Printf(_L("\nCLP=%C\n"),(TInt)gDriveToTest);
316 /** Writes a file synchronously in blocks of aBlockSize size
319 @param aFile File name
320 @param aSize Size of the file in bytes
321 @param aBlockSize Size of the blocks to be used in bytes
322 @param aState Determines if the operation is being done in the main process
324 @param aReadBack Reads the file back if ETrue. This is used for Read-ahead testing to ensure
325 what is written is also read back through the media driver's cache. If the
326 file is bigger than the cache, then subsequent streaming reads starting from
327 position zero will have to be re-read from the media.
329 @return Returns KErrNone if everything ok, otherwise it panics
331 LOCAL_C TInt WriteFile(RFs& fs, TDes16& aFile, TInt aSize, TInt aBlockSize, TDes8& aBuf, TTestState aState, TBool aReadBack = EFalse)
333 RTest test(_L("T_RCACHE"));
340 test((aSize%aBlockSize) == 0); // Ensure the size of the file is a multiple of the block size
342 if(aState == EThreadWait)
347 // delete file first to ensure it's contents are not in the cache (file may be be on the closed file queue)
348 r = fs.Delete(aFile);
349 test_Value(r, r == KErrNone || r == KErrNotFound);
351 r = fileWrite.Replace(fs,aFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
357 r = fileWrite.Write(pos, aBuf);
362 r = fileWrite.Read(pos, aBuf);
366 if((j>(aSize/2))&&(aState == EThreadSignal))
380 /** Read File in blocks of size aBlockSize
383 @param aFile File name
384 @param aBlockSize Size of the blocks to be used in bytes
386 @return Returns KErrNone if everything ok, otherwise it panics
388 LOCAL_C TInt ReadFile(RFs& fs, TDes16& aFile, TInt aBlockSize)
390 RTest test(_L("T_RCACHE"));
392 TInt r = 0, size = 0;
395 test(aBlockSize>0); // Block size must be greater than 0
397 r = fileRead.Open(fs,aFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOff);
400 r = fileRead.Size(size);
406 r = fileRead.Read(gBufReadPtr, aBlockSize);
416 /** Write a file asynchronously in blocks of aBlockSize size
419 @param aFileWrite RFile object, needs to exist beyond the scope of this function
420 @param aFile File name
421 @param aSize Size of the file in bytes
422 @param aBlockSize Size of the blocks to be used in bytes
423 @param aStatus TRequestStatus array for all the requests
425 LOCAL_C void WriteFileAsync(RFs& fs, RFile& aFileWrite, TDes16& aFile, TInt aSize, TInt aBlockSize, TRequestStatus aStatus[])
427 RTest test(_L("T_RCACHE"));
432 test((aSize%aBlockSize) == 0); // Ensure the size of the file is a multiple of the block size
435 // delete file first to ensure it's contents are not in the cache (file may be be on the closed file queue)
436 r = fs.Delete(aFile);
437 test(r == KErrNone || r == KErrNotFound);
439 r = aFileWrite.Replace(fs,aFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
445 aFileWrite.Write(gBufWritePtr,aStatus[i]);
446 r = aStatus[i].Int();
447 if (r != KErrNone && r != KRequestPending)
449 test.Printf(_L("Write %d returned %d\n"), i, r);
459 /** Read a file asynchronously in blocks of aBlockSize size
462 @param aFileRead RFile object, needs to exist beyond the scope of this function
463 @param aFile File name
464 @param aSize Size of the file in bytes
465 @param aBlockSize Size of the blocks to be used in bytes
466 @param aStatus TRequestStatus array for all the requests
470 LOCAL_C TInt ReadFileAsync(RFs& fs,RFile& aFileRead, TDes16& aFile, TInt aBlockSize,TRequestStatus aStatus[], TInt aFileSize)
472 RTest test(_L("T_RCACHE"));
477 test(aBlockSize > 0);
479 r = aFileRead.Open(fs,aFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOff);
482 r = aFileRead.Size(size);
485 test(size == aFileSize);
490 aFileRead.Read(gBufReadPtr,aStatus[i]);
491 r = aStatus[i].Int();
492 if (r != KErrNone && r != KRequestPending)
494 test.Printf(_L("Read %d returned %d\n"), i, r);
506 /** Measure the time taken for this file to be written synchronously
508 LOCAL_C TInt WriteTestFile(TDes16& aFile, TInt aSize, TBool aReadBack = EFalse)
510 RTest test(_L("T_RCACHE"));
516 startTime.HomeTime();
518 r = WriteFile(TheFs,aFile, aSize, KBlockSize, gBufWritePtr, ENoThreads, aReadBack);
523 gTimeTakenBigFile = I64LOW(endTime.MicroSecondsFrom(startTime).Int64());
526 return I64LOW(gTimeTakenBigFile.Int64()) / 1000;
529 /** Measure the time taken for this file to be read synchronously
531 LOCAL_C TInt ReadTestFile(TDes16& aFile)
536 startTime.HomeTime();
537 ReadFile(TheFs,aFile, KBlockSize);
540 gTimeTakenBigFile = I64LOW(endTime.MicroSecondsFrom(startTime).Int64());
542 return I64LOW(gTimeTakenBigFile.Int64()) / 1000;
545 /** Read asynchronously the test file from the disc
548 LOCAL_C TInt ReadAsyncTestFile(TDes16& aFile, TInt aSize)
550 RTest test(_L("T_RCACHE"));
554 TRequestStatus status[KWaitRequestsTableSize];
558 TInt r = fs.Connect();
559 test (r == KErrNone);
561 startTime.HomeTime();
563 ReadFileAsync(fs, file, aFile, KBlockSize, status, aSize);
564 WaitForAll(status, aSize/KBlockSize);
568 gTimeTakenBigFile = I64LOW(endTime.MicroSecondsFrom(startTime).Int64());
573 return I64LOW(gTimeTakenBigFile.Int64()) / 1000;
576 /** Write a file for the simple case
579 LOCAL_C TInt WriteFileT(TAny* )
581 RTest test(_L("T_RCACHE"));
583 TInt r = fs.Connect();
586 r = fs.SetSessionPath(gSessionPath);
590 r = WriteFile(fs,gCurrentFile,gCurrentFileSize, KBlockSize,gBufWritePtr, ENoThreads);
598 gTimeTakenBigFile = I64LOW(gTime2.MicroSecondsFrom(gTime1).Int64());
605 /** Write a file for the concurrent case
608 LOCAL_C TInt WriteFileT2(TAny* )
610 RTest test(_L("T_RCACHE"));
612 TInt r = fs.Connect();
615 TRequestStatus status[KWaitRequestsTableSize];
618 r = fs.SetSessionPath(gSessionPath);
621 WriteFileAsync(fs,file,gFirstFile,gSecondFileSize, KBlockSize, status);
622 WaitForAll(status,gSecondFileSize/KBlockSize);
626 test( size == gSecondFileSize );
638 /** Write a file for the simple case
641 LOCAL_C TInt ReadFileT(TAny* )
643 RTest test(_L("T_RCACHE"));
645 TInt r = fs.Connect();
648 r = fs.SetSessionPath(gSessionPath);
652 ReadFile(fs,gCurrentFile, KBlockSize);
659 gTimeTakenBigFile = I64LOW(gTime2.MicroSecondsFrom(gTime1).Int64());
666 /** Simple case, cache effect shown
669 LOCAL_C void TestSimpleRead()
679 test.Next(_L("File fits in: read sync + read sync + read async\n"));
681 tcreate = WriteTestFile(gSecondFile, gSecondFileSize);
682 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
684 time = ReadTestFile(gSecondFile);
685 test.Printf(KMsg1,time);
686 time2 = ReadTestFile(gSecondFile);
687 test.Printf(KMsg2,time2);
688 time3 = ReadAsyncTestFile(gSecondFile,gSecondFileSize);
689 test.Printf(KMsg3,time3);
690 #if !defined(__WINS__)
692 test.Printf(_L("Skipping timing test on paged ROM\n"));
694 test((time2 <= time) && (time3 < time));
697 r = DeleteAll(gSessionPath);
698 test(r == KErrNone || r == KErrInUse);
700 // Simple case filling/reading the cache from different threads
701 test.Next(_L("File fits in: read sync (another thread) + read sync + read async\n"));
702 gCurrentFile = gSecondFile;
703 gCurrentFileSize = gSecondFileSize;
705 TBuf<20> buf = _L("Write File");
706 r = gThread1.Create(buf,WriteFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
712 tcreate = I64LOW(gTimeTakenBigFile.Int64()) / 1000;
714 test.Printf(_L("Time to create the file from a thread: %d ms\n"),tcreate);
716 buf = _L("Read File");
717 r = gThread2.Create(buf,ReadFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
726 time = I64LOW(gTimeTakenBigFile.Int64()) / 1000;
727 test.Printf(KMsg1,time);
728 time2 = ReadTestFile(gSecondFile);
729 test.Printf(KMsg2,time2);
730 time3 = ReadAsyncTestFile(gSecondFile,gSecondFileSize);
731 test.Printf(KMsg3,time3);
732 #if !defined(__WINS__)
734 test.Printf(_L("Skipping timing test on paged ROM\n"));
736 test((time2<=time) && (time3<time));
739 r = DeleteAll(gSessionPath);
740 test(r == KErrNone || r == KErrInUse);
743 test.Next(_L("File doesn't fit in: read sync + read sync + read async\n"));
745 tcreate = WriteTestFile(gFirstFile,gFirstFileSize);
746 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
748 time = ReadTestFile(gFirstFile);
749 test.Printf(KMsg1,time);
750 time2 = ReadTestFile(gFirstFile);
751 test.Printf(KMsg2,time2);
752 time3 = ReadAsyncTestFile(gFirstFile,gFirstFileSize);
753 test.Printf(KMsg3,time3);
755 #if !defined(__WINS__)
756 // this isn't valid as the file doesn't fit in the cache, so there's no reason why
757 // the second read should be any faster than the first
758 // test((time2 <= time) && (time3 < time));
762 r = DeleteAll(gSessionPath);
763 test(r == KErrNone || r == KErrInUse);
766 test.Next(_L("File doesn't fit in: read sync (another thread) + read sync + read async\n"));
767 gCurrentFile = gFirstFile;
768 gCurrentFileSize = gFirstFileSize;
770 buf = _L("Write Big File");
771 r = gThread1.Create(buf,WriteFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
777 tcreate = I64LOW(gTimeTakenBigFile.Int64()) / 1000;
779 test.Printf(_L("Time to create the file from a thread: %d ms\n"),tcreate);
781 buf = _L("Read Big File");
782 r = gThread2.Create(buf,ReadFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
791 time = I64LOW(gTimeTakenBigFile.Int64()) / 1000;
792 test.Printf(KMsg1,time);
793 time2 = ReadTestFile(gFirstFile);
794 test.Printf(KMsg2,time2);
795 time3 = ReadAsyncTestFile(gFirstFile,gFirstFileSize);
796 test.Printf(KMsg3,time3);
798 #if !defined(__WINS__)
799 // this isn't valid as the file doesn't fit in the cache, so there's no reason why
800 // the second read should be any faster than the first
801 // test((time2 <= time) && (time3 < time));
804 r = DeleteAll(gSessionPath);
805 test(r == KErrNone || r == KErrInUse);
810 /** Thread to create file and read from it
813 LOCAL_C TInt ReadAnotherEntry(TAny* )
815 RTest test(_L("T_RCACHE"));
817 TInt r = fs.Connect();
819 HBufC8* lBufSec = NULL;
820 TPtr8 lBufReadPtr(NULL, 0);
822 TRAPD(res2,lBufSec = HBufC8::NewL(KBlockSize+1));
823 test(res2 == KErrNone && lBufSec != NULL);
824 lBufReadPtr.Set(lBufSec->Des());
827 r = fs.SetSessionPath(gSessionPath);
830 // delete file first to ensure it's contents are not in the cache (file may be be on the closed file queue)
831 r = fs.Delete(gFirstFile);
832 test(r == KErrNone || r == KErrNotFound);
834 r = file.Create(fs,gFirstFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
836 if(r == KErrAlreadyExists)
838 r = file.Open(fs,gFirstFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
842 r = file.Write(gBufWritePtr);
849 r = file.Read(gBufReadPtr, KBlockSize);
855 /** Test the cache behaviour in repeated call situations
858 LOCAL_C void TestRepeatedRead()
867 test.Next(_L("File fits in: read sync / read async \n"));
869 tcreate = WriteTestFile(gSecondFile, gSecondFileSize);
870 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
875 time = ReadTestFile(gSecondFile);
876 test.Printf(_L("%d) Sync Read: %d\n"), i+1 , time);
880 time = ReadAsyncTestFile(gSecondFile,gSecondFileSize);
881 test.Printf(_L("%d) Async Read: %d\n"), i+1 , time);
886 r = DeleteAll(gSessionPath);
889 test.Next(_L("File fits in: read sync / read async, with another thread using the drive \n"));
891 TBuf<20> buf = _L("Noise Thread");
892 r = gThread1.Create(buf,ReadAnotherEntry,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
895 tcreate = WriteTestFile(gSecondFile, gSecondFileSize);
896 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
906 time = ReadTestFile(gSecondFile);
907 test.Printf(_L("%d) Sync Read: %d\n"), i+1 , time);
911 time = ReadAsyncTestFile(gSecondFile,gSecondFileSize);
912 test.Printf(_L("%d) Async Read: %d\n"), i+1 , time);
917 gThread1.Kill(KErrNone);
920 r = DeleteAll(gSessionPath);
926 /** Concurrent operations testing
929 LOCAL_C void TestConcurrent()
936 test.Start(_L("Write two files concurrently\n"));
938 gCurrentFile = gSecondFile;
939 gCurrentFileSize = gSecondFileSize;
941 TBuf<20> buf = _L("Write Two Files 1");
942 r = gThread1.Create(buf,WriteFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
945 TBuf<20> buf2 = _L("Write Two Files 2");
946 r = gThread2.Create(buf2,WriteFileT2,KDefaultStackSize*2,KHeapSize,KMaxHeapSize,NULL);
954 test.Next(_L("Read the two files repeatedly\n"));
956 test.Printf(_L("File 1:\n"));
957 time = ReadTestFile(gSecondFile);
958 test.Printf(KMsg1,time);
959 time2 = ReadTestFile(gSecondFile);
960 test.Printf(KMsg2,time2);
961 time3 = ReadAsyncTestFile(gSecondFile,gSecondFileSize);
962 test.Printf(KMsg3,time3);
964 test.Printf(_L("File 2:\n"));
966 time = ReadTestFile(gFirstFile);
967 test.Printf(KMsg1,time);
968 time2 = ReadTestFile(gFirstFile);
969 test.Printf(KMsg2,time2);
970 time3 = ReadAsyncTestFile(gFirstFile,gSecondFileSize);
971 test.Printf(KMsg3,time3);
975 r = DeleteAll(gSessionPath);
979 /** Create file from other thread, to be cached
982 LOCAL_C TInt CreateFile(TAny* )
984 RTest test(_L("T_RCACHE"));
986 TInt r = fs.Connect();
989 r = fs.SetSessionPath(gSessionPath);
992 r = WriteFile(fs, gSecondFile, gSecondFileSize, KBlockSize, gBufWritePtr, EThreadSignal);
998 LOCAL_C TBool FindPattern(TUint8 *aBuf, TUint8 *aPattern, TInt aLong, TInt *aOffSet)
1001 TBool found = EFalse;
1003 while((i < (aLong-4)) && !found)
1006 (aBuf[i] == aPattern[0])&&
1007 (aBuf[i+1] == aPattern[1])&&
1008 (aBuf[i+2] == aPattern[2])&&
1009 (aBuf[i+3] == aPattern[3])
1020 /** Corrupts the second file with Raw access
1023 LOCAL_C void CorruptSecondFileRaw()
1030 TUint8 gBufferB[4] =
1034 TPtr8 gBufferBPtr(&gBufferB[0], 4, 4);
1036 TUint8 gBuffer2[KBlockSize];
1037 TPtr8 gBuffer2Ptr(&gBuffer2[0], KBlockSize);
1039 TInt r = rDisk.Open(TheFs,gDrive);
1043 TBool found = EFalse;
1048 rDisk.Read(pos, gBuffer2Ptr);
1049 found = FindPattern(gBuffer2, gBuffer, KBlockSize, &offset);
1050 pos += (KBlockSize);
1052 pos -= (KBlockSize+1);
1055 r = rDisk.Write(pos+4, gBufferBPtr);
1061 /** Modifies the second file
1064 LOCAL_C TInt CorruptSecondFile()
1068 HBufC8* dummy = NULL;
1069 TPtr8 dummyPtr(NULL, 0);
1071 TRAPD(res,dummy = HBufC8::NewL(4));
1072 test(res == KErrNone && dummy != NULL);
1074 dummyPtr.Set(dummy->Des());
1075 FillBuffer(dummyPtr, 4, '1');
1077 r = fileWrite.Open(TheFs,gSecondFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
1081 r = fileWrite.Seek(ESeekStart,pos);
1083 r = fileWrite.Write(dummyPtr);
1095 // Read the file verifying content
1097 LOCAL_C TInt ReadTestFileVerif(TDes16& aFile, TBool aRaw)
1101 TInt r = 0, size = 0;
1104 TBool isFat=IsFSFAT(TheFs,gDrive);
1106 startTime.HomeTime();
1108 r = fileRead.Open(TheFs,aFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOff);
1111 r = fileRead.Size(size);
1117 r = fileRead.Read(gBufReadPtr, KBlockSize);
1126 if(r == KErrCorrupt)
1135 r = VerifyBuffer(gBufReadPtr);
1136 if(r == KErrCorrupt)
1142 test(corrupt>0); // Ensure the cache returns the changed content
1146 gTimeTakenBigFile = I64LOW(endTime.MicroSecondsFrom(startTime).Int64());
1148 return I64LOW(gTimeTakenBigFile.Int64()) / 1000;
1152 /** Negative testing
1155 LOCAL_C void TestNegative()
1158 TInt time, time2, time3;
1162 // Kill a thread while writing, then read content
1163 TBuf<20> buf = _L("A thread to kill");
1164 gCurrentFile = gSecondFile;
1165 gCurrentFileSize = gSecondFileSize;
1167 r = gThread1.Create(buf,CreateFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
1172 gThread1.Kill(KErrGeneral);
1174 test.Next(_L("Read after killing the write in the middle\n"));
1175 time = ReadTestFile(gSecondFile);
1176 test.Printf(KMsg1,time);
1177 time2 = ReadTestFile(gSecondFile);
1178 test.Printf(KMsg2,time2);
1180 // Read async the content
1182 TRequestStatus status[KWaitRequestsTableSize];
1187 startTime.HomeTime();
1189 r = fileRead.Open(TheFs,gSecondFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOff);
1192 r = fileRead.Size(size);
1198 fileRead.Read(gBufReadPtr,status[i++]);
1207 User::WaitForRequest(status[i++]);
1211 gTimeTakenBigFile = I64LOW(endTime.MicroSecondsFrom(startTime).Int64());
1212 time3 = I64LOW(gTimeTakenBigFile.Int64()) / 1000;
1214 test.Printf(KMsg3,time3);
1216 // Modify file in some position
1217 test.Next(_L("Overwrite partially a file\n"));
1218 Formatting(gDrive, EFullFormat);
1219 r = TheFs.MkDirAll(gSessionPath);
1220 if (r != KErrNone && r != KErrAlreadyExists)
1225 tcreate = WriteTestFile(gSecondFile, gSecondFileSize);
1226 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
1228 time = ReadTestFile(gSecondFile);
1229 test.Printf(KMsg1,time);
1231 time = ReadTestFile(gSecondFile);
1232 test.Printf(KMsg2,time);
1234 CorruptSecondFile();
1236 time = ReadTestFileVerif(gSecondFile,EFalse);
1237 test.Printf(KMsg1,time);
1239 time = ReadTestFileVerif(gSecondFile,EFalse);
1240 test.Printf(KMsg2,time);
1242 // Modify the file in disk, raw access
1243 test.Next(_L("Overwrite file with raw access\n"));
1245 Formatting(gDrive,EFullFormat);
1247 r = TheFs.MkDirAll(gSessionPath);
1248 if (r != KErrNone && r != KErrAlreadyExists)
1254 tcreate = WriteTestFile(gSecondFile, gSecondFileSize);
1255 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
1257 time = ReadTestFile(gSecondFile);
1258 test.Printf(KMsg1,time);
1260 time = ReadTestFile(gSecondFile);
1261 test.Printf(KMsg2,time);
1263 CorruptSecondFileRaw();
1265 time = ReadTestFileVerif(gSecondFile,ETrue);
1266 test.Printf(KMsg1,time);
1268 time = ReadTestFileVerif(gSecondFile,ETrue);
1269 test.Printf(KMsg2,time);
1272 r = DeleteAll(gSessionPath);
1278 /** Creates the files to fill the read cache
1280 @param aFiles Number of files needed to fill the cache
1281 @param aFileSize The file size
1283 LOCAL_C void CreateFiles(TInt aFiles, TInt aFileSize)
1287 TBuf16<50> directory;
1290 TBuf16<50> buffer(50);
1292 directory = gSessionPath;
1294 test.Printf(_L("Creating %d files for filling the cache (size %d)\n"), aFiles, aFileSize);
1296 // create a big buffer to speed things up
1297 HBufC8* bigBuf = NULL;
1298 const TInt KBigBifferSize = 32 * 1024;
1299 TRAPD(res,bigBuf = HBufC8::NewL(KBigBifferSize));
1300 test(res == KErrNone && bigBuf != NULL);
1302 TPtr8 bigBufWritePtr(NULL, 0);
1303 bigBufWritePtr.Set(bigBuf->Des());
1304 FillBuffer(bigBufWritePtr, KBigBifferSize, 'A');
1311 test.Printf(_L("Creating file %d of %d...\r"), i, aFiles);
1312 FileNameGen(buffer, 8, i+3) ;
1314 path.Append(buffer);
1316 // delete file first to ensure it's contents are not in the cache (file may be on the closed file queue)
1317 r = TheFs.Delete(path);
1318 test(r == KErrNone || r == KErrNotFound);
1320 r = file.Create(TheFs,path,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
1321 if(r == KErrAlreadyExists)
1322 r = file.Open(TheFs,path,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
1324 while(j < aFileSize)
1326 bigBufWritePtr.SetLength(Min(KBigBifferSize, aFileSize - j));
1327 r = file.Write(bigBufWritePtr);
1329 j += bigBufWritePtr.Length();
1335 test.Printf(_L("\nFiles created\n"));
1339 /** Fills the read cache
1341 @param aFile Array of files needed to fill the cache
1342 @param aFiles Number of files needed to fill the cache
1343 @param aFileSize The file size
1345 LOCAL_C void FillCache(RFile aFile[KFilesNeededToFillCache], TInt aFiles, TInt aFileSize)
1348 TBuf16<50> directory;
1351 TBuf16<50> buffer(50);
1353 TPtr8 bufPtr(NULL, 0);
1355 TRAPD(res,buf = HBufC8::NewL(2));
1356 test(res == KErrNone && buf != NULL);
1357 bufPtr.Set(buf->Des());
1359 directory = gSessionPath;
1364 FileNameGen(buffer, 8, i+3) ;
1366 path.Append(buffer);
1367 r = aFile[i].Open(TheFs,path,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOff);
1371 while(j < aFileSize)
1373 r = aFile[i].Read(j,bufPtr);
1382 test.Printf(_L("Cache filled\n"));
1385 /** Fills the default cache
1388 LOCAL_C void TestFillCache()
1390 TInt nFiles = KFilesNeededToFillCache;
1391 TInt fSize = KDefaultCacheSize;
1392 RFile file[KFilesNeededToFillCache];
1394 if(gMediaSize> ((fSize * nFiles)+gSecondFileSize+gFirstFileSize))
1396 test.Start(_L("Creating files for filling the cache\n"));
1397 CreateFiles(nFiles,fSize);
1398 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
1399 // get number of items on Page Cache
1400 TFileCacheStats startPageCacheStats;
1401 TInt r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, startPageCacheStats);
1402 test(r==KErrNone || r == KErrNotSupported);
1403 test.Printf(_L("Number of page cache lines on free list at beginning=%d\n"),startPageCacheStats.iFreeCount);
1404 test.Printf(_L("Number of page cache lines on used list at beginning=%d\n"),startPageCacheStats.iUsedCount);
1405 test.Printf(_L("Number of files on closed queue=%d\n"),startPageCacheStats.iFilesOnClosedQueue);
1407 FillCache(file,nFiles,fSize);
1409 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
1410 // get number of items on Page Cache
1411 r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, startPageCacheStats);
1412 test(r==KErrNone || r == KErrNotSupported);
1413 test.Printf(_L("Number of page cache lines on free list at end=%d\n"),startPageCacheStats.iFreeCount);
1414 test.Printf(_L("Number of page cache lines on used list at end=%d\n"),startPageCacheStats.iUsedCount);
1415 test.Printf(_L("Number of files on closed queue=%d\n"),startPageCacheStats.iFilesOnClosedQueue);
1420 while( i < KFilesNeededToFillCache )
1428 test.Printf(_L("Skipping the fill of the cache due to lack of space in the current drive\n"));
1431 /** Overflow-safe tick deltas
1434 static TInt64 TicksToMsec(TUint32 aInitTicks, TUint32 aFinalTicks, TInt aFastCounterFreq)
1437 if (aFinalTicks >= aInitTicks)
1438 timeDelta = aFinalTicks - aInitTicks;
1440 timeDelta = aFinalTicks + (KMaxTUint32 - aInitTicks); // must've wrapped
1442 return TInt64(timeDelta) * TInt64(1000000) / TInt64(aFastCounterFreq);
1445 /** Read three blocks and waits for the read ahead on the File Server to do its job
1448 LOCAL_C void TestReadAhead()
1452 HBufC8* dummy = NULL;
1453 TPtr8 dummyPtr(NULL, 0);
1455 TUint32 initTicks = 0;
1456 TUint32 finalTicks = 0;
1457 TTimeIntervalMicroSeconds timeTakenReadFirst(0);
1458 TTimeIntervalMicroSeconds timeTakenReadSubsequent(0);
1460 // On NAND/FAT and NOR/LFFS drives, due to the lack of DMA support, the read-ahead is likely to happen
1461 // BEFORE control is returned to this test app - for NAND this could be fixed by adding
1462 // "FileCacheReadAsync OFF" to the estart.txt file, but we can't do this on the integrator as it has no
1463 // estart.txt file. Also, we can't set "FileCacheReadAsync OFF" for LFFS as it kills the LFFS background
1465 // So... it's only really worth testing on MMC.
1466 _LIT(KFATName,"FAT");
1467 TDriveInfo driveInfo;
1468 test(TheFs.Drive(driveInfo, gDrive) == KErrNone);
1469 TFileName fileSystem;
1470 r = TheFs.FileSystemName(fileSystem, gDrive);
1471 fileSystem.UpperCase();
1472 test((r==KErrNone)||(r==KErrNotFound));
1474 if ((driveInfo.iType != EMediaHardDisk) || (fileSystem.Compare(KFATName) != 0))
1476 test.Printf(_L("Skipping read-ahead testing (drive is not MMC)...\n"));
1480 //--Find out if the drive is sync/async at this point and print information
1481 TPckgBuf<TBool> drvSyncBuf;
1482 r = TheFs.QueryVolumeInfoExt(gDrive, EIsDriveSync, drvSyncBuf);
1483 test(r == KErrNone);
1484 const TBool bDrvSync = drvSyncBuf();
1486 test.Printf(_L("Drive D: is synchronous\n"));
1488 test.Printf(_L("Drive D: is asynchronous\n"));
1490 // use a fast counter as this is more accurate than using TTime
1491 TInt fastCounterFreq;
1492 r = HAL::Get(HAL::EFastCounterFrequency, fastCounterFreq);
1493 test(r == KErrNone);
1494 test.Printf(_L("HAL::EFastCounterFrequency %d\n"), fastCounterFreq);
1496 // Bind this thread to CPU 0. This is so that timer deltas don't drift from
1497 // scheduling - else, it causes spurious failures.
1498 if (UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0) > 1)
1499 (void)UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)0, 0);
1501 const TInt KReadLen = 28 * KOneK;
1503 TRAPD(res,dummy = HBufC8::NewL(KReadLen));
1504 test(res == KErrNone && dummy != NULL);
1506 dummyPtr.Set(dummy->Des());
1508 test.Start(_L("Creating test file..."));
1511 tcreate = WriteTestFile(gFirstFile, gFirstFileSize, ETrue);
1512 test.Printf(_L("Time to create the file: %d ms\n"),tcreate);
1514 r = fileRead.Open(TheFs,gFirstFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOn);
1518 test.Printf(_L("Issuing read #1...\n"));
1519 initTicks = User::FastCounter();
1520 r = fileRead.Read(dummyPtr);
1521 finalTicks = User::FastCounter();
1524 timeTakenReadFirst = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
1525 test.Printf(_L("first read time %d \n"), I64LOW(timeTakenReadFirst.Int64()));
1528 test.Printf(_L("Issuing read #2...\n"));
1529 r = fileRead.Read(dummyPtr);
1532 test.Printf(_L("Issuing read #3......resulting in read-ahead #1\n"));
1533 r = fileRead.Read(dummyPtr);
1535 // Wait for the read ahead #1 to be done - this should be approx the same size as previous read (KReadLen)
1536 test.Printf(_L("Wait for read-ahead #1...\n"));
1537 User::After(I64LOW(timeTakenReadFirst.Int64()) * 3 / 2);
1540 test.Printf(_L("Issuing read #4...resulting in read-ahead #2\n"));
1541 initTicks = User::FastCounter();
1542 r = fileRead.Read(dummyPtr);
1543 finalTicks = User::FastCounter();
1545 timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
1547 test.Printf(_L("read time: %d \n"), I64LOW(timeTakenReadSubsequent.Int64()));
1549 #if !defined(__WINS__)
1550 // NB the read-ahead on LFFS occurs "synchronously" i.e. it occurs before control is returned
1551 // to the caller. However it's not a good idea to mark the drive as synchronous (FileCacheReadAsync OFF)
1552 // as this causes the drive thread's priority to be lowered which kills the LFFS background processing (!)
1554 test.Printf(_L("Skipping timing test on paged ROM\n"));
1556 test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
1559 // The read ahead #2 should now be in progress - this should be approx KReadLen * 2
1560 // so this read will take result in the next read taking longer than normal (about double)
1561 test.Printf(_L("Issuing read #5......resulting in read-ahead #3\n"));
1562 initTicks = User::FastCounter();
1563 r = fileRead.Read(dummyPtr);
1564 finalTicks = User::FastCounter();
1566 timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
1567 test.Printf(_L("read time: %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
1570 // this read should take a long time, so don't test
1571 //#if !defined(__WINS__)
1572 // test(gTimeTakenReadBlockFile.Int64() < gTimeTakenBigFile.Int64());
1575 // The third read should be very quick as the previous read-ahead should have already buffered the data
1576 test.Printf(_L("Issuing read #6......resulting in read-ahead #4\n"));
1577 initTicks = User::FastCounter();
1578 r = fileRead.Read(dummyPtr);
1579 finalTicks = User::FastCounter();
1581 timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
1582 test.Printf(_L("read time: %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
1585 #if !defined(__WINS__)
1587 test.Printf(_L("Skipping timing test on paged ROM\n"));
1589 test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
1595 r = DeleteAll(gSessionPath);
1603 /** Main tests function
1605 GLDEF_C void CallTestsL()
1607 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
1608 test.Printf(_L("Disabling Lock Fail simulation ...\n"));
1609 // turn OFF lock failure mode
1610 TBool simulatelockFailureMode = EFalse;
1611 TInt r = controlIo(TheFs, gDrive, KControlIoSimulateLockFailureMode, simulatelockFailureMode);
1612 test (r == KErrNone);
1617 RProcess().SetPriority(EPriorityBackground);
1619 // FileNames/File generation
1620 test.Start(_L("Preparing the environmnet\n"));
1621 FileNameGen(gFirstFile, 8, gNextFile++);
1622 FileNameGen(gSecondFile, 8, gNextFile++);
1624 dir.Append(gFirstFile);
1627 dir.Append(gSecondFile);
1631 TRAPD(res,gBuf = HBufC8::NewL(KBlockSize+1));
1632 test(res == KErrNone && gBuf != NULL);
1634 gBufWritePtr.Set(gBuf->Des());
1635 FillBuffer(gBufWritePtr, KBlockSize, 'A');
1637 TRAPD(res2,gBufSec = HBufC8::NewL(KBlockSize+1));
1638 test(res2 == KErrNone && gBufSec != NULL);
1639 gBufReadPtr.Set(gBufSec->Des());
1641 test.Next(_L("Negative test\n"));
1644 test.Next(_L("Simple cases, use of the cache from same location/different"));
1647 test.Next(_L("Repeated reads, same file\n"));
1650 test.Next(_L("Read ahead testing\n"));
1653 test.Next(_L("Concurrent read cases\n"));
1656 test.Next(_L("Fill the cache, boundary testing\n"));
1663 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
1664 // turn lock failure mode back ON (if enabled)
1665 simulatelockFailureMode = ETrue;
1666 r = controlIo(TheFs, gDrive, KControlIoSimulateLockFailureMode, simulatelockFailureMode);
1667 test (r == KErrNone);
1672 /** Initialises semaphores and call the tests
1674 LOCAL_C void DoTests()
1678 r = client.CreateLocal(0);
1681 r = gSync.CreateLocal(0);
1685 r = TheFs.SetSessionPath(gSessionPath);
1688 r = TheFs.MkDirAll(gSessionPath);
1689 if (r != KErrNone && r != KErrAlreadyExists)
1693 TheFs.ResourceCountMarkStart();
1694 TRAP(r,CallTestsL());
1696 TheFs.ResourceCountMarkEnd();
1703 /** Determines the space that can be used for the files
1706 TBool CheckForDiskSize()
1708 TVolumeInfo volInfo;
1709 TInt r = TheFs.Volume(volInfo, gDrive);
1711 gMediaSize = volInfo.iSize;
1712 gSecondFileSize = KBlockSize*92;
1713 gFirstFileSize = KBlockSize*(256);
1714 while(((2*gFirstFileSize)+KOneMeg) > gMediaSize )
1716 gFirstFileSize -= (2*KBlockSize);
1719 TReal32 small = (TReal32)(gSecondFileSize/KOneK);
1720 TReal32 big = (TReal32)(gFirstFileSize/KOneK);
1722 test.Printf(_L("Test File: %.2f KB\n"), small );
1723 test.Printf(_L("Too big for the cache file: %.2f KB (%.2f MB)\n"), big, big / KOneK );
1725 if(gFirstFileSize < gSecondFileSize)
1733 @return KErrNone if everything was ok, panics otherwise
1735 GLDEF_C TInt E32Main()
1737 // Determine whether this is a paged ROM -
1738 // if it is we bypass some of the timimg tests as the default paging ROMs have a deliberately
1739 // small pool of pages (in order to stress the system) and reading things through the file cache
1740 // in this "artificial" environment can cause code to be evicted which can result in the read timings
1741 // going AWOL. In a more real-world environment, file caching should turn itself off if the amount of
1742 // memory falls below a threshold.
1743 #if !defined(__WINS__)
1744 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1745 gPagedRom = romHeader->iPageableRomStart ? (TBool)ETrue : (TBool)EFalse;
1749 gMainThreadId = t.Id();
1751 CTrapCleanup* cleanup;
1752 cleanup = CTrapCleanup::New();
1755 test.Start(_L("Starting tests... T_RCACHE"));
1758 TInt r = TheFs.Connect();
1762 TVolumeInfo volInfo;
1763 r = TheFs.Drive(info,gDrive);
1766 if(info.iMediaAtt&KMediaAttVariableSize)
1768 test.Printf(_L("Tests skipped in RAM drive\n"));
1772 r = TheFs.Volume(volInfo, gDrive);
1773 if (r == KErrNotReady)
1775 if (info.iType == EMediaNotPresent)
1776 test.Printf(_L("%c: Medium not present - cannot perform test.\n"), (TUint)gDriveToTest);
1778 test.Printf(_L("%c: medium found (type %d) but drive not ready\nPrevious test may have hung; else, check hardware.\n"), (TUint)gDriveToTest, (TInt)info.iType);
1780 else if (r == KErrCorrupt)
1782 test.Printf(_L("%c: Media corruption; previous test may have aborted; else, check hardware\n"), (TUint)gDriveToTest);
1786 if(!(volInfo.iFileCacheFlags & (EFileCacheReadEnabled | EFileCacheReadAheadEnabled)))
1788 test.Printf(_L("Skipping tests, Read caching not enabled in this drive\n"));
1792 if (((volInfo.iDrive.iMediaAtt & KMediaAttFormattable)))
1793 Formatting(gDrive,ESpecialFormat);
1795 if(CheckForDiskSize())
1801 test.Printf(_L("Skipping tests due to lack of space to perform them in this drive\n"));