First public contribution.
1 // Copyright (c) 2004-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 // tests read/write throughput on two drives simultaneously
18 //! @file f32test\concur\t_cfsbench.cpp
26 //IMPORT_C TUint32 DebugRegister();
29 GLDEF_D RTest test(_L("T_CFSBENCH"));
32 LOCAL_D TFullName gFsName;
33 LOCAL_D TFullName gFsName1;
34 LOCAL_D TFullName gFsName2;
35 LOCAL_D TFullName gOldFsName;
36 LOCAL_D TFullName gNewFsName;
37 LOCAL_D TBool gNoMedia = ETrue;
39 _LIT(KFsFile, "CFAFSDLY");
40 _LIT(KFsName, "DelayFS");
42 LOCAL_D const TInt32 KSecond = 1000000;
43 LOCAL_D const TInt32 KTimeBM = 20;
46 LOCAL_D const TInt32 KBufLen = 0x100;
48 LOCAL_D const TInt32 KMaxLag = 4;
50 LOCAL_D TBool gVerbose = EFalse;
52 TBuf16<KBufLen> gResults;
54 const TInt KMaxFileSize = (4*1024*1024);
55 const TInt KMinBufferSize = (16);
56 const TInt KMaxBufferSize = (512*1024);
57 const TInt KMaxIter = 17;
60 TBool gReadTests = EFalse;
61 TBool gWriteTests = EFalse;
62 TBool gAsyncTests = EFalse;
63 TBool gSyncTests = EFalse;
66 LOCAL_C TInt32 GetSpeed(TInt aOps, TInt aBufSize, TInt64 aDtime)
67 /// Calculate and return the throughput from the umber of blocks transferred
68 /// and the elapsed time.
70 TInt64 dsize = MAKE_TINT64(0, aOps) * MAKE_TINT64(0, aBufSize) * MAKE_TINT64(0, KSecond);
71 TInt32 speed = I64LOW((dsize + aDtime/2) / aDtime);
75 LOCAL_C TBool DriveIsOK(TChar c)
76 /// Test that a selected drive leter is OK to write files.
80 r=TheFs.CharToDrive(c, drv);
84 r=TheFs.Drive(info,drv);
86 return (info.iDriveAtt != 0 && !(info.iDriveAtt & KDriveAttRom));
89 LOCAL_C TChar MountTestFileSystem(TInt aDrive)
91 // Mount a new CTestFileSystem on the drive under test
97 r=TheFs.DriveToChar(aDrive,c);
99 b.Format(_L("Mount test file system on %c:"),(TUint)c);
102 r=TheFs.AddFileSystem(KFsFile);
103 test(r==KErrNone || r==KErrAlreadyExists);
105 r=TheFs.FileSystemName(gOldFsName,aDrive);
106 test(r==KErrNone || r==KErrNotFound);
109 r = TheFs.Drive(drv, aDrive);
112 gNoMedia = (drv.iType == EMediaUnknown || drv.iType == EMediaNotPresent);
114 if (gOldFsName.Length() > 0)
116 TTest::Printf(_L("Dismount %C: %S"), (TUint)c, &gOldFsName);
117 r=TheFs.DismountFileSystem(gOldFsName,aDrive);
121 r=TheFs.MountFileSystem(KFsName,aDrive);
124 r=TheFs.FileSystemName(gNewFsName,aDrive);
126 test(gNewFsName.CompareF(KFsName)==0);
130 LOCAL_C void UnmountFileSystem(TInt aDrive)
131 /// Unmount a test filesystem and mount the old one.
134 TInt r=TheFs.DriveToChar(aDrive,c);
136 r=TheFs.DismountFileSystem(gNewFsName,aDrive);
138 // if there's no media present, don't try to mount it
141 test.Printf(_L("No media on %C: so don't remount it"), (TUint)c);
143 else if (gOldFsName.Length() > 0)
145 test.Printf(_L("Mount %C: %S"), (TUint)c, &gOldFsName);
146 r=TheFs.MountFileSystem(gOldFsName,aDrive);
150 test.Printf(_L("Error %d remounting %S on %C\n"), r, &gOldFsName, (TUint)c);
153 LOCAL_C void RemountFileSystem(TInt aDrive, TBool aSync)
154 /// Unmount and remount the file system on the specified drive in the
156 /// @param aDrive Drive number (EDriveC etc.).
157 /// @param aSync Mount synchronous if true, asynchronous if not.
160 TInt r=TheFs.DriveToChar(aDrive,c);
161 r=TheFs.FileSystemName(gFsName, aDrive);
162 test(r==KErrNone || r==KErrNotFound);
164 if (gFsName.Length() > 0)
166 r=TheFs.DismountFileSystem(gFsName, aDrive);
169 test.Printf(_L("Error = %d"),r);
174 TBufC<16> type = _L("asynchronous");
176 type = _L("synchronous");
178 test.Printf(_L("Mount filesystem %c: %-8S as %S\n"), (TUint)c, &gFsName, &type);
180 #ifdef __CONCURRENT_FILE_ACCESS__
181 r=TheFs.MountFileSystem(gFsName, aDrive, aSync);
183 r=TheFs.MountFileSystem(gFsName, aDrive);
196 // ---------------------------------------------------------------------------
199 /// Do operations on a file.
211 TInt Init(TChar dr, TInt aBufSize);
213 void CalculateFreeSpace();
215 TInt Open(TOper aOper);
223 TInt CreateReadFile();
227 TFileName iNameWrite;
230 HBufC8* iBuffer[KMaxLag];
231 TPtr8* iBufPtr[KMaxLag];
233 TRequestStatus iStatus[KMaxLag];
245 TInt iFileSyncAccesses;
246 TInt iFileAsyncAccesses;
249 RFileOps::RFileOps() : iPtr(0), iNum(0), iOps(0), iMax(0), iOpen(EFalse)
251 for (TInt i = 0; i < KMaxLag; i++)
253 iStatus[i] = KErrNone;
260 TInt RFileOps::Init(TChar aDrvCh, TInt aBufSize)
268 iNameWrite.Format(_L("%c:\\TESTWT"), (TUint)aDrvCh);
269 iNameRead.Format(_L("%c:\\TESTRD"), (TUint)aDrvCh);
271 for (TInt i = 0; i < KMaxLag; i++)
273 iStatus[i] = KErrNone;
275 iBuffer[i] = HBufC8::NewL(aBufSize);
276 if (iBuffer[i] == NULL)
278 iBufPtr[i] = new TPtr8(iBuffer[i]->Des());
279 //TPtr8 buffer(iBuffer[i]->Des());
280 //buffer.Fill(TChar('_'), aBufSize);
281 iBufPtr[i]->Fill(TChar('_'), aBufSize);
287 void RFileOps::DeInit()
291 for (TInt i = 0; i < KMaxLag; i++)
301 void RFileOps::CalculateFreeSpace()
307 TInt r = TheFs.CharToDrive(iDrvCh, drv);
309 TTest::Fail(HERE, _L("CharToDrive(%c) returned %d"), (TUint)iDrvCh, r);
311 r = TheFs.Volume(vol, drv);
313 TTest::Fail(HERE, _L("Volume(%c:) returned %d"), (TUint)iDrvCh, r);
317 TInt64 fileSize = iFree / 2;
318 if (fileSize > KMaxFileSize)
319 fileSize = KMaxFileSize;
320 iFileSize = I64LOW(fileSize);
323 // calculate the number of buffers to use
324 // if we assume we'll be able to use half the available disk space
325 TInt max = iFileSize / iBufSize;
330 test.Printf(_L("Free space on drive %c = %d KB\n"), (TUint)iDrvCh, I64LOW(iFree/1024));
331 test.Printf(_L("File Size = %d KB. Using %d buffers of size %d\n"), iFileSize/1024, iMax, iBufSize);
337 TInt RFileOps::Open(TOper aOper)
338 /// Open the file for testing, give error if there is not enough space for it.
347 iFileSyncAccesses = 0;
348 iFileAsyncAccesses = 0;
350 TheFs.Delete(iNameWrite);
354 r = iF.Open(TheFs, iNameRead, EFileStreamText | EFileRead);
359 r = iF.Size(sizeFile);
363 test.Printf(_L("File Size = %d, %d buffers of size %d\n"), sizeFile, iMax, iBufSize);
365 iMax = sizeFile / iBufSize;
369 CalculateFreeSpace();
373 test.Printf(_L("Insufficient free space on drive %c, deleting read file\n"), (TUint)iDrvCh);
375 TheFs.Delete(iNameRead);
376 CalculateFreeSpace();
377 test.Printf(_L("Old available buffers = %d, new available buffers = %d\n"), maxOld, iMax);
380 TTest::Fail(HERE, _L("Not enough space to do test, only %d KB available. Only %d buffers of %d bytes available"),
381 I64LOW(iFree/1024), iMax, iBufSize );
383 r = iF.Replace(TheFs, iNameWrite, EFileStreamText | EFileWrite);
395 // Close and delete the file, returning the number of operations done.
396 TInt RFileOps::Close()
404 // always delete the write file
405 TheFs.Delete(iNameWrite);
411 TInt RFileOps::Delete()
413 TInt r = TheFs.Delete(iNameRead);
414 r = TheFs.Delete(iNameWrite);
419 TInt RFileOps::Reset()
420 /// Reset all of the counts.
430 TInt RFileOps::CreateReadFile()
434 CalculateFreeSpace(); // get iMax
441 r = iF.Open(TheFs, iNameRead, EFileStreamText | EFileRead);
445 test.Printf(_L("temp file already exists.\n"));
452 r = iF.Replace(TheFs, iNameRead, EFileStreamText | EFileWrite);
461 test.Printf(_L("Creating temp file on drive %c of size %d..."), (TUint)iDrvCh, iFileSize);
463 HBufC8* buf = HBufC8::NewL(KMaxBufferSize);
464 TPtr8 bufptr(buf->Des());
465 bufptr.Fill(TChar('_'), KMaxBufferSize);
468 for (TInt pos=0; pos<iFileSize; pos+= buf->Length())
470 r = iF.Write(pos, bufptr);
472 test.Printf(_L("Write() returned %d\n"), r);
476 delete buf; buf = NULL;
479 test.Printf(_L("Done.\n"));
487 TInt RFileOps::Write()
488 /// If there is a free buffer available, start a write.
493 while (iNum < iOps && iStatus[iNum%KMaxLag] != KRequestPending)
495 TInt status = iStatus[iNum%KMaxLag].Int();
496 test (status == KErrNone);
500 if (iOps < KMaxLag || iStatus[iPtr] != KRequestPending)
502 TInt pos = iOps%iMax * iBufSize;
504 iF.Write(pos, *iBufPtr[iPtr], iStatus[iPtr]);
506 TInt status = iStatus[iPtr].Int();
510 test.Printf(_L("Writing buf #%d to drive %c at pos %d, status = %d\n"),
511 iPtr, (TUint)iDrvCh, pos, status);
513 test (status == KErrNone || status == KRequestPending);
523 TInt RFileOps::Read()
524 /// If there is a free buffer available, start a read.
529 while (iNum < iOps && iStatus[iNum%KMaxLag] != KRequestPending)
531 TInt status = iStatus[iNum%KMaxLag].Int();
532 if (status != KErrNone)
533 test.Printf(_L("drive %c, iNum = %d, iOps=%d, Status = %d\n"), (TUint)iDrvCh, iNum, iOps, status);
534 test (status == KErrNone);
538 if (iOps < KMaxLag || iStatus[iPtr] != KRequestPending)
540 TInt pos = iOps%iMax * iBufSize;
542 iBufPtr[iPtr]->SetLength(0);
544 iF.Read(pos, *iBufPtr[iPtr], iStatus[iPtr]);
546 TInt len = iBufPtr[iPtr]->Length();
547 TInt status = iStatus[iPtr].Int();
551 if (status == KErrNone)
554 if (len < iBufPtr[iPtr]->MaxLength())
557 else if (status == KRequestPending)
559 iFileAsyncAccesses++;
566 if (gVerbose || err != KErrNone)
568 test.Printf(_L("Reading buf #%d, drive %c, pos %d, status %d, len %d, iNum %d, iOps %d, iMax %d\n"),
569 iPtr, (TUint)iDrvCh, pos, status, len, iNum, iOps, iMax);
572 test (err == KErrNone);
578 // have we wrapped to postion zero ?
579 if (iOps % iMax == 0)
589 /// Wait until all outstanding operations have ended, then return the number.
595 test.Printf(_L("Waiting for reads/writes to %c to complete, iNum=%d, iOps=%d...\n"), (TUint)iDrvCh, iNum, iOps);
599 if (iStatus[iNum%KMaxLag] == KRequestPending)
601 User::WaitForRequest(iStatus[iNum%KMaxLag]);
605 TInt status = iStatus[iNum%KMaxLag].Int();
606 if (gVerbose || (status != KErrNone && status != KRequestPending))
607 test.Printf(_L("Buf#%d: Status = %d\n"), iNum, status);
608 test (status == KErrNone || status == KRequestPending);
616 LOCAL_C TInt testAsyncAccess(
626 // Test one drive against the other.
640 TRequestStatus tstat;
643 TTimeIntervalMicroSeconds timeTaken(0);
646 aThroughput1 = aThroughput2 = 0;
648 if (aBufSize1 == 0 && aBufSize2 == 0)
654 r = TheFs.DriveToChar(aDrive1, dc1);
656 r = TheFs.DriveToChar(aDrive2, dc2);
660 r = f1.Init(dc1, aBufSize1);
662 r = f2.Init(dc2, aBufSize2);
666 _LIT(KSync, " sync");
667 _LIT(KAsync, "async");
669 test.Printf(_L("%c: (%S) %d, %c: (%S) %d\n"),
671 aSync1?&KSync:&KAsync,
674 aSync2?&KSync:&KAsync,
677 RemountFileSystem(aDrive1, aSync1);
678 RemountFileSystem(aDrive2, aSync2);
682 //********************************************************************
684 //********************************************************************
688 r = f1.CreateReadFile();
693 r = f2.CreateReadFile();
698 r = f1.Open(RFileOps::ERead);
702 r = f2.Open(RFileOps::ERead);
706 timer.After(tstat, KTimeBM * KSecond);
708 startTime.HomeTime();
710 while (tstat == KRequestPending)
718 User::WaitForAnyRequest();
728 timeTaken=endTime.MicroSecondsFrom(startTime);
730 //********************************************************************
732 //********************************************************************
737 //********************************************************************
739 //********************************************************************
742 r = f1.Open(RFileOps::EWrite);
748 r = f2.Open(RFileOps::EWrite);
752 timer.After(tstat, KTimeBM * KSecond);
754 startTime.HomeTime();
756 while (tstat == KRequestPending)
764 User::WaitForAnyRequest();
775 timeTaken=endTime.MicroSecondsFrom(startTime);
777 //********************************************************************
779 //********************************************************************
783 dtime = timeTaken.Int64();
785 aThroughput1 = GetSpeed(op1, aBufSize1, dtime);
786 aThroughput2 = GetSpeed(op2, aBufSize2, dtime);
788 test.Printf(_L("%c:,%c:,%10d,%10d,%10d,%10d\n"),
789 (TUint)dc1, (TUint)dc2,
798 test.Printf(_L("%c: %d async reads, %d sync reads, wraps = %d\n"),
799 (TUint)dc1, f1.iFileAsyncAccesses, f1.iFileSyncAccesses, f1.iFileWraps);
800 test.Printf(_L("%c: %d async reads, %d sync reads, wraps = %d\n"),
801 (TUint)dc2, f2.iFileAsyncAccesses, f2.iFileSyncAccesses, f2.iFileWraps);
817 LOCAL_C TInt parseCmd(TChar& aDrvCh1, TChar& aDrvCh2)
818 /// Get parameters from the comand line; if there aren't enough then
819 /// prompt the user for them and return KErrAbort if ^C is pressed.
821 while (aDrvCh1 < 'A' || aDrvCh1 > 'Z')
823 test.Printf(_L("Enter drive letter: "));
824 while (aDrvCh1 < 'A' || aDrvCh1 > 'Z')
828 aDrvCh1 = User::UpperCase(test.Getch());
830 if (!DriveIsOK(aDrvCh1))
832 test.Printf(_L("%c: is not a valid drive\n"), (TUint)aDrvCh1);
838 TheFs.CharToDrive(aDrvCh1, drv);
839 TheFs.FileSystemName(gFsName1, drv);
840 test.Printf(_L("%c: (%S)\n"), (TUint)aDrvCh1, &gFsName1);
844 while (aDrvCh2 < 'A' || aDrvCh2 > 'Z')
846 test.Printf(_L("Enter drive letter: "));
847 while (aDrvCh2 < 'A' || aDrvCh2 > 'Z')
851 aDrvCh2 = User::UpperCase(test.Getch());
853 if (!DriveIsOK(aDrvCh2))
855 test.Printf(_L("%c: is not a valid drive\n"), (TUint)aDrvCh2);
861 TheFs.CharToDrive(aDrvCh2, drv);
862 TheFs.FileSystemName(gFsName2, drv);
863 test.Printf(_L("%c: (%S)\n"), (TUint)aDrvCh2, &gFsName2);
870 typedef TInt RESULTS[KMaxIter][KMaxIter];
871 LOCAL_C void PrintResults(RESULTS& aResults, TChar aDrvCh, TChar aDrvCh2)
874 TInt drive1Index, drive2Index;
876 test.Printf(_L("*** Throughput for drive %c ***\n"), (TUint)aDrvCh);
878 test.Printf(_L(" BufferSize (%C:)....\n"), (TUint)aDrvCh2);
880 for (bufSize2 = drive2Index = 0; bufSize2 <= KMaxBufferSize; bufSize2 = bufSize2 << 1, drive2Index++)
882 gResults.AppendFormat(_L("%10d,"), bufSize2);
884 bufSize2 = KMinBufferSize >> 1;
886 test.Printf(_L("%S\n"), &gResults);
888 for (drive1Index = 0; drive1Index < KMaxIter; drive1Index++)
891 for (drive2Index = 0; drive2Index < KMaxIter; drive2Index++)
893 gResults.AppendFormat(_L("%10d,"), aResults[drive1Index][drive2Index]);
895 test.Printf(_L("%S\n"), &gResults);
904 GLDEF_C void CallTestsL()
906 TInt r = TTest::Init();
914 const TInt KMaxArgs = 5;
915 TPtrC argv[KMaxArgs];
916 TInt argc = TTest::ParseCommandArguments(argv, KMaxArgs);
918 drvch1 = User::UpperCase(argv[1][0]);
920 drvch2 = User::UpperCase(argv[2][0]);
922 TBool testFs = EFalse;
924 for (TInt n=3; n<argc; n++)
928 if (argv[n].Compare(_L("verbose")) == 0)
930 if (argv[n].Compare(_L("read")) == 0)
932 if (argv[n].Compare(_L("write")) == 0)
935 if (argv[n].Compare(_L("async")) == 0)
937 if (argv[n].Compare(_L("sync")) == 0)
940 if (argv[n].Compare(_L("testfs")) == 0)
945 if ((!gReadTests && !gWriteTests) ||
946 (!gAsyncTests && !gSyncTests))
948 test.Printf(_L("T_CFSPERFORM - tests read/write throughput on two drives simultaneously\n"));
949 test.Printf(_L("Syntax : t_cfsperform <Drive1> <Drive2> [verbose] [testfs] read|write sync|async\n"));
950 test.Printf(_L("Where : async = concurrent access, sync = non-concurrent access\n"));
951 test.Printf(_L("E.g. : t_cfsperform c d read async\n"));
952 test.Printf(_L("Press any key"));
954 test.Printf(_L("\n"));
959 r = parseCmd(drvch1, drvch2);
962 User::Panic(_L("USER ABORT"), 0);
965 r = TheFs.CharToDrive(drvch1, drive1);
967 r = TheFs.CharToDrive(drvch2, drive2);
970 r = TheFs.FileSystemName(gFsName1, drive1);
971 test(r == KErrNone || r == KErrNotFound);
972 r = TheFs.FileSystemName(gFsName2, drive2);
973 test(r == KErrNone || r == KErrNotFound);
977 MountTestFileSystem(drive1);
978 MountTestFileSystem(drive2);
985 // delete temp files before starting
995 TInt resultsDrive1[KMaxIter][KMaxIter];
996 TInt resultsDrive2[KMaxIter][KMaxIter];
1000 test.Printf(_L(" BufSize(%c) BufSize(%c) ThruPut(%c) ThruPut(%c) \n"),
1001 (TUint)drvch1, (TUint)drvch2, (TUint)drvch1, (TUint)drvch2);
1003 for (bufSize1 = drive1Index = 0; bufSize1 <= KMaxBufferSize; bufSize1 = bufSize1 << 1, drive1Index++)
1005 for (bufSize2 = drive2Index = 0; bufSize2 <= KMaxBufferSize; bufSize2 = bufSize2 << 1, drive2Index++)
1008 // // !!! Disable platform security tests until we get the new APIs
1009 // if (User::Capability() & KCapabilityRoot)
1011 // CheckMountLFFS(TheFs, drvch1);
1012 // CheckMountLFFS(TheFs, drvch2);
1016 test.Printf(_L("Using drives %c: (%S) and %c: (%S)\n"),
1017 (TUint)drvch1, &gFsName1, (TUint)drvch2, &gFsName2);
1019 TInt throughputDrive1;
1020 TInt throughputDrive2;
1021 TBool sync = EFalse;
1029 throughputDrive1, throughputDrive2);
1031 resultsDrive1[drive1Index][drive2Index] = throughputDrive1;
1032 resultsDrive2[drive1Index][drive2Index] = throughputDrive2;
1034 // buffer size sequence is 0,16,32,64,128, ...
1036 bufSize2 = KMinBufferSize >> 1;
1038 // buffer size sequence is 0,16,32,64,128, ...
1040 bufSize1 = KMinBufferSize >> 1;
1045 PrintResults(resultsDrive1, drvch1, drvch2);
1046 PrintResults(resultsDrive2, drvch2, drvch2);
1051 UnmountFileSystem(drive1);
1052 UnmountFileSystem(drive2);
1058 GLDEF_C TInt E32Main()
1064 CTrapCleanup* cleanup;
1065 cleanup=CTrapCleanup::New();
1069 test.Start(_L("Starting tests..."));
1074 // TheFs.SetAllocFailure(gAllocFailOn);
1078 TRAP(r,CallTestsL());
1080 // reset the debug register
1081 TheFs.SetDebugRegister(0);
1084 endTimeC.HomeTime();
1085 TTimeIntervalSeconds timeTakenC;
1086 r=endTimeC.SecondsFrom(timerC,timeTakenC);
1088 test.Printf(_L("Time taken for test = %d seconds\n"),timeTakenC.Int());
1089 // TheFs.SetAllocFailure(gAllocFailOff);