diff -r 000000000000 -r a41df078684a kerneltest/f32test/filesystem/fat/t_fatcache_bm.cpp --- /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 +#include +#include +#include + +#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 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 buf; + RFile file; + + timeStart.UniversalTime(); //-- take start time + + for(i=0; i 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 buf; + + TTime timeStart; + TTime timeEnd; + TInt64 usTotalTimeSeek=0; + TInt64 usTotalTimeOpen=0; + + const TInt KNumRepetitions = 10; + + for(TInt repCnt=0; repCnt 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 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 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 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 %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(); + + } + + + + + + + + + + + + + + + + +