|
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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // f32test\server\t_mount.cpp |
|
15 // Testing FAT cache performance |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 */ |
|
22 |
|
23 #define __E32TEST_EXTENSION__ |
|
24 |
|
25 #include <f32file.h> |
|
26 #include <e32test.h> |
|
27 #include <e32math.h> |
|
28 #include <e32property.h> |
|
29 |
|
30 #include "t_server.h" |
|
31 //#include "t_std.h" |
|
32 |
|
33 #include "fat_utils.h" |
|
34 |
|
35 using namespace Fat_Test_Utils; |
|
36 |
|
37 #ifdef __VC32__ |
|
38 // Solve compilation problem caused by non-English locale |
|
39 #pragma setlocale("english") |
|
40 #endif |
|
41 |
|
42 RTest test(_L("T_FAT_Cache_BM")); |
|
43 |
|
44 //-- note that this test disables all FAT mount enhancements, like asynchronous mounting and using FSInfo sector. |
|
45 |
|
46 static void WaitForFatBkGndActivityEnd(); |
|
47 |
|
48 //------------------------------------------------------------------- |
|
49 //-- debug bit flags that may be set in the property which controls FAT volume mounting |
|
50 |
|
51 const TUid KThisTestSID={0x10210EB3}; ///< this EXE SID |
|
52 |
|
53 //const TUint32 KMntProp_EnableALL = 0x00000000; //-- enable all operations |
|
54 const TUint32 KMntProp_DisableALL = 0xFFFFFFFF; //-- disable all operations |
|
55 |
|
56 //const TUint32 KMntProp_Disable_FsInfo = 0x00000001; //-- mask for disabling/enabling FSInfo information |
|
57 //const TUint32 KMntProp_Disable_FatBkGndScan = 0x00000002; //-- mask for disabling/enabling FAT background scanner |
|
58 |
|
59 //------------------------------------------------------------------- |
|
60 |
|
61 static TInt gDriveNum=-1; ///< drive number we are dealing with |
|
62 static TInt64 gRndSeed; |
|
63 static TFatBootSector gBootSector; |
|
64 |
|
65 static void DoRemountFS(TInt aDrive); |
|
66 |
|
67 //-- Array of integer file tars. Tags are used to identify files (the file name is generated by KFnTemplate template) |
|
68 typedef CArrayFixFlat<TInt> CFileTagsArray; |
|
69 static CFileTagsArray *pFTagArray = NULL; |
|
70 |
|
71 |
|
72 //------------------------------------------------------------------- |
|
73 const TInt KMaxFiles = 1000; //-- maximal number of files to create |
|
74 |
|
75 //-- number of unfragmented files that will be left, other files will be merged to bigger ones. |
|
76 const TInt KUnfragmentedFilesLeave = KMaxFiles/10; |
|
77 |
|
78 _LIT(KDirName, "\\DIR1\\"); //-- directory name we a working with (FAT12/16 won't allow KMaxFiles in the root dir.) |
|
79 _LIT(KFirstFileName, "\\First_file_1.nul"); //-- the name of the first file on the volume |
|
80 |
|
81 //------------------------------------------------------------------- |
|
82 |
|
83 /** |
|
84 Make a file name by its numeric tag |
|
85 @param aDes here will be a file name |
|
86 @param aFileNameTag numeric tag for the file name generation |
|
87 |
|
88 */ |
|
89 void MakeFileName(TDes& aDes, TInt aFileNameTag) |
|
90 { |
|
91 _LIT(KFnTemplate, "F%d.NUL");//-- file name template, use 8.3 names here in order not to stress dir. cache much. |
|
92 aDes.Copy(KDirName); |
|
93 aDes.AppendFormat(KFnTemplate, aFileNameTag); |
|
94 } |
|
95 |
|
96 //------------------------------------------------------------------- |
|
97 /** |
|
98 format the volume and read the boot sector |
|
99 */ |
|
100 static void FormatVolume(TBool aQuickFormat) |
|
101 { |
|
102 (void)aQuickFormat; |
|
103 |
|
104 #ifndef __EPOC32__ |
|
105 test.Printf(_L("This is emulator configuration!!!!\n")); |
|
106 |
|
107 //-- FAT32 SPC:1; for the FAT32 testing on the emulator |
|
108 //TFatFormatParam fp; |
|
109 //fp.iFatType = EFat32; |
|
110 //fp.iSecPerCluster = 1; |
|
111 //FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fp); //-- always quick; doesn't matter for the emulator |
|
112 |
|
113 aQuickFormat = ETrue; |
|
114 #endif |
|
115 |
|
116 |
|
117 FormatFatDrive(TheFs, CurrentDrive(), aQuickFormat); |
|
118 |
|
119 |
|
120 TInt nRes = ReadBootSector(TheFs, gDriveNum, 0x00, gBootSector); |
|
121 test_KErrNone(nRes); |
|
122 } |
|
123 |
|
124 |
|
125 //------------------------------------------------------------------- |
|
126 |
|
127 /** |
|
128 Helper method. Does one iteration of merging test files into one fragmented one. |
|
129 See DoMergeFiles() |
|
130 |
|
131 @param aFTagArray reference to the file tags array |
|
132 @param aBigFileNo a sequential number of the result file to be merged from random number of smaller ones (names are taken from the tag array) |
|
133 @param aTimeTaken_us on return will contain time taken to this operation, in microseconds |
|
134 |
|
135 @return number of files merged into one. |
|
136 */ |
|
137 TInt DoMergeTestFiles(CFileTagsArray& aFTagArray, TInt aBigFileNo, TInt64& aTimeTaken_us) |
|
138 { |
|
139 |
|
140 aTimeTaken_us = 0; |
|
141 TTime timeStart; |
|
142 TTime timeEnd; |
|
143 |
|
144 |
|
145 //-- merged files' names start with this number |
|
146 const TInt KMergedFileFnThreshold = 20000; |
|
147 |
|
148 const TInt KMaxMergedFiles = 20; |
|
149 const TInt nFilesToMerge = Max((Math::Rand(gRndSeed) % KMaxMergedFiles), 2); //-- how many files to merge into one |
|
150 |
|
151 test(aFTagArray.Count() > KMaxMergedFiles); |
|
152 |
|
153 TInt selectedFTags[KMaxMergedFiles]; //-- here we will store file tags to be merged to one large fragmented file |
|
154 TInt i; |
|
155 TInt nRes; |
|
156 |
|
157 i=0; |
|
158 do |
|
159 { |
|
160 //-- randomly select a file tag from the global array |
|
161 const TInt index = (TUint)Math::Rand(gRndSeed) % aFTagArray.Count(); |
|
162 const TInt fnTag = aFTagArray[index]; |
|
163 |
|
164 if(fnTag < 0 || //-- no such file, already deleted |
|
165 fnTag >= KMergedFileFnThreshold) //-- this is a big, already merged file |
|
166 continue; |
|
167 |
|
168 |
|
169 selectedFTags[i] = fnTag; |
|
170 aFTagArray.Delete(index); |
|
171 |
|
172 ++i; |
|
173 }while(i<nFilesToMerge); |
|
174 |
|
175 //-- here we have file tags in selectedFNumbers array. delete these files and create one big file |
|
176 //-- with the equal size. This file will be perfectly fragmented. |
|
177 //-- search for FAT entries had priority to the right, so delete files in reverse order. |
|
178 |
|
179 TUint32 newFileSize = 0; |
|
180 TBuf<128> buf; |
|
181 RFile file; |
|
182 |
|
183 timeStart.UniversalTime(); //-- take start time |
|
184 |
|
185 for(i=0; i<nFilesToMerge; ++i) |
|
186 { |
|
187 MakeFileName(buf, selectedFTags[nFilesToMerge-1-i]); |
|
188 |
|
189 nRes=file.Open(TheFs, buf, EFileRead); |
|
190 test_KErrNone(nRes); |
|
191 |
|
192 TInt nSize; |
|
193 nRes = file.Size(nSize); |
|
194 test_KErrNone(nRes); |
|
195 file.Close(); |
|
196 |
|
197 newFileSize+=(TUint32)nSize; //-- this will be the size of the new file |
|
198 |
|
199 //-- delete small file |
|
200 nRes = TheFs.Delete(buf); |
|
201 test_KErrNone(nRes); |
|
202 |
|
203 } |
|
204 |
|
205 //-- create a large file taking the place of few smaller. It will be framented. |
|
206 const TInt bigFileTag = aBigFileNo+KMergedFileFnThreshold; |
|
207 |
|
208 MakeFileName(buf, bigFileTag); |
|
209 nRes = CreateEmptyFile(TheFs, buf, newFileSize); |
|
210 test_KErrNone(nRes); |
|
211 |
|
212 timeEnd.UniversalTime(); //-- take end time |
|
213 aTimeTaken_us = (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
214 |
|
215 //-- put new big file name tag to the global array in order not to forget it for later use. |
|
216 aFTagArray.AppendL(bigFileTag); |
|
217 |
|
218 return nFilesToMerge; |
|
219 } |
|
220 |
|
221 //---------------------------------------------------------------------------------------------- |
|
222 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0689 |
|
223 //! @SYMTestType PT |
|
224 //! @SYMPREQ PREQ1721 |
|
225 //! @SYMTestCaseDesc randomly deletes small files and creates larger. Measures time taken by this FAT fragmentation |
|
226 //! |
|
227 //! @SYMTestActions |
|
228 //! 0 delete a random number of small files |
|
229 //! 1 create a random number of larger files, measure time taken |
|
230 //! |
|
231 //! @SYMTestExpectedResults successful files deletion/creation |
|
232 //! @SYMTestPriority High |
|
233 //! @SYMTestStatus Implemented |
|
234 //---------------------------------------------------------------------------------------------- |
|
235 |
|
236 /** |
|
237 precondition: We have a lot of (KMaxFiles) files of the same size on the volume. They occupy almost all FAT. |
|
238 This method randomly selects several files on the volume, deletes them and creates a bigger file that occupies space from the |
|
239 deleted files. So that we got a fragmented big file. Repeat this until we have KUnfragmentedFilesLeave initial files left on the |
|
240 volume. |
|
241 */ |
|
242 void DoMergeFiles(CFileTagsArray& aFTagArray) |
|
243 { |
|
244 test.Next(_L("Merging small files to larger creating FAT fragmentation...\n")); |
|
245 |
|
246 TInt64 usTotalTime=0; |
|
247 TInt64 usCurrTime; |
|
248 |
|
249 TInt nUnfragmentedLeft = aFTagArray.Count(); |
|
250 for(TInt i=0; nUnfragmentedLeft > KUnfragmentedFilesLeave; ++i) |
|
251 { |
|
252 nUnfragmentedLeft -= DoMergeTestFiles(aFTagArray, i, usCurrTime); |
|
253 usTotalTime += usCurrTime; |
|
254 } |
|
255 |
|
256 test.Printf(_L("#--> Merging files :%d ms\n"), (TUint32)usTotalTime/K1mSec); |
|
257 } |
|
258 |
|
259 //------------------------------------------------------------------- |
|
260 /** |
|
261 Randomly shuffles entries in file name tags array. |
|
262 */ |
|
263 void ShuffleArray(CFileTagsArray& aFTagArray) |
|
264 { |
|
265 const TInt KSwapIterations = 500; |
|
266 const TInt arrSize = aFTagArray.Count(); |
|
267 |
|
268 |
|
269 for(TInt i = 0; i<KSwapIterations; ++i) |
|
270 {//-- randomly swap 2 elements in the array |
|
271 const TInt idx1 = (TUint)Math::Rand(gRndSeed) % arrSize; |
|
272 const TInt idx2 = (TUint)Math::Rand(gRndSeed) % arrSize; |
|
273 |
|
274 TInt tmp = aFTagArray[idx1]; |
|
275 aFTagArray[idx1] = aFTagArray[idx2];; |
|
276 aFTagArray[idx2] = tmp; |
|
277 } |
|
278 |
|
279 } |
|
280 |
|
281 //---------------------------------------------------------------------------------------------- |
|
282 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0690 |
|
283 //! @SYMTestType PT |
|
284 //! @SYMPREQ PREQ1721 |
|
285 //! @SYMTestCaseDesc Measure open and seek time for all files that have tags in aFTagArray. |
|
286 //! |
|
287 //! @SYMTestActions |
|
288 //! 0 remount FS |
|
289 //! 1 open all files, that have tags in aFTagArray, measure time taken |
|
290 //! 2 seek to the each file end, measure time taken |
|
291 //! |
|
292 //! @SYMTestExpectedResults successful files open/seek |
|
293 //! @SYMTestPriority High |
|
294 //! @SYMTestStatus Implemented |
|
295 //---------------------------------------------------------------------------------------------- |
|
296 void MeasureSeekTime(CFileTagsArray& aFTagArray) |
|
297 { |
|
298 test.Next(_L("Measuring seek time...\n")); |
|
299 |
|
300 TInt nRes; |
|
301 RFile file; |
|
302 TBuf<128> buf; |
|
303 |
|
304 TTime timeStart; |
|
305 TTime timeEnd; |
|
306 TInt64 usTotalTimeSeek=0; |
|
307 TInt64 usTotalTimeOpen=0; |
|
308 |
|
309 const TInt KNumRepetitions = 10; |
|
310 |
|
311 for(TInt repCnt=0; repCnt<KNumRepetitions; ++repCnt) |
|
312 { |
|
313 //-- remount file system, reset caches |
|
314 DoRemountFS(gDriveNum); |
|
315 |
|
316 for(TInt i = 0; i<aFTagArray.Count(); ++i) |
|
317 { |
|
318 MakeFileName(buf, aFTagArray[i]); |
|
319 |
|
320 //-- 1. open the file |
|
321 timeStart.UniversalTime(); //-- take start time |
|
322 |
|
323 nRes = file.Open(TheFs, buf, EFileRead); |
|
324 |
|
325 timeEnd.UniversalTime(); //-- take end time |
|
326 usTotalTimeOpen += (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
327 |
|
328 test_KErrNone(nRes); |
|
329 |
|
330 |
|
331 //-- 2. goto the end of the file. This operation shall traverse whole file's cluster chain in FAT |
|
332 timeStart.UniversalTime(); //-- take start time |
|
333 |
|
334 TInt seekPos = 0; |
|
335 nRes = file.Seek(ESeekEnd, seekPos); |
|
336 |
|
337 timeEnd.UniversalTime(); //-- take end time |
|
338 usTotalTimeSeek += (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
339 |
|
340 test_KErrNone(nRes); |
|
341 file.Close(); |
|
342 } |
|
343 } |
|
344 |
|
345 test.Printf(_L("#--> Total open time for %d files is %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTimeOpen/(K1mSec*KNumRepetitions)); |
|
346 test.Printf(_L("#--> Total seek time for %d files is %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTimeSeek/(K1mSec*KNumRepetitions)); |
|
347 } |
|
348 |
|
349 |
|
350 //---------------------------------------------------------------------------------------------- |
|
351 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0692 |
|
352 //! @SYMTestType PT |
|
353 //! @SYMPREQ PREQ1721 |
|
354 //! @SYMTestCaseDesc Detetes all files that have name tags in name tags array and measures time taken. |
|
355 //! |
|
356 //! @SYMTestActions |
|
357 //! 0 remount the FS |
|
358 //! 1 delete files and measure time taken. |
|
359 //! |
|
360 //! @SYMTestExpectedResults successful creating files |
|
361 //! @SYMTestPriority High |
|
362 //! @SYMTestStatus Implemented |
|
363 //---------------------------------------------------------------------------------------------- |
|
364 void DeleteAllFiles(CFileTagsArray& aFTagArray) |
|
365 { |
|
366 TInt nRes; |
|
367 TBuf<128> buf; |
|
368 |
|
369 TTime timeStart; |
|
370 TTime timeEnd; |
|
371 TInt64 usTotalTime=0; |
|
372 |
|
373 test.Next(_L("Deleting all files...\n")); |
|
374 |
|
375 //-- remount file system, reset caches |
|
376 DoRemountFS(gDriveNum); |
|
377 |
|
378 for(TInt i = 0; i<aFTagArray.Count(); ++i) |
|
379 { |
|
380 MakeFileName(buf, aFTagArray[i]); |
|
381 |
|
382 timeStart.UniversalTime(); //-- take start time |
|
383 |
|
384 nRes = TheFs.Delete(buf); |
|
385 |
|
386 timeEnd.UniversalTime(); //-- take end time |
|
387 usTotalTime += (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
388 |
|
389 test_KErrNone(nRes); |
|
390 } |
|
391 |
|
392 test.Printf(_L("#--> Deleted %d files in %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTime/K1mSec); |
|
393 } |
|
394 |
|
395 //---------------------------------------------------------------------------------------------- |
|
396 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0687 |
|
397 //! @SYMTestType PT |
|
398 //! @SYMPREQ PREQ1721 |
|
399 //! @SYMTestCaseDesc Create KMaxFiles files to fill in space in FAT table and measure time taken. |
|
400 //! |
|
401 //! @SYMTestActions |
|
402 //! 0 Create KMaxFiles files and measure time taken. |
|
403 //! |
|
404 //! @SYMTestExpectedResults successful creating files |
|
405 //! @SYMTestPriority High |
|
406 //! @SYMTestStatus Implemented |
|
407 //---------------------------------------------------------------------------------------------- |
|
408 /** |
|
409 Create KMaxFiles files to fill in space in FAT table and measure time taken. |
|
410 @return EFalse if it is impossible to create test files |
|
411 */ |
|
412 TBool DoCreateFiles(CFileTagsArray& aFTagArray) |
|
413 { |
|
414 TInt nRes; |
|
415 TBuf<128> buf; |
|
416 |
|
417 TTime timeStart; |
|
418 TTime timeEnd; |
|
419 TInt64 usTotalTime=0; |
|
420 |
|
421 test.Next(_L("Creating many files\n")); |
|
422 test.Printf(_L("Number of files:%d\n"), KMaxFiles); |
|
423 |
|
424 aFTagArray.Reset(); |
|
425 |
|
426 TVolumeInfo volInfo; |
|
427 nRes = TheFs.Volume(volInfo, gDriveNum); |
|
428 test_KErrNone(nRes); |
|
429 |
|
430 |
|
431 test(gBootSector.IsValid()); |
|
432 |
|
433 const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector(); |
|
434 const TUint32 maxClusters = (TUint32)(volInfo.iFree / clustSz); |
|
435 |
|
436 if(KMaxFiles > 0.8 * maxClusters) |
|
437 { |
|
438 test.Printf(_L("Can't create %d files; skipping the test!\n"), KMaxFiles); |
|
439 return EFalse; |
|
440 } |
|
441 |
|
442 //-- adjust file size for very small volumes |
|
443 TUint32 fillFileSz = (maxClusters/KMaxFiles)*clustSz; |
|
444 if(fillFileSz*KMaxFiles >= 0.8*volInfo.iFree) //-- take into account the size of the directory with 1000 files. |
|
445 { |
|
446 if(fillFileSz <= clustSz) |
|
447 { |
|
448 test.Printf(_L("Can't create %d files; skipping the test!\n"), KMaxFiles); |
|
449 return EFalse; |
|
450 } |
|
451 |
|
452 fillFileSz -= clustSz; |
|
453 } |
|
454 |
|
455 //-- create the first file on the volume. It will be deleted then in order to create 1 free FAT entry |
|
456 //-- in the very beginnng of the FAT. So, the size of this file shan't be more that 1 sector/cluster. |
|
457 nRes = CreateEmptyFile(TheFs, KFirstFileName, 100); |
|
458 test_KErrNone(nRes); |
|
459 |
|
460 |
|
461 //-- to avoid affected timings in UREL mode. |
|
462 WaitForFatBkGndActivityEnd(); |
|
463 |
|
464 //-- disable FAT test utils print out, it affects measured time when we create empty files |
|
465 EnablePrintOutput(EFalse); |
|
466 |
|
467 //-- create KMaxFiles files on the volume |
|
468 for(TInt i=0; i<KMaxFiles; ++i) |
|
469 { |
|
470 //-- create empty file |
|
471 MakeFileName(buf, i); |
|
472 |
|
473 timeStart.UniversalTime(); //-- take start time |
|
474 |
|
475 nRes = CreateEmptyFile(TheFs, buf, fillFileSz); |
|
476 |
|
477 timeEnd.UniversalTime(); //-- take end time |
|
478 usTotalTime += (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
479 |
|
480 test_KErrNone(nRes); |
|
481 //-- put its id number to the array. |
|
482 aFTagArray.AppendL(i); |
|
483 |
|
484 if((i % 100) == 0) |
|
485 test.Printf(_L("*")); |
|
486 |
|
487 } |
|
488 |
|
489 EnablePrintOutput(ETrue); //-- Enable FAT test utils print out |
|
490 |
|
491 test.Printf(_L("\n#--> Created %d files in %d ms\n"), KMaxFiles, (TUint32)usTotalTime/K1mSec); |
|
492 |
|
493 return ETrue; |
|
494 } |
|
495 |
|
496 //---------------------------------------------------------------------------------------------- |
|
497 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0691 |
|
498 //! @SYMTestType PT |
|
499 //! @SYMPREQ PREQ1721 |
|
500 //! @SYMTestCaseDesc Check that all FAT copies are the same. |
|
501 //! |
|
502 //! @SYMTestActions |
|
503 //! 0 read all available FAT copies and compare them |
|
504 //! |
|
505 //! @SYMTestExpectedResults all FAT copies on the vollume must be the same. |
|
506 //! @SYMTestPriority High |
|
507 //! @SYMTestStatus Implemented |
|
508 //---------------------------------------------------------------------------------------------- |
|
509 void CheckFatCopies() |
|
510 { |
|
511 test.Next(_L("Comparing FATs...\n")); |
|
512 |
|
513 TFatBootSector bootSec; |
|
514 |
|
515 TInt nRes = ReadBootSector(TheFs, gDriveNum, 0x00, bootSec); |
|
516 test_KErrNone(nRes); |
|
517 |
|
518 const TInt numFATs = bootSec.NumberOfFats(); |
|
519 if(numFATs < 2) |
|
520 {//-- only one FAT, nothing to compare with. |
|
521 test.Printf(_L("The volume has only 1 FAT. Nothing to do.\n")); |
|
522 return; |
|
523 } |
|
524 |
|
525 const TUint32 bytesPerSec = bootSec.BytesPerSector(); |
|
526 const TUint32 posFat1Start = bootSec.FirstFatSector() * bytesPerSec; |
|
527 const TUint32 fatSize = bootSec.TotalFatSectors() * bytesPerSec; |
|
528 |
|
529 RBuf8 fatBuf1; |
|
530 RBuf8 fatBuf2; |
|
531 |
|
532 nRes = fatBuf1.CreateMax(bytesPerSec); |
|
533 test_KErrNone(nRes); |
|
534 |
|
535 nRes = fatBuf2.CreateMax(bytesPerSec); |
|
536 test_KErrNone(nRes); |
|
537 |
|
538 //-- read FAT sector by sector comparing all copies |
|
539 TUint32 currPos = posFat1Start; |
|
540 for(TUint cntSectors=0; cntSectors<bootSec.TotalFatSectors(); ++cntSectors) |
|
541 { |
|
542 //-- read a sector of FAT#0 |
|
543 nRes = MediaRawRead(TheFs, gDriveNum, currPos, bytesPerSec, fatBuf1); |
|
544 test_KErrNone(nRes); |
|
545 |
|
546 //-- read the same sector from other copies of FAT and compare with FAT#0 |
|
547 for(TInt currFat=1; currFat<numFATs; ++currFat) |
|
548 { |
|
549 nRes = MediaRawRead(TheFs, gDriveNum, (currFat*fatSize + currPos), bytesPerSec, fatBuf2); |
|
550 test_KErrNone(nRes); |
|
551 |
|
552 //-- compare the buffer to FAT#0 |
|
553 if(fatBuf1.CompareF(fatBuf2) !=0) |
|
554 {//-- current FAT is different from FAT0 |
|
555 test.Printf(_L("FAT#%d differs from FAT#0! FAT sector:%d, media Sector:%d\n"), currFat, cntSectors, cntSectors+bootSec.FirstFatSector()); |
|
556 test(0); |
|
557 } |
|
558 |
|
559 } |
|
560 |
|
561 |
|
562 currPos+=bytesPerSec; |
|
563 } |
|
564 |
|
565 |
|
566 fatBuf1.Close(); |
|
567 fatBuf2.Close(); |
|
568 |
|
569 } |
|
570 |
|
571 //---------------------------------------------------------------------------------------------- |
|
572 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0688 |
|
573 //! @SYMTestType PT |
|
574 //! @SYMPREQ PREQ1721 |
|
575 //! @SYMTestCaseDesc Create the file whose FAT entries will go to the end of the FAT table and measure the time taken. |
|
576 //! |
|
577 //! @SYMTestActions |
|
578 //! 0 delete a file in the very beginning of the FAT |
|
579 //! 1 remount file system |
|
580 //! 2 create a larger file finishing at the end of FAT, measure time taken |
|
581 //! |
|
582 //! @SYMTestExpectedResults successful files creation |
|
583 //! @SYMTestPriority High |
|
584 //! @SYMTestStatus Implemented |
|
585 //---------------------------------------------------------------------------------------------- |
|
586 |
|
587 /** |
|
588 Create the file whose FAT entries will go to the end of the FAT table and measure the time taken. |
|
589 preconditions: |
|
590 1. The FAT table must be almost full already. This is done previously in DoCreateFiles(). |
|
591 2. There shall be a small file in the very beginning of the FAT which this test deletes and remounts the FS. |
|
592 this will cause "the last known free cluster" in the FAT to be set to the beginning of the FAT. |
|
593 |
|
594 Then when we create a larger file, whole occupied FAT region will be scanned for the free cluster. |
|
595 */ |
|
596 void CreateLastFile() |
|
597 { |
|
598 test.Next(_L("Create a file in the end of FAT\n")); |
|
599 |
|
600 TTime timeStart; |
|
601 TTime timeEnd; |
|
602 TInt64 usTotalTime=0; |
|
603 |
|
604 TInt nRes; |
|
605 |
|
606 |
|
607 //-- 1. delete the first file on the volume (see KFirstFileName & DoCreateFiles() |
|
608 //-- it will create free FAT entry in the very beginning. |
|
609 nRes = TheFs.Delete(KFirstFileName); |
|
610 test_KErrNone(nRes); |
|
611 |
|
612 |
|
613 //-- 2. remount file system, reset caches etc. The first known free cluster will be number 2 or 3, because of the point 1. |
|
614 //-- the rest of the FAT is filled, because we've created plenty of files in the DoCreateFiles() |
|
615 DoRemountFS(gDriveNum); |
|
616 |
|
617 //-- 3. create a file that will occupy more that 2 clusters; the 1st cluster of it will be in the very beginning of the FAT, |
|
618 //-- and the rest will be in the very end of the FAT. Measure the time taken to walk all FAT when searching free entry. |
|
619 _LIT(KLastFn, "\\last-last.file"); |
|
620 |
|
621 test(gBootSector.IsValid()); |
|
622 |
|
623 const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector(); |
|
624 |
|
625 |
|
626 //-- disable FAT test utils print out, it affects measured time |
|
627 EnablePrintOutput(EFalse); |
|
628 |
|
629 timeStart.UniversalTime(); //-- take start time |
|
630 |
|
631 //-- create an empty file, it is supposed to be placed in the very end of FAT (FAT table is almost full because of the |
|
632 //-- previous test) |
|
633 nRes = CreateEmptyFile(TheFs, KLastFn, 7*clustSz); |
|
634 |
|
635 timeEnd.UniversalTime(); //-- take end time |
|
636 usTotalTime = (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
637 |
|
638 test_KErrNone(nRes); |
|
639 |
|
640 test.Printf(_L("#--> file at the end of FAT created in %d ms\n"), (TUint32)usTotalTime/K1mSec); |
|
641 |
|
642 //-- delete the file |
|
643 nRes = TheFs.Delete(KLastFn); |
|
644 test_KErrNone(nRes); |
|
645 |
|
646 EnablePrintOutput(ETrue); //-- Enable FAT test utils print out |
|
647 } |
|
648 |
|
649 //------------------------------------------------------------------- |
|
650 /** |
|
651 Create 100 directories in the root and measure time |
|
652 */ |
|
653 void DoCreateDirsInRoot() |
|
654 { |
|
655 test.Next(_L("Measure time to create many directories in the Root.\n")); |
|
656 |
|
657 if(!Is_Fat32(TheFs, gDriveNum)) |
|
658 { |
|
659 test.Printf(_L("This test requires FAT32, skipping\n")); |
|
660 return; |
|
661 } |
|
662 |
|
663 TTime timeStart; |
|
664 TTime timeEnd; |
|
665 TInt64 usTotalTime=0; |
|
666 TFileName dirName; |
|
667 |
|
668 //-- remount file system, reset caches etc. The first known free cluster will be number 2 or 3 |
|
669 DoRemountFS(gDriveNum); |
|
670 |
|
671 //-- disable FAT test utils print out, it affects measured time |
|
672 EnablePrintOutput(EFalse); |
|
673 |
|
674 timeStart.UniversalTime(); //-- take start time |
|
675 |
|
676 //-- create some subdirectories in the root dir and measure time |
|
677 const TInt KMaxDirs = 100; |
|
678 for(TInt i=0; i<KMaxDirs; ++i) |
|
679 { |
|
680 dirName.Format(_L("\\directory%04d\\"), i); |
|
681 TInt nRes = TheFs.MkDir(dirName); |
|
682 test_KErrNone(nRes); |
|
683 } |
|
684 |
|
685 timeEnd.UniversalTime(); //-- take end time |
|
686 usTotalTime = (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
687 |
|
688 test.Printf(_L("#--> %d Dirs. created in %d ms\n"), KMaxDirs, (TUint32)usTotalTime/K1mSec); |
|
689 |
|
690 EnablePrintOutput(ETrue); //-- Enable FAT test utils print out |
|
691 } |
|
692 |
|
693 //---------------------------------------------------------------------------------------------- |
|
694 //! @SYMTestCaseID PBASE-T_FATCACHE_BM-0693 |
|
695 //! @SYMTestType PT |
|
696 //! @SYMPREQ PREQ1721 |
|
697 //! @SYMTestCaseDesc Create a large file (2G max) and measure the time. Then delete this file and measure time taken |
|
698 //! |
|
699 //! @SYMTestActions |
|
700 //! 0 quick format the volume |
|
701 //! 1 create emply file that takes either 80% of the volume of 2G max, masure time taken |
|
702 //! 2 remount FS |
|
703 //! 3 delete this file and measure time taken |
|
704 //! |
|
705 //! @SYMTestExpectedResults successful files creation/deletion |
|
706 //! @SYMTestPriority High |
|
707 //! @SYMTestStatus Implemented |
|
708 //---------------------------------------------------------------------------------------------- |
|
709 static void CreateLargeFile() |
|
710 { |
|
711 test.Next(_L("Create a large file and measure time\n")); |
|
712 |
|
713 FormatVolume(ETrue); //-- quick format the volume. |
|
714 |
|
715 _LIT(KBigFileName, "\\BigFile.big"); |
|
716 |
|
717 test(gBootSector.IsValid()); |
|
718 |
|
719 //-- calculate the size of the file, it shall be max 2G or take almost all volume |
|
720 TVolumeInfo volInfo; |
|
721 TInt nRes; |
|
722 |
|
723 nRes = TheFs.Volume(volInfo, gDriveNum); |
|
724 test_KErrNone(nRes); |
|
725 |
|
726 const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector(); |
|
727 const TUint32 maxClusters = (TUint32)(volInfo.iFree / clustSz); |
|
728 |
|
729 const TUint32 clustersPer1G = K1GigaByte / clustSz; |
|
730 const TUint32 clustersPer2G = 2*clustersPer1G; |
|
731 |
|
732 TUint32 fileClusters=0; |
|
733 if(maxClusters*0.8 < clustersPer2G) |
|
734 fileClusters = (TUint32)(maxClusters*0.8); |
|
735 else |
|
736 fileClusters = (TUint32)(clustersPer2G*0.8); |
|
737 |
|
738 const TUint32 fileSize = fileClusters*clustSz; |
|
739 |
|
740 //-- create empty file and measure time |
|
741 TTime timeStart; |
|
742 TTime timeEnd; |
|
743 TInt64 usTimeCreate=0; |
|
744 TInt64 usTimeDelete=0; |
|
745 |
|
746 timeStart.UniversalTime(); //-- take start time |
|
747 nRes = CreateEmptyFile(TheFs, KBigFileName, fileSize); |
|
748 timeEnd.UniversalTime(); //-- take end time |
|
749 test_KErrNone(nRes); |
|
750 |
|
751 usTimeCreate = (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
752 |
|
753 //-- remount file system, reset caches etc. |
|
754 DoRemountFS(gDriveNum); |
|
755 |
|
756 //-- delete the file |
|
757 timeStart.UniversalTime(); //-- take start time |
|
758 nRes = TheFs.Delete(KBigFileName); |
|
759 timeEnd.UniversalTime(); //-- take end time |
|
760 |
|
761 test_KErrNone(nRes); |
|
762 usTimeDelete = (timeEnd.MicroSecondsFrom(timeStart)).Int64(); |
|
763 |
|
764 test.Printf(_L("#--> Big file sz:%u created:%d ms, deleted:%d ms\n"), fileSize, (TUint32)(usTimeCreate/K1mSec) , (TUint32)(usTimeDelete/K1mSec)); |
|
765 |
|
766 } |
|
767 |
|
768 |
|
769 //------------------------------------------------------------------- |
|
770 /** |
|
771 Start tests. |
|
772 */ |
|
773 void RunTest() |
|
774 { |
|
775 test.Printf(_L("Prepare the volume for BM testing...\n")); |
|
776 |
|
777 test(pFTagArray != NULL); |
|
778 CFileTagsArray &fTagArray = *pFTagArray; |
|
779 fTagArray.Reset(); |
|
780 |
|
781 //-- full format the drive |
|
782 FormatVolume(EFalse); |
|
783 |
|
784 test.Printf(_L("\n#--> t_fatcache_bm\n")); |
|
785 |
|
786 //-- create test directory. |
|
787 MakeDir(KDirName); |
|
788 |
|
789 //-- 1. create KMaxFiles files to fill in space in FAT table. |
|
790 if(!DoCreateFiles(fTagArray)) |
|
791 return; //-- test is inconsistent |
|
792 |
|
793 |
|
794 //-- 1.1 create a file in the very end of the full volume (FAT table is almost full). Measure time taken |
|
795 CreateLastFile(); |
|
796 |
|
797 //-- 1.2 create multiple directories in the root and measure time |
|
798 // DoCreateDirsInRoot(); |
|
799 |
|
800 //-- 2. randomly merge some small files to bigger ones that will be fragmented |
|
801 DoMergeFiles(fTagArray); |
|
802 |
|
803 //-- 3. randomly shuffle file tags in the array |
|
804 ShuffleArray(fTagArray); |
|
805 |
|
806 //-- 4. measure file open and seek time |
|
807 MeasureSeekTime(fTagArray); |
|
808 |
|
809 //-- 4.5 Check that all copies of FAT are the same. |
|
810 CheckFatCopies(); |
|
811 |
|
812 //-- 5. delete all files and print out time taken |
|
813 DeleteAllFiles(fTagArray); |
|
814 |
|
815 //-- 6. Create a large file (2G max) and measure the time |
|
816 //!!!! |
|
817 CreateLargeFile(); |
|
818 |
|
819 } |
|
820 |
|
821 |
|
822 |
|
823 //------------------------------------------------------------------- |
|
824 static void WaitForFatBkGndActivityEnd() |
|
825 { |
|
826 //-- if we work in release mode, we need to use a hardcore solution to wait until possible FAT background activity finishes |
|
827 //-- because transient FAT threads can affect timings (e.g. creating a file may need waiting to FAT background thread to |
|
828 //-- parse some portion of FAT) etc. |
|
829 //-- for debug mode background FAT activity is disabled in InitGlobals() and timings are not precise anyway |
|
830 //-- for release mode we just need to wait some time |
|
831 #ifndef _DEBUG |
|
832 const TInt KWaitTimeSec = 10; |
|
833 test.Printf(_L("waiting %d sec...\n"), KWaitTimeSec); |
|
834 User::After(KWaitTimeSec*K1Sec); |
|
835 #endif |
|
836 |
|
837 } |
|
838 |
|
839 |
|
840 |
|
841 //------------------------------------------------------------------- |
|
842 |
|
843 /** |
|
844 Dismounts and mounts the FS on a drive aDrive |
|
845 This will cause resetting "last known free cluster number" value in the FAT table implementation in FSY. |
|
846 (Mounting enhancements are disabled.) Empty the caches etc. |
|
847 */ |
|
848 static void DoRemountFS(TInt aDrive) |
|
849 { |
|
850 TInt nRes = RemountFS(TheFs, aDrive); |
|
851 test_KErrNone(nRes); |
|
852 |
|
853 //-- get volume info, this is a trick that can help avoiding asynchronous FAT mount in UREL mode |
|
854 //TVolumeInfo v; |
|
855 //nRes = TheFs.Volume(v); |
|
856 |
|
857 //-- to avoid affected timings in UREL mode. |
|
858 WaitForFatBkGndActivityEnd(); |
|
859 } |
|
860 |
|
861 |
|
862 //------------------------------------------------------------------- |
|
863 |
|
864 /** initialise test global objects */ |
|
865 static void InitGlobals() |
|
866 { |
|
867 //-- initialise random generator |
|
868 gRndSeed = 0x67fc1a9; |
|
869 |
|
870 //-- construct file numbers array |
|
871 pFTagArray = new CFileTagsArray(KMaxFiles); |
|
872 test(pFTagArray != NULL); |
|
873 pFTagArray->SetReserveL(KMaxFiles); |
|
874 |
|
875 //-- define a propery which will control mount process in the fsy. |
|
876 //-- The property key is a drive number being tested |
|
877 _LIT_SECURITY_POLICY_PASS(KTestPropPolicy); |
|
878 TInt nRes = RProperty::Define(KThisTestSID, gDriveNum, RProperty::EInt, KTestPropPolicy, KTestPropPolicy); |
|
879 test(nRes == KErrNone || nRes == KErrAlreadyExists); |
|
880 |
|
881 //-- disable all volume mount enhancements, like asynch mount and FSInfo. |
|
882 //-- this works only in debug mode. |
|
883 nRes = RProperty::Set(KThisTestSID, gDriveNum, (TInt)KMntProp_DisableALL); |
|
884 test_KErrNone(nRes); |
|
885 |
|
886 } |
|
887 |
|
888 /** destroy test global objects */ |
|
889 static void DestroyGlobals() |
|
890 { |
|
891 delete pFTagArray; |
|
892 |
|
893 //-- delete test property |
|
894 RProperty::Delete(KThisTestSID, gDriveNum); |
|
895 |
|
896 } |
|
897 |
|
898 |
|
899 //------------------------------------------------------------------- |
|
900 void CallTestsL() |
|
901 { |
|
902 |
|
903 //-- set up console output |
|
904 Fat_Test_Utils::SetConsole(test.Console()); |
|
905 |
|
906 TInt nRes=TheFs.CharToDrive(gDriveToTest, gDriveNum); |
|
907 test(nRes==KErrNone); |
|
908 |
|
909 //-- check if this is FAT |
|
910 if(!Is_Fat(TheFs, gDriveNum)) |
|
911 { |
|
912 test.Printf(_L("Skipping. This test requires FAT drive.\n")); |
|
913 return; |
|
914 } |
|
915 |
|
916 //-- check this is not the internal ram drive |
|
917 TVolumeInfo v; |
|
918 nRes = TheFs.Volume(v); |
|
919 test(nRes==KErrNone); |
|
920 if(v.iDrive.iMediaAtt & KMediaAttVariableSize) |
|
921 { |
|
922 test.Printf(_L("Skipping. Internal ram drive not tested.\n")); |
|
923 return; |
|
924 } |
|
925 |
|
926 |
|
927 //------------------------------------- |
|
928 PrintDrvInfo(TheFs, gDriveNum); |
|
929 |
|
930 InitGlobals(); |
|
931 |
|
932 RunTest(); |
|
933 |
|
934 //------------------------------------- |
|
935 DestroyGlobals(); |
|
936 |
|
937 } |
|
938 |
|
939 |
|
940 |
|
941 |
|
942 |
|
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 |