--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/filesystem/fat/t_fatcache_bm.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,954 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32test\server\t_mount.cpp
+// Testing FAT cache performance
+//
+//
+
+/**
+ @file
+*/
+
+#define __E32TEST_EXTENSION__
+
+#include <f32file.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <e32property.h>
+
+#include "t_server.h"
+//#include "t_std.h"
+
+#include "fat_utils.h"
+
+using namespace Fat_Test_Utils;
+
+#ifdef __VC32__
+ // Solve compilation problem caused by non-English locale
+ #pragma setlocale("english")
+#endif
+
+RTest test(_L("T_FAT_Cache_BM"));
+
+//-- note that this test disables all FAT mount enhancements, like asynchronous mounting and using FSInfo sector.
+
+static void WaitForFatBkGndActivityEnd();
+
+//-------------------------------------------------------------------
+//-- debug bit flags that may be set in the property which controls FAT volume mounting
+
+const TUid KThisTestSID={0x10210EB3}; ///< this EXE SID
+
+//const TUint32 KMntProp_EnableALL = 0x00000000; //-- enable all operations
+const TUint32 KMntProp_DisableALL = 0xFFFFFFFF; //-- disable all operations
+
+//const TUint32 KMntProp_Disable_FsInfo = 0x00000001; //-- mask for disabling/enabling FSInfo information
+//const TUint32 KMntProp_Disable_FatBkGndScan = 0x00000002; //-- mask for disabling/enabling FAT background scanner
+
+//-------------------------------------------------------------------
+
+static TInt gDriveNum=-1; ///< drive number we are dealing with
+static TInt64 gRndSeed;
+static TFatBootSector gBootSector;
+
+static void DoRemountFS(TInt aDrive);
+
+//-- Array of integer file tars. Tags are used to identify files (the file name is generated by KFnTemplate template)
+typedef CArrayFixFlat<TInt> CFileTagsArray;
+static CFileTagsArray *pFTagArray = NULL;
+
+
+//-------------------------------------------------------------------
+const TInt KMaxFiles = 1000; //-- maximal number of files to create
+
+//-- number of unfragmented files that will be left, other files will be merged to bigger ones.
+const TInt KUnfragmentedFilesLeave = KMaxFiles/10;
+
+_LIT(KDirName, "\\DIR1\\"); //-- directory name we a working with (FAT12/16 won't allow KMaxFiles in the root dir.)
+_LIT(KFirstFileName, "\\First_file_1.nul"); //-- the name of the first file on the volume
+
+//-------------------------------------------------------------------
+
+/**
+ Make a file name by its numeric tag
+ @param aDes here will be a file name
+ @param aFileNameTag numeric tag for the file name generation
+
+*/
+void MakeFileName(TDes& aDes, TInt aFileNameTag)
+{
+ _LIT(KFnTemplate, "F%d.NUL");//-- file name template, use 8.3 names here in order not to stress dir. cache much.
+ aDes.Copy(KDirName);
+ aDes.AppendFormat(KFnTemplate, aFileNameTag);
+}
+
+//-------------------------------------------------------------------
+/**
+ format the volume and read the boot sector
+*/
+static void FormatVolume(TBool aQuickFormat)
+{
+ (void)aQuickFormat;
+
+ #ifndef __EPOC32__
+ test.Printf(_L("This is emulator configuration!!!!\n"));
+
+ //-- FAT32 SPC:1; for the FAT32 testing on the emulator
+ //TFatFormatParam fp;
+ //fp.iFatType = EFat32;
+ //fp.iSecPerCluster = 1;
+ //FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fp); //-- always quick; doesn't matter for the emulator
+
+ aQuickFormat = ETrue;
+ #endif
+
+
+ FormatFatDrive(TheFs, CurrentDrive(), aQuickFormat);
+
+
+ TInt nRes = ReadBootSector(TheFs, gDriveNum, 0x00, gBootSector);
+ test_KErrNone(nRes);
+}
+
+
+//-------------------------------------------------------------------
+
+/**
+ Helper method. Does one iteration of merging test files into one fragmented one.
+ See DoMergeFiles()
+
+ @param aFTagArray reference to the file tags array
+ @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)
+ @param aTimeTaken_us on return will contain time taken to this operation, in microseconds
+
+ @return number of files merged into one.
+*/
+TInt DoMergeTestFiles(CFileTagsArray& aFTagArray, TInt aBigFileNo, TInt64& aTimeTaken_us)
+{
+
+ aTimeTaken_us = 0;
+ TTime timeStart;
+ TTime timeEnd;
+
+
+ //-- merged files' names start with this number
+ const TInt KMergedFileFnThreshold = 20000;
+
+ const TInt KMaxMergedFiles = 20;
+ const TInt nFilesToMerge = Max((Math::Rand(gRndSeed) % KMaxMergedFiles), 2); //-- how many files to merge into one
+
+ test(aFTagArray.Count() > KMaxMergedFiles);
+
+ TInt selectedFTags[KMaxMergedFiles]; //-- here we will store file tags to be merged to one large fragmented file
+ TInt i;
+ TInt nRes;
+
+ i=0;
+ do
+ {
+ //-- randomly select a file tag from the global array
+ const TInt index = (TUint)Math::Rand(gRndSeed) % aFTagArray.Count();
+ const TInt fnTag = aFTagArray[index];
+
+ if(fnTag < 0 || //-- no such file, already deleted
+ fnTag >= KMergedFileFnThreshold) //-- this is a big, already merged file
+ continue;
+
+
+ selectedFTags[i] = fnTag;
+ aFTagArray.Delete(index);
+
+ ++i;
+ }while(i<nFilesToMerge);
+
+ //-- here we have file tags in selectedFNumbers array. delete these files and create one big file
+ //-- with the equal size. This file will be perfectly fragmented.
+ //-- search for FAT entries had priority to the right, so delete files in reverse order.
+
+ TUint32 newFileSize = 0;
+ TBuf<128> buf;
+ RFile file;
+
+ timeStart.UniversalTime(); //-- take start time
+
+ for(i=0; i<nFilesToMerge; ++i)
+ {
+ MakeFileName(buf, selectedFTags[nFilesToMerge-1-i]);
+
+ nRes=file.Open(TheFs, buf, EFileRead);
+ test_KErrNone(nRes);
+
+ TInt nSize;
+ nRes = file.Size(nSize);
+ test_KErrNone(nRes);
+ file.Close();
+
+ newFileSize+=(TUint32)nSize; //-- this will be the size of the new file
+
+ //-- delete small file
+ nRes = TheFs.Delete(buf);
+ test_KErrNone(nRes);
+
+ }
+
+ //-- create a large file taking the place of few smaller. It will be framented.
+ const TInt bigFileTag = aBigFileNo+KMergedFileFnThreshold;
+
+ MakeFileName(buf, bigFileTag);
+ nRes = CreateEmptyFile(TheFs, buf, newFileSize);
+ test_KErrNone(nRes);
+
+ timeEnd.UniversalTime(); //-- take end time
+ aTimeTaken_us = (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ //-- put new big file name tag to the global array in order not to forget it for later use.
+ aFTagArray.AppendL(bigFileTag);
+
+ return nFilesToMerge;
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0689
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc randomly deletes small files and creates larger. Measures time taken by this FAT fragmentation
+//!
+//! @SYMTestActions
+//! 0 delete a random number of small files
+//! 1 create a random number of larger files, measure time taken
+//!
+//! @SYMTestExpectedResults successful files deletion/creation
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+
+/**
+ precondition: We have a lot of (KMaxFiles) files of the same size on the volume. They occupy almost all FAT.
+ This method randomly selects several files on the volume, deletes them and creates a bigger file that occupies space from the
+ deleted files. So that we got a fragmented big file. Repeat this until we have KUnfragmentedFilesLeave initial files left on the
+ volume.
+*/
+void DoMergeFiles(CFileTagsArray& aFTagArray)
+{
+ test.Next(_L("Merging small files to larger creating FAT fragmentation...\n"));
+
+ TInt64 usTotalTime=0;
+ TInt64 usCurrTime;
+
+ TInt nUnfragmentedLeft = aFTagArray.Count();
+ for(TInt i=0; nUnfragmentedLeft > KUnfragmentedFilesLeave; ++i)
+ {
+ nUnfragmentedLeft -= DoMergeTestFiles(aFTagArray, i, usCurrTime);
+ usTotalTime += usCurrTime;
+ }
+
+ test.Printf(_L("#--> Merging files :%d ms\n"), (TUint32)usTotalTime/K1mSec);
+}
+
+//-------------------------------------------------------------------
+/**
+ Randomly shuffles entries in file name tags array.
+*/
+void ShuffleArray(CFileTagsArray& aFTagArray)
+{
+ const TInt KSwapIterations = 500;
+ const TInt arrSize = aFTagArray.Count();
+
+
+ for(TInt i = 0; i<KSwapIterations; ++i)
+ {//-- randomly swap 2 elements in the array
+ const TInt idx1 = (TUint)Math::Rand(gRndSeed) % arrSize;
+ const TInt idx2 = (TUint)Math::Rand(gRndSeed) % arrSize;
+
+ TInt tmp = aFTagArray[idx1];
+ aFTagArray[idx1] = aFTagArray[idx2];;
+ aFTagArray[idx2] = tmp;
+ }
+
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0690
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Measure open and seek time for all files that have tags in aFTagArray.
+//!
+//! @SYMTestActions
+//! 0 remount FS
+//! 1 open all files, that have tags in aFTagArray, measure time taken
+//! 2 seek to the each file end, measure time taken
+//!
+//! @SYMTestExpectedResults successful files open/seek
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+void MeasureSeekTime(CFileTagsArray& aFTagArray)
+{
+ test.Next(_L("Measuring seek time...\n"));
+
+ TInt nRes;
+ RFile file;
+ TBuf<128> buf;
+
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTotalTimeSeek=0;
+ TInt64 usTotalTimeOpen=0;
+
+ const TInt KNumRepetitions = 10;
+
+ for(TInt repCnt=0; repCnt<KNumRepetitions; ++repCnt)
+ {
+ //-- remount file system, reset caches
+ DoRemountFS(gDriveNum);
+
+ for(TInt i = 0; i<aFTagArray.Count(); ++i)
+ {
+ MakeFileName(buf, aFTagArray[i]);
+
+ //-- 1. open the file
+ timeStart.UniversalTime(); //-- take start time
+
+ nRes = file.Open(TheFs, buf, EFileRead);
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTimeOpen += (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test_KErrNone(nRes);
+
+
+ //-- 2. goto the end of the file. This operation shall traverse whole file's cluster chain in FAT
+ timeStart.UniversalTime(); //-- take start time
+
+ TInt seekPos = 0;
+ nRes = file.Seek(ESeekEnd, seekPos);
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTimeSeek += (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test_KErrNone(nRes);
+ file.Close();
+ }
+ }
+
+ test.Printf(_L("#--> Total open time for %d files is %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTimeOpen/(K1mSec*KNumRepetitions));
+ test.Printf(_L("#--> Total seek time for %d files is %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTimeSeek/(K1mSec*KNumRepetitions));
+}
+
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0692
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Detetes all files that have name tags in name tags array and measures time taken.
+//!
+//! @SYMTestActions
+//! 0 remount the FS
+//! 1 delete files and measure time taken.
+//!
+//! @SYMTestExpectedResults successful creating files
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+void DeleteAllFiles(CFileTagsArray& aFTagArray)
+{
+ TInt nRes;
+ TBuf<128> buf;
+
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTotalTime=0;
+
+ test.Next(_L("Deleting all files...\n"));
+
+ //-- remount file system, reset caches
+ DoRemountFS(gDriveNum);
+
+ for(TInt i = 0; i<aFTagArray.Count(); ++i)
+ {
+ MakeFileName(buf, aFTagArray[i]);
+
+ timeStart.UniversalTime(); //-- take start time
+
+ nRes = TheFs.Delete(buf);
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTime += (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test_KErrNone(nRes);
+ }
+
+ test.Printf(_L("#--> Deleted %d files in %d ms\n"), aFTagArray.Count(), (TUint32)usTotalTime/K1mSec);
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0687
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Create KMaxFiles files to fill in space in FAT table and measure time taken.
+//!
+//! @SYMTestActions
+//! 0 Create KMaxFiles files and measure time taken.
+//!
+//! @SYMTestExpectedResults successful creating files
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+/**
+ Create KMaxFiles files to fill in space in FAT table and measure time taken.
+ @return EFalse if it is impossible to create test files
+*/
+TBool DoCreateFiles(CFileTagsArray& aFTagArray)
+{
+ TInt nRes;
+ TBuf<128> buf;
+
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTotalTime=0;
+
+ test.Next(_L("Creating many files\n"));
+ test.Printf(_L("Number of files:%d\n"), KMaxFiles);
+
+ aFTagArray.Reset();
+
+ TVolumeInfo volInfo;
+ nRes = TheFs.Volume(volInfo, gDriveNum);
+ test_KErrNone(nRes);
+
+
+ test(gBootSector.IsValid());
+
+ const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector();
+ const TUint32 maxClusters = (TUint32)(volInfo.iFree / clustSz);
+
+ if(KMaxFiles > 0.8 * maxClusters)
+ {
+ test.Printf(_L("Can't create %d files; skipping the test!\n"), KMaxFiles);
+ return EFalse;
+ }
+
+ //-- adjust file size for very small volumes
+ TUint32 fillFileSz = (maxClusters/KMaxFiles)*clustSz;
+ if(fillFileSz*KMaxFiles >= 0.8*volInfo.iFree) //-- take into account the size of the directory with 1000 files.
+ {
+ if(fillFileSz <= clustSz)
+ {
+ test.Printf(_L("Can't create %d files; skipping the test!\n"), KMaxFiles);
+ return EFalse;
+ }
+
+ fillFileSz -= clustSz;
+ }
+
+ //-- create the first file on the volume. It will be deleted then in order to create 1 free FAT entry
+ //-- in the very beginnng of the FAT. So, the size of this file shan't be more that 1 sector/cluster.
+ nRes = CreateEmptyFile(TheFs, KFirstFileName, 100);
+ test_KErrNone(nRes);
+
+
+ //-- to avoid affected timings in UREL mode.
+ WaitForFatBkGndActivityEnd();
+
+ //-- disable FAT test utils print out, it affects measured time when we create empty files
+ EnablePrintOutput(EFalse);
+
+ //-- create KMaxFiles files on the volume
+ for(TInt i=0; i<KMaxFiles; ++i)
+ {
+ //-- create empty file
+ MakeFileName(buf, i);
+
+ timeStart.UniversalTime(); //-- take start time
+
+ nRes = CreateEmptyFile(TheFs, buf, fillFileSz);
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTime += (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test_KErrNone(nRes);
+ //-- put its id number to the array.
+ aFTagArray.AppendL(i);
+
+ if((i % 100) == 0)
+ test.Printf(_L("*"));
+
+ }
+
+ EnablePrintOutput(ETrue); //-- Enable FAT test utils print out
+
+ test.Printf(_L("\n#--> Created %d files in %d ms\n"), KMaxFiles, (TUint32)usTotalTime/K1mSec);
+
+ return ETrue;
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0691
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Check that all FAT copies are the same.
+//!
+//! @SYMTestActions
+//! 0 read all available FAT copies and compare them
+//!
+//! @SYMTestExpectedResults all FAT copies on the vollume must be the same.
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+void CheckFatCopies()
+{
+ test.Next(_L("Comparing FATs...\n"));
+
+ TFatBootSector bootSec;
+
+ TInt nRes = ReadBootSector(TheFs, gDriveNum, 0x00, bootSec);
+ test_KErrNone(nRes);
+
+ const TInt numFATs = bootSec.NumberOfFats();
+ if(numFATs < 2)
+ {//-- only one FAT, nothing to compare with.
+ test.Printf(_L("The volume has only 1 FAT. Nothing to do.\n"));
+ return;
+ }
+
+ const TUint32 bytesPerSec = bootSec.BytesPerSector();
+ const TUint32 posFat1Start = bootSec.FirstFatSector() * bytesPerSec;
+ const TUint32 fatSize = bootSec.TotalFatSectors() * bytesPerSec;
+
+ RBuf8 fatBuf1;
+ RBuf8 fatBuf2;
+
+ nRes = fatBuf1.CreateMax(bytesPerSec);
+ test_KErrNone(nRes);
+
+ nRes = fatBuf2.CreateMax(bytesPerSec);
+ test_KErrNone(nRes);
+
+ //-- read FAT sector by sector comparing all copies
+ TUint32 currPos = posFat1Start;
+ for(TUint cntSectors=0; cntSectors<bootSec.TotalFatSectors(); ++cntSectors)
+ {
+ //-- read a sector of FAT#0
+ nRes = MediaRawRead(TheFs, gDriveNum, currPos, bytesPerSec, fatBuf1);
+ test_KErrNone(nRes);
+
+ //-- read the same sector from other copies of FAT and compare with FAT#0
+ for(TInt currFat=1; currFat<numFATs; ++currFat)
+ {
+ nRes = MediaRawRead(TheFs, gDriveNum, (currFat*fatSize + currPos), bytesPerSec, fatBuf2);
+ test_KErrNone(nRes);
+
+ //-- compare the buffer to FAT#0
+ if(fatBuf1.CompareF(fatBuf2) !=0)
+ {//-- current FAT is different from FAT0
+ test.Printf(_L("FAT#%d differs from FAT#0! FAT sector:%d, media Sector:%d\n"), currFat, cntSectors, cntSectors+bootSec.FirstFatSector());
+ test(0);
+ }
+
+ }
+
+
+ currPos+=bytesPerSec;
+ }
+
+
+ fatBuf1.Close();
+ fatBuf2.Close();
+
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0688
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Create the file whose FAT entries will go to the end of the FAT table and measure the time taken.
+//!
+//! @SYMTestActions
+//! 0 delete a file in the very beginning of the FAT
+//! 1 remount file system
+//! 2 create a larger file finishing at the end of FAT, measure time taken
+//!
+//! @SYMTestExpectedResults successful files creation
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+
+/**
+ Create the file whose FAT entries will go to the end of the FAT table and measure the time taken.
+ preconditions:
+ 1. The FAT table must be almost full already. This is done previously in DoCreateFiles().
+ 2. There shall be a small file in the very beginning of the FAT which this test deletes and remounts the FS.
+ this will cause "the last known free cluster" in the FAT to be set to the beginning of the FAT.
+
+ Then when we create a larger file, whole occupied FAT region will be scanned for the free cluster.
+*/
+void CreateLastFile()
+{
+ test.Next(_L("Create a file in the end of FAT\n"));
+
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTotalTime=0;
+
+ TInt nRes;
+
+
+ //-- 1. delete the first file on the volume (see KFirstFileName & DoCreateFiles()
+ //-- it will create free FAT entry in the very beginning.
+ nRes = TheFs.Delete(KFirstFileName);
+ test_KErrNone(nRes);
+
+
+ //-- 2. remount file system, reset caches etc. The first known free cluster will be number 2 or 3, because of the point 1.
+ //-- the rest of the FAT is filled, because we've created plenty of files in the DoCreateFiles()
+ DoRemountFS(gDriveNum);
+
+ //-- 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,
+ //-- and the rest will be in the very end of the FAT. Measure the time taken to walk all FAT when searching free entry.
+ _LIT(KLastFn, "\\last-last.file");
+
+ test(gBootSector.IsValid());
+
+ const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector();
+
+
+ //-- disable FAT test utils print out, it affects measured time
+ EnablePrintOutput(EFalse);
+
+ timeStart.UniversalTime(); //-- take start time
+
+ //-- create an empty file, it is supposed to be placed in the very end of FAT (FAT table is almost full because of the
+ //-- previous test)
+ nRes = CreateEmptyFile(TheFs, KLastFn, 7*clustSz);
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTime = (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test_KErrNone(nRes);
+
+ test.Printf(_L("#--> file at the end of FAT created in %d ms\n"), (TUint32)usTotalTime/K1mSec);
+
+ //-- delete the file
+ nRes = TheFs.Delete(KLastFn);
+ test_KErrNone(nRes);
+
+ EnablePrintOutput(ETrue); //-- Enable FAT test utils print out
+}
+
+//-------------------------------------------------------------------
+/**
+ Create 100 directories in the root and measure time
+*/
+void DoCreateDirsInRoot()
+{
+ test.Next(_L("Measure time to create many directories in the Root.\n"));
+
+ if(!Is_Fat32(TheFs, gDriveNum))
+ {
+ test.Printf(_L("This test requires FAT32, skipping\n"));
+ return;
+ }
+
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTotalTime=0;
+ TFileName dirName;
+
+ //-- remount file system, reset caches etc. The first known free cluster will be number 2 or 3
+ DoRemountFS(gDriveNum);
+
+ //-- disable FAT test utils print out, it affects measured time
+ EnablePrintOutput(EFalse);
+
+ timeStart.UniversalTime(); //-- take start time
+
+ //-- create some subdirectories in the root dir and measure time
+ const TInt KMaxDirs = 100;
+ for(TInt i=0; i<KMaxDirs; ++i)
+ {
+ dirName.Format(_L("\\directory%04d\\"), i);
+ TInt nRes = TheFs.MkDir(dirName);
+ test_KErrNone(nRes);
+ }
+
+ timeEnd.UniversalTime(); //-- take end time
+ usTotalTime = (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test.Printf(_L("#--> %d Dirs. created in %d ms\n"), KMaxDirs, (TUint32)usTotalTime/K1mSec);
+
+ EnablePrintOutput(ETrue); //-- Enable FAT test utils print out
+}
+
+//----------------------------------------------------------------------------------------------
+//! @SYMTestCaseID PBASE-T_FATCACHE_BM-0693
+//! @SYMTestType PT
+//! @SYMPREQ PREQ1721
+//! @SYMTestCaseDesc Create a large file (2G max) and measure the time. Then delete this file and measure time taken
+//!
+//! @SYMTestActions
+//! 0 quick format the volume
+//! 1 create emply file that takes either 80% of the volume of 2G max, masure time taken
+//! 2 remount FS
+//! 3 delete this file and measure time taken
+//!
+//! @SYMTestExpectedResults successful files creation/deletion
+//! @SYMTestPriority High
+//! @SYMTestStatus Implemented
+//----------------------------------------------------------------------------------------------
+static void CreateLargeFile()
+{
+ test.Next(_L("Create a large file and measure time\n"));
+
+ FormatVolume(ETrue); //-- quick format the volume.
+
+ _LIT(KBigFileName, "\\BigFile.big");
+
+ test(gBootSector.IsValid());
+
+ //-- calculate the size of the file, it shall be max 2G or take almost all volume
+ TVolumeInfo volInfo;
+ TInt nRes;
+
+ nRes = TheFs.Volume(volInfo, gDriveNum);
+ test_KErrNone(nRes);
+
+ const TUint32 clustSz = gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector();
+ const TUint32 maxClusters = (TUint32)(volInfo.iFree / clustSz);
+
+ const TUint32 clustersPer1G = K1GigaByte / clustSz;
+ const TUint32 clustersPer2G = 2*clustersPer1G;
+
+ TUint32 fileClusters=0;
+ if(maxClusters*0.8 < clustersPer2G)
+ fileClusters = (TUint32)(maxClusters*0.8);
+ else
+ fileClusters = (TUint32)(clustersPer2G*0.8);
+
+ const TUint32 fileSize = fileClusters*clustSz;
+
+ //-- create empty file and measure time
+ TTime timeStart;
+ TTime timeEnd;
+ TInt64 usTimeCreate=0;
+ TInt64 usTimeDelete=0;
+
+ timeStart.UniversalTime(); //-- take start time
+ nRes = CreateEmptyFile(TheFs, KBigFileName, fileSize);
+ timeEnd.UniversalTime(); //-- take end time
+ test_KErrNone(nRes);
+
+ usTimeCreate = (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ //-- remount file system, reset caches etc.
+ DoRemountFS(gDriveNum);
+
+ //-- delete the file
+ timeStart.UniversalTime(); //-- take start time
+ nRes = TheFs.Delete(KBigFileName);
+ timeEnd.UniversalTime(); //-- take end time
+
+ test_KErrNone(nRes);
+ usTimeDelete = (timeEnd.MicroSecondsFrom(timeStart)).Int64();
+
+ test.Printf(_L("#--> Big file sz:%u created:%d ms, deleted:%d ms\n"), fileSize, (TUint32)(usTimeCreate/K1mSec) , (TUint32)(usTimeDelete/K1mSec));
+
+}
+
+
+//-------------------------------------------------------------------
+/**
+ Start tests.
+*/
+void RunTest()
+{
+ test.Printf(_L("Prepare the volume for BM testing...\n"));
+
+ test(pFTagArray != NULL);
+ CFileTagsArray &fTagArray = *pFTagArray;
+ fTagArray.Reset();
+
+ //-- full format the drive
+ FormatVolume(EFalse);
+
+ test.Printf(_L("\n#--> t_fatcache_bm\n"));
+
+ //-- create test directory.
+ MakeDir(KDirName);
+
+ //-- 1. create KMaxFiles files to fill in space in FAT table.
+ if(!DoCreateFiles(fTagArray))
+ return; //-- test is inconsistent
+
+
+ //-- 1.1 create a file in the very end of the full volume (FAT table is almost full). Measure time taken
+ CreateLastFile();
+
+ //-- 1.2 create multiple directories in the root and measure time
+// DoCreateDirsInRoot();
+
+ //-- 2. randomly merge some small files to bigger ones that will be fragmented
+ DoMergeFiles(fTagArray);
+
+ //-- 3. randomly shuffle file tags in the array
+ ShuffleArray(fTagArray);
+
+ //-- 4. measure file open and seek time
+ MeasureSeekTime(fTagArray);
+
+ //-- 4.5 Check that all copies of FAT are the same.
+ CheckFatCopies();
+
+ //-- 5. delete all files and print out time taken
+ DeleteAllFiles(fTagArray);
+
+ //-- 6. Create a large file (2G max) and measure the time
+ //!!!!
+ CreateLargeFile();
+
+}
+
+
+
+//-------------------------------------------------------------------
+static void WaitForFatBkGndActivityEnd()
+{
+ //-- if we work in release mode, we need to use a hardcore solution to wait until possible FAT background activity finishes
+ //-- because transient FAT threads can affect timings (e.g. creating a file may need waiting to FAT background thread to
+ //-- parse some portion of FAT) etc.
+ //-- for debug mode background FAT activity is disabled in InitGlobals() and timings are not precise anyway
+ //-- for release mode we just need to wait some time
+ #ifndef _DEBUG
+ const TInt KWaitTimeSec = 10;
+ test.Printf(_L("waiting %d sec...\n"), KWaitTimeSec);
+ User::After(KWaitTimeSec*K1Sec);
+ #endif
+
+}
+
+
+
+//-------------------------------------------------------------------
+
+/**
+ Dismounts and mounts the FS on a drive aDrive
+ This will cause resetting "last known free cluster number" value in the FAT table implementation in FSY.
+ (Mounting enhancements are disabled.) Empty the caches etc.
+*/
+static void DoRemountFS(TInt aDrive)
+{
+ TInt nRes = RemountFS(TheFs, aDrive);
+ test_KErrNone(nRes);
+
+ //-- get volume info, this is a trick that can help avoiding asynchronous FAT mount in UREL mode
+ //TVolumeInfo v;
+ //nRes = TheFs.Volume(v);
+
+ //-- to avoid affected timings in UREL mode.
+ WaitForFatBkGndActivityEnd();
+}
+
+
+//-------------------------------------------------------------------
+
+/** initialise test global objects */
+static void InitGlobals()
+{
+ //-- initialise random generator
+ gRndSeed = 0x67fc1a9;
+
+ //-- construct file numbers array
+ pFTagArray = new CFileTagsArray(KMaxFiles);
+ test(pFTagArray != NULL);
+ pFTagArray->SetReserveL(KMaxFiles);
+
+ //-- define a propery which will control mount process in the fsy.
+ //-- The property key is a drive number being tested
+ _LIT_SECURITY_POLICY_PASS(KTestPropPolicy);
+ TInt nRes = RProperty::Define(KThisTestSID, gDriveNum, RProperty::EInt, KTestPropPolicy, KTestPropPolicy);
+ test(nRes == KErrNone || nRes == KErrAlreadyExists);
+
+ //-- disable all volume mount enhancements, like asynch mount and FSInfo.
+ //-- this works only in debug mode.
+ nRes = RProperty::Set(KThisTestSID, gDriveNum, (TInt)KMntProp_DisableALL);
+ test_KErrNone(nRes);
+
+}
+
+/** destroy test global objects */
+static void DestroyGlobals()
+{
+ delete pFTagArray;
+
+ //-- delete test property
+ RProperty::Delete(KThisTestSID, gDriveNum);
+
+}
+
+
+//-------------------------------------------------------------------
+void CallTestsL()
+ {
+
+ //-- set up console output
+ Fat_Test_Utils::SetConsole(test.Console());
+
+ TInt nRes=TheFs.CharToDrive(gDriveToTest, gDriveNum);
+ test(nRes==KErrNone);
+
+ //-- check if this is FAT
+ if(!Is_Fat(TheFs, gDriveNum))
+ {
+ test.Printf(_L("Skipping. This test requires FAT drive.\n"));
+ return;
+ }
+
+ //-- check this is not the internal ram drive
+ TVolumeInfo v;
+ nRes = TheFs.Volume(v);
+ test(nRes==KErrNone);
+ if(v.iDrive.iMediaAtt & KMediaAttVariableSize)
+ {
+ test.Printf(_L("Skipping. Internal ram drive not tested.\n"));
+ return;
+ }
+
+
+ //-------------------------------------
+ PrintDrvInfo(TheFs, gDriveNum);
+
+ InitGlobals();
+
+ RunTest();
+
+ //-------------------------------------
+ DestroyGlobals();
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+