kerneltest/f32test/concur/t_cfsbench.cpp
changeset 9 96e5fb8b040d
child 43 c1f20ce4abcf
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     1 // Copyright (c) 2002-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 // Do benchmarking comparisons in asynchronous and synchronous modes.
       
    15 //
       
    16 //
       
    17 
       
    18 //! @file f32test\concur\t_cfsbench.cpp
       
    19 
       
    20 #include <f32file.h>
       
    21 #include <e32test.h>
       
    22 #include <f32dbg.h>
       
    23 #include "t_server.h"
       
    24 #include "t_tdebug.h"
       
    25 
       
    26 // The following #defines are for using older (and less accurate) benchmark
       
    27 // timings.  They use multiple threads to get the operations simultaneous
       
    28 // but this is inherrently inaccurate (it depends whether one of them starts
       
    29 // and/or ends before the other how accurate the timings are).  If you leave
       
    30 // them both commented out then the tests will be done in a single thread
       
    31 // using asynchronous file operations, thus avoiding the problem.
       
    32 
       
    33 // Uncomment the following if you want to test asynchronous file operations
       
    34 // using two threads rather than in a single thread.
       
    35 
       
    36 // #define TEST_ASYNC_IN_THREAD
       
    37 
       
    38 // Uncomment the following if you want to test using synchronous file
       
    39 // operations, using two threads to do both at once.
       
    40 
       
    41 // #define TEST_SYNC_IN_THREAD
       
    42 
       
    43 struct TStats
       
    44 //
       
    45 // Statistics -- size and time of operations.
       
    46 //
       
    47 	{
       
    48 	TInt64 iSize;
       
    49 	TInt64 iTime;
       
    50 	void Init() { iSize = 0; iTime = 0; }
       
    51 	};
       
    52 
       
    53 GLDEF_D RTest test(_L("T_CFSBENCH"));
       
    54 GLDEF_D	RFs TheFs;
       
    55 
       
    56 LOCAL_D TFullName gFsName;
       
    57 LOCAL_D TFullName gFsName1;
       
    58 LOCAL_D TFullName gFsName2;
       
    59 LOCAL_D TFullName gOldFsName;
       
    60 LOCAL_D TFullName gNewFsName;
       
    61 LOCAL_D TBool     gNoMedia = ETrue;
       
    62 
       
    63 #if defined(TEST_SYNC_IN_THREAD) || defined(TEST_ASYNC_IN_THREAD)
       
    64 LOCAL_D TInt      gThreadNumber = 0;
       
    65 #endif
       
    66 
       
    67 LOCAL_D RMutex gDataLock;
       
    68 LOCAL_D TStats gWrStats;
       
    69 LOCAL_D TStats gRdStats;
       
    70 
       
    71 _LIT(KFsFile, "CFAFSDLY");
       
    72 _LIT(KFsName, "DelayFS");
       
    73 
       
    74 LOCAL_D const TInt32 KSecond = 1000000;
       
    75 LOCAL_D const TInt32 KTimeBM = 20;
       
    76 LOCAL_D const TInt32 KNumBuf = 100;
       
    77 LOCAL_D const TInt32 KBufLen = 0x100;
       
    78 LOCAL_D const TInt32 KMaxThr = 10;
       
    79 LOCAL_D const TInt32 KMaxLag = 4;
       
    80 
       
    81 LOCAL_D TBuf8<KBufLen> gBufferArr[KMaxThr][KNumBuf];
       
    82 LOCAL_D TRequestStatus gStatusArr[KMaxThr][KNumBuf];
       
    83 
       
    84 LOCAL_C void AddStats(TStats& aStats, TInt64 aSize, TInt64 aTime)
       
    85 /// Add values to the statistics.
       
    86 	{
       
    87 	gDataLock.Wait();
       
    88 	aStats.iSize += aSize;
       
    89 	aStats.iTime += aTime;
       
    90 	gDataLock.Signal();
       
    91 	}
       
    92 
       
    93 LOCAL_C TInt GetSpeed(TStats& aStats)
       
    94 /// Calculate and return the data throughput from the statistics, rounded.
       
    95 	{
       
    96 	gDataLock.Wait();
       
    97 	TInt speed = I64LOW((aStats.iSize + aStats.iTime/2) / aStats.iTime);
       
    98 	gDataLock.Signal();
       
    99 	return speed;
       
   100 	}
       
   101 
       
   102 LOCAL_C TInt32 GetSpeed(TInt aOps, TInt64 aDtime)
       
   103 /// Calculate and return the throughput from the umber of blocks transferred
       
   104 /// and the elapsed time.
       
   105 	{
       
   106 	TInt64 dsize = MAKE_TINT64(0, aOps) * MAKE_TINT64(0, KBufLen) * MAKE_TINT64(0, KSecond);
       
   107 	TInt32 speed = I64LOW((dsize + aDtime/2) / aDtime);
       
   108 	return speed;
       
   109 	}
       
   110 
       
   111 LOCAL_C TBool DriveIsOK(TChar c)
       
   112 /// Test that a selected drive leter is OK to write files.
       
   113 	{
       
   114 	TInt r;
       
   115 	TInt drv;
       
   116 	r=TheFs.CharToDrive(c, drv);
       
   117 	if (r != KErrNone)
       
   118 		return EFalse;
       
   119 	TDriveInfo info;
       
   120 	r=TheFs.Drive(info,drv);
       
   121 	test(r==KErrNone);
       
   122 	return (info.iDriveAtt != 0 && !(info.iDriveAtt & KDriveAttRom));
       
   123 	}
       
   124 
       
   125 LOCAL_C TChar MountTestFileSystem(TInt aDrive)
       
   126 //
       
   127 // Mount a new CTestFileSystem on the drive under test
       
   128 //
       
   129 	{
       
   130 	TInt r;
       
   131 	TBuf<64> b;
       
   132 	TChar c;
       
   133 	r=TheFs.DriveToChar(aDrive,c);
       
   134 	test(r==KErrNone);
       
   135 	b.Format(_L("Mount test file system on %c:"),(TUint)c);
       
   136 	test.Next(b);
       
   137 
       
   138 	r=TheFs.AddFileSystem(KFsFile);
       
   139 	test(r==KErrNone || r==KErrAlreadyExists);
       
   140 
       
   141 	r=TheFs.FileSystemName(gOldFsName,aDrive);
       
   142 	test(r==KErrNone || r==KErrNotFound);
       
   143 
       
   144 	TDriveInfo drv;
       
   145 	r = TheFs.Drive(drv, aDrive);
       
   146 	test(r == KErrNone);
       
   147 
       
   148 	gNoMedia = (drv.iType == EMediaUnknown || drv.iType == EMediaNotPresent);
       
   149 
       
   150 	if (gOldFsName.Length() > 0)
       
   151 		{
       
   152 		TTest::Printf(_L("Dismount %C: %S"), (TUint)c, &gOldFsName);
       
   153 		r=TheFs.DismountFileSystem(gOldFsName,aDrive);
       
   154 		test(r==KErrNone);
       
   155 		}
       
   156 
       
   157 	r=TheFs.MountFileSystem(KFsName,aDrive);
       
   158 	test(r==KErrNone);
       
   159 
       
   160 	r=TheFs.FileSystemName(gNewFsName,aDrive);
       
   161 	test(r==KErrNone);
       
   162 	test(gNewFsName.CompareF(KFsName)==0);
       
   163 	return c;
       
   164 	}
       
   165 
       
   166 LOCAL_C void UnmountFileSystem(TInt aDrive)
       
   167 /// Unmount a test filesystem and mount the old one.
       
   168 	{
       
   169 	TChar c;
       
   170 	TInt r=TheFs.DriveToChar(aDrive,c);
       
   171 	test(r==KErrNone);
       
   172 	r=TheFs.DismountFileSystem(gNewFsName,aDrive);
       
   173 	test(r==KErrNone);
       
   174 	// if there's no media present, don't try to mount it
       
   175 	if (gNoMedia)
       
   176 		{
       
   177 		test.Printf(_L("No media on %C: so don't remount it"), (TUint)c);
       
   178 		}
       
   179 	else if (gOldFsName.Length() > 0)
       
   180 		{
       
   181 		test.Printf(_L("Mount    %C: %S"), (TUint)c, &gOldFsName);
       
   182 		r=TheFs.MountFileSystem(gOldFsName,aDrive);
       
   183 		test(r==KErrNone);
       
   184 		}
       
   185 	if (r != KErrNone)
       
   186 		test.Printf(_L("Error %d remounting %S on %C\n"), r, &gOldFsName, (TUint)c);
       
   187 	}
       
   188 
       
   189 LOCAL_C void RemountFileSystem(TInt aDrive, TBool aSync)
       
   190 /// Unmount and remount the file system on the specified drive in the
       
   191 /// selected mode.
       
   192 /// @param aDrive Drive number (EDriveC etc.).
       
   193 /// @param aSync  Mount synchronous if true, asynchronous if not.
       
   194 	{
       
   195 	TChar c;
       
   196 	TInt r=TheFs.DriveToChar(aDrive,c);
       
   197 	r=TheFs.FileSystemName(gFsName, aDrive);
       
   198 	test(r==KErrNone || r==KErrNotFound);
       
   199 
       
   200 	if (gFsName.Length() > 0)
       
   201 		{
       
   202 		r=TheFs.DismountFileSystem(gFsName, aDrive);
       
   203 		if(r!=KErrNone)
       
   204 			{
       
   205 			test.Printf(_L("Error = %d"),r);
       
   206 			test(EFalse);
       
   207 			}
       
   208 		}
       
   209 
       
   210 	TBufC<16> type = _L("asynchronous");
       
   211 	if (aSync)
       
   212 		type = _L("synchronous");
       
   213 	test.Printf(_L("Mount filesystem %c: %-8S as %S\n"), (TUint)c, &gFsName, &type);
       
   214 
       
   215 #ifdef __CONCURRENT_FILE_ACCESS__
       
   216 	r=TheFs.MountFileSystem(gFsName, aDrive, aSync);
       
   217 #else
       
   218 	r=TheFs.MountFileSystem(gFsName, aDrive);
       
   219 #endif
       
   220 
       
   221 	test(r==KErrNone);
       
   222 	}
       
   223 
       
   224 enum TOper
       
   225 	{
       
   226 	ERead,
       
   227 	EWrite
       
   228 	};
       
   229 
       
   230 // ---------------------------------------------------------------------------
       
   231 
       
   232 #if defined(TEST_SYNC_IN_THREAD)
       
   233 
       
   234 LOCAL_C TInt testSyncAccess(TAny* aData)
       
   235 ///
       
   236 /// Test read file handling.
       
   237 ///
       
   238 /// @param aData pointer to the thread data area
       
   239     {
       
   240 	TThreadData& data = *(TThreadData*)aData;
       
   241 	TFileName fileName = data.iFile;
       
   242 	TBool     dowrite  = (data.iData != NULL);
       
   243 
       
   244 	RFs   myFs;
       
   245 	TInt r = myFs.Connect();
       
   246 	TEST(r==KErrNone);
       
   247 
       
   248 	r = myFs.SetSessionPath(gSessionPath);
       
   249 	if (r != KErrNone)
       
   250 		TTest::Fail(HERE, _L("SetSessionPath returned %d"), r);
       
   251 
       
   252 	TVolumeInfo vol;
       
   253 	TInt        drv;
       
   254 	r = myFs.CharToDrive(fileName[0], drv);
       
   255 	if (r != KErrNone)
       
   256 		TTest::Fail(HERE, _L("CharToDrive(%c) returned %d"), fileName[0], r);
       
   257 	r = myFs.Volume(vol, drv);
       
   258 	if (r != KErrNone)
       
   259 		TTest::Fail(HERE, _L("Volume() returned %d"), r);
       
   260 
       
   261 	TInt maxwrite = TInt(vol.iFree / 2 - KBufLen);
       
   262 	if (maxwrite < KBufLen*2)
       
   263 		TTest::Fail(HERE, _L("Not enough space to do test, only %d KB available"),
       
   264 					 TInt(vol.iFree/1024));
       
   265 
       
   266     RFile f;
       
   267 	RTimer timer;
       
   268 	TTime startTime;
       
   269 	TTime endTime;
       
   270 	TTimeIntervalMicroSeconds timeTaken;
       
   271 
       
   272 	TBuf8<KBufLen> buff;
       
   273 	TRequestStatus tstat;
       
   274 
       
   275 	TInt wrnum = 0;
       
   276 	TInt rdnum = 0;
       
   277 
       
   278 	timer.CreateLocal();
       
   279 
       
   280 	if (dowrite)
       
   281 		{
       
   282 		// write tests
       
   283 
       
   284 		r = f.Replace(myFs, fileName, EFileStreamText | EFileWrite);
       
   285 		TEST(r==KErrNone);
       
   286 
       
   287 		// wait for both tasks to have a chance to complete opening the files
       
   288 		User::After(1000);
       
   289 
       
   290 		buff.Fill('_', KBufLen);
       
   291 
       
   292 		timer.After(tstat, KTimeBM * KSecond);
       
   293 
       
   294 		startTime.HomeTime();
       
   295 
       
   296 		while (tstat == KRequestPending)
       
   297 			{
       
   298 			TInt pos = (wrnum * KBufLen) % maxwrite;
       
   299 			r = f.Write(pos, buff);
       
   300 			TEST(r==KErrNone);
       
   301 			++wrnum;
       
   302 			}
       
   303 
       
   304 		endTime.HomeTime();
       
   305 		timeTaken=endTime.MicroSecondsFrom(startTime);
       
   306 
       
   307 		TInt64 dtime = timeTaken.Int64();
       
   308 		TInt64 dsize = wrnum * KBufLen * TInt64(KSecond);
       
   309 		TInt32 speed = TInt32((dsize + dtime/2) / dtime);
       
   310 		AddStats(gWrStats, dsize, dtime);
       
   311 
       
   312 		TTest::Printf(_L("%8d writes in %6d mS = %8d bytes per second\n"),
       
   313 					  wrnum, TInt32(dtime)/1000, speed);
       
   314 
       
   315 		timer.Cancel();
       
   316 		f.Close();
       
   317 		}
       
   318 	else
       
   319 		{
       
   320 		// read tests
       
   321 
       
   322 		r = f.Open(myFs, fileName, EFileStreamText);
       
   323 		TEST(r==KErrNone);
       
   324 
       
   325 		// wait for both tasks to have a chance to complete opening the files
       
   326 		User::After(1000);
       
   327 
       
   328 		timer.After(tstat, KTimeBM * KSecond);
       
   329 
       
   330 		startTime.HomeTime();
       
   331 
       
   332 		while (tstat == KRequestPending)
       
   333 			{
       
   334 			TInt pos = (rdnum * KBufLen) % maxwrite;
       
   335 			r = f.Read(pos, buff, KBufLen);
       
   336 			TEST(r==KErrNone);
       
   337 			++rdnum;
       
   338 			}
       
   339 
       
   340 		endTime.HomeTime();
       
   341 		timeTaken=endTime.MicroSecondsFrom(startTime);
       
   342 
       
   343 		TInt64 dtime = timeTaken.Int64();
       
   344 		TInt64 dsize = rdnum * KBufLen * TInt64(KSecond);
       
   345 		TInt32 speed = TInt32((dsize + dtime/2) / dtime);
       
   346 		AddStats(gRdStats, dsize, dtime);
       
   347 
       
   348 		// wait to allow the dust to settle
       
   349 		User::After(KSecond);
       
   350 
       
   351 		TTest::Printf(_L("%8d reads  in %6d mS = %8d bytes per second\n"),
       
   352 					  rdnum, TInt32(dtime)/1000, speed);
       
   353 
       
   354 		timer.Cancel();
       
   355 		timer.Close();
       
   356 		f.Close();
       
   357 
       
   358 		// delete file after reading it
       
   359 		myFs.Delete(fileName);
       
   360 		}
       
   361 
       
   362 	myFs.Close();
       
   363 	return r;
       
   364     }
       
   365 
       
   366 #endif
       
   367 
       
   368 // ---------------------------------------------------------------------------
       
   369 
       
   370 #if defined(TEST_ASYNC_IN_THREAD)
       
   371 
       
   372 LOCAL_C TInt testAsyncAccess(TAny* aData)
       
   373 //
       
   374 /// Test read file handling.
       
   375 ///
       
   376 /// @param aData pointer to the thread data area
       
   377     {
       
   378 	TThreadData& data = *(TThreadData*)aData;
       
   379 	TFileName fileName = data.iFile;
       
   380 	TBool     dowrite  = (data.iData != NULL);
       
   381 	TBuf8<KBufLen>* buffer = gBufferArr[data.iNum];
       
   382 	TRequestStatus* status = gStatusArr[data.iNum];
       
   383 
       
   384 	RFs   myFs;
       
   385 	TInt r = myFs.Connect();
       
   386 	TEST(r==KErrNone);
       
   387 
       
   388 	r = myFs.SetSessionPath(gSessionPath);
       
   389 	if (r != KErrNone)
       
   390 		TTest::Fail(HERE, _L("SetSessionPath returned %d"), r);
       
   391 
       
   392 	TVolumeInfo vol;
       
   393 	TInt        drv;
       
   394 	r = myFs.CharToDrive(fileName[0], drv);
       
   395 	if (r != KErrNone)
       
   396 		TTest::Fail(HERE, _L("CharToDrive(%c) returned %d"), fileName[0], r);
       
   397 	r = myFs.Volume(vol, drv);
       
   398 	if (r != KErrNone)
       
   399 		TTest::Fail(HERE, _L("Volume() returned %d"), r);
       
   400 
       
   401 	TInt64 maxwrite = vol.iFree / 2 - KBufLen;
       
   402 	if (maxwrite < KBufLen*2)
       
   403 		TTest::Fail(HERE, _L("Not enough space to do test, only %d KB available"),
       
   404 					 TInt(vol.iFree/1024));
       
   405 
       
   406     RFile f;
       
   407 	RTimer timer;
       
   408 	TRequestStatus tstat;
       
   409 	TTime startTime;
       
   410 	TTime endTime;
       
   411 	TTimeIntervalMicroSeconds timeTaken;
       
   412 
       
   413 	TInt wrnum = 0;
       
   414 	TInt rdnum = 0;
       
   415 	TInt opnum = 0;
       
   416 	TInt opfin = 0;
       
   417 	TInt i;
       
   418 
       
   419 	timer.CreateLocal();
       
   420 
       
   421 	if (dowrite)
       
   422 		{
       
   423 		r = f.Replace(myFs, fileName, EFileStreamText | EFileWrite);
       
   424 		TEST(r==KErrNone);
       
   425 
       
   426 		// wait for both tasks to have a chance to complete opening the files
       
   427 		User::After(1000);
       
   428 
       
   429 		for (i = 0; i < KNumBuf; i++)
       
   430 			buffer[i].Fill('_', KBufLen);
       
   431 
       
   432 		timer.After(tstat, KTimeBM * KSecond);
       
   433 
       
   434 		startTime.HomeTime();
       
   435 
       
   436 		while (tstat == KRequestPending)
       
   437 			{
       
   438 			TInt pos = TInt((wrnum * KBufLen) % maxwrite);
       
   439 			TInt bnum = opnum++ % KNumBuf;
       
   440 			f.Write(pos, buffer[bnum], status[bnum]);
       
   441 			if (opnum - opfin > KMaxLag)
       
   442 				{
       
   443 				while (status[opfin % KNumBuf] == KRequestPending)
       
   444 					User::WaitForRequest(status[opfin % KNumBuf]);
       
   445 				opfin++;
       
   446 				}
       
   447 			++wrnum;
       
   448 			}
       
   449 
       
   450 		while (opfin < opnum)
       
   451 			{
       
   452 			while (status[opfin % KNumBuf] == KRequestPending)
       
   453 				User::WaitForRequest(status[opfin % KNumBuf]);
       
   454 			opfin++;
       
   455 			}
       
   456 
       
   457 		endTime.HomeTime();
       
   458 		TTimeIntervalMicroSeconds timeTaken=endTime.MicroSecondsFrom(startTime);
       
   459 
       
   460 		TInt64 dtime = timeTaken.Int64();
       
   461 		TInt64 dsize = wrnum * KBufLen * TInt64(KSecond);
       
   462 		TInt32 speed = TInt32((dsize + dtime/2) / dtime);
       
   463 		AddStats(gWrStats, dsize, dtime);
       
   464 
       
   465 		TTest::Printf(_L("%8d writes in %6d mS = %8d bytes per second\n"),
       
   466 					  wrnum, TInt32(dtime)/1000, speed);
       
   467 		}
       
   468 	else
       
   469 		{
       
   470 		r = f.Open(myFs, fileName, EFileStreamText);
       
   471 		TEST(r==KErrNone);
       
   472 
       
   473 		timer.After(tstat, KTimeBM * KSecond);
       
   474 
       
   475 		startTime.HomeTime();
       
   476 
       
   477 		while (tstat == KRequestPending)
       
   478 			{
       
   479 			TInt pos = TInt((rdnum * KBufLen) % maxwrite);
       
   480 			TInt bnum = opnum++ % KNumBuf;
       
   481 			f.Read(pos, buffer[bnum], status[bnum]);
       
   482 			if (opnum - opfin > KMaxLag)
       
   483 				{
       
   484 				User::WaitForRequest(status[opfin++ % KNumBuf]);
       
   485 				}
       
   486 			++rdnum;
       
   487 			}
       
   488 
       
   489 		while (opfin < opnum)
       
   490 			{
       
   491 			if (status[opfin % KNumBuf] == KRequestPending)
       
   492 				User::WaitForRequest(status[opfin % KNumBuf]);
       
   493 			opfin++;
       
   494 			}
       
   495 
       
   496 		endTime.HomeTime();
       
   497 		timeTaken=endTime.MicroSecondsFrom(startTime);
       
   498 		TInt64 dtime = timeTaken.Int64();
       
   499 		TInt64 dsize = rdnum * KBufLen * TInt64(KSecond);
       
   500 		TInt32 speed = TInt32((dsize + dtime/2) / dtime);
       
   501 		AddStats(gRdStats, dsize, dtime);
       
   502 
       
   503 		// wait to allow the dust to settle
       
   504 		User::After(KSecond);
       
   505 
       
   506 		TTest::Printf(_L("%8d reads  in %6d mS = %8d bytes per second\n"),
       
   507 					  rdnum, TInt32(dtime)/1000, speed);
       
   508 
       
   509 		myFs.Delete(fileName);
       
   510 		}
       
   511 
       
   512 	timer.Cancel();
       
   513 	timer.Close();
       
   514 	f.Close();
       
   515 	myFs.Close();
       
   516 	return r;
       
   517     }
       
   518 
       
   519 #endif
       
   520 
       
   521 // ---------------------------------------------------------------------------
       
   522 
       
   523 class TFileOps
       
   524 /// Do operations on a file.
       
   525 	{
       
   526 public:
       
   527 	TFileOps();
       
   528 	TInt Open(TChar dr, TInt n);
       
   529 	TInt Close();
       
   530 	TInt Reset();
       
   531 	TInt Erase();
       
   532 	TInt Write();
       
   533 	TInt Read();
       
   534 	TInt End();
       
   535 public:
       
   536 	TFileName      iName;
       
   537 	RFile          iF;
       
   538 	TBuf8<KBufLen> iBuffer[KMaxLag];
       
   539 	TRequestStatus iStatus[KMaxLag];
       
   540 	TInt           iPtr;
       
   541 	TInt           iNum;
       
   542 	TInt           iOps;
       
   543 	TInt           iMax;
       
   544 	TBool          iOpen;
       
   545 	};
       
   546 
       
   547 TFileOps::TFileOps() : iPtr(0), iNum(0), iOps(0), iMax(0), iOpen(EFalse)
       
   548 	{
       
   549 	for (TInt i = 0; i < KMaxLag; i++)
       
   550 		{
       
   551 		iStatus[i] = KErrNone;
       
   552 		iBuffer[i].Fill(TChar('_'), KBufLen);
       
   553 		}
       
   554 	}
       
   555 
       
   556 TInt TFileOps::Open(TChar aDrvCh, TInt aNum)
       
   557 /// Open the file for testing, give error if there is not enough space for it.
       
   558 /// @param aDrvCh Drive letter.
       
   559 /// @param aNum   File number suffix.
       
   560 	{
       
   561 	TVolumeInfo vol;
       
   562 	TInt        drv;
       
   563 	TInt r = TheFs.CharToDrive(aDrvCh, drv);
       
   564 	if (r != KErrNone)
       
   565 		TTest::Fail(HERE, _L("CharToDrive(%c) returned %d"), (TUint)aDrvCh, r);
       
   566 	r = TheFs.Volume(vol, drv);
       
   567 	if (r != KErrNone)
       
   568 		TTest::Fail(HERE, _L("Volume(%c:) returned %d"), (TUint)aDrvCh, r);
       
   569 
       
   570 	iMax = I64LOW(vol.iFree / MAKE_TINT64(0,KBufLen)) / 2 - 1;
       
   571 	if (iMax < 10)
       
   572 		TTest::Fail(HERE, _L("Not enough space to do test, only %d KB available"),
       
   573 							                  I64LOW(vol.iFree/1024));
       
   574 
       
   575 	Reset();
       
   576 	iName.Format(_L("%c:\\TEST_%d"), (TUint)aDrvCh, aNum);
       
   577 	r = iF.Replace(TheFs, iName, EFileStreamText | EFileWrite);
       
   578 	if (r == KErrNone)
       
   579 		iOpen = ETrue;
       
   580 	return r;
       
   581 	}
       
   582 
       
   583 TInt TFileOps::Close()
       
   584 /// Close and delete the file, returning the number of operations done.
       
   585 	{
       
   586 	if (!iOpen)
       
   587 		return 0;
       
   588 	iF.Close();
       
   589 	TheFs.Delete(iName);
       
   590 	iOpen = EFalse;
       
   591 	return iNum;
       
   592 	}
       
   593 
       
   594 TInt TFileOps::Reset()
       
   595 /// Reset all of the counts.
       
   596 	{
       
   597 	iPtr = 0;
       
   598 	iNum = 0;
       
   599 	iOps = 0;
       
   600 	return 0;
       
   601 	}
       
   602 
       
   603 TInt TFileOps::Write()
       
   604 /// If there is a free buffer available, start a write.
       
   605 	{
       
   606 	if (!iOpen)
       
   607 		return 0;
       
   608 	while (iNum < iOps && iStatus[iNum%KMaxLag] != KRequestPending)
       
   609 		iNum++;
       
   610 	if (iOps < KMaxLag || iStatus[iPtr] != KRequestPending)
       
   611 		{
       
   612 		TInt pos = iNum%iMax * KBufLen;
       
   613 		iF.Write(pos, iBuffer[iPtr], iStatus[iPtr]);
       
   614 		iOps++;
       
   615 		iPtr++;
       
   616 		iPtr %= KMaxLag;
       
   617 		return 1;
       
   618 		}
       
   619 	return 0;
       
   620 	}
       
   621 
       
   622 TInt TFileOps::Read()
       
   623 /// If there is a free buffer available, start a read.
       
   624 	{
       
   625 	if (!iOpen)
       
   626 		return 0;
       
   627 	while (iNum < iOps && iStatus[iNum%KMaxLag] != KRequestPending)
       
   628 		iNum++;
       
   629 	if (iOps < KMaxLag || iStatus[iPtr] != KRequestPending)
       
   630 		{
       
   631 		TInt pos = iNum%iMax * KBufLen;
       
   632 		iF.Read(pos, iBuffer[iPtr], iStatus[iPtr]);
       
   633 		iOps++;
       
   634 		iPtr++;
       
   635 		iPtr %= KMaxLag;
       
   636 		return 1;
       
   637 		}
       
   638 	return 0;
       
   639 	}
       
   640 
       
   641 TInt TFileOps::End()
       
   642 /// Wait until all outstanding operations have ended, then return the number.
       
   643 	{
       
   644 	if (!iOpen)
       
   645 		return 0;
       
   646 	while (iNum < iOps)
       
   647 		{
       
   648 		if (iStatus[iNum%KMaxLag] == KRequestPending)
       
   649 			User::WaitForRequest(iStatus[iNum%KMaxLag]);
       
   650 		else
       
   651 			iNum++;
       
   652 		}
       
   653 	if (iOps < iMax)
       
   654 		iMax = iOps;
       
   655 	return iNum;
       
   656 	}
       
   657 
       
   658 LOCAL_C TInt testAsyncAccess(TChar dc1, TChar dc2)
       
   659 //
       
   660 // Test one drive against the other.
       
   661 //
       
   662     {
       
   663 	TFileOps f1;
       
   664 	TFileOps f2;
       
   665 
       
   666 	f1.Open(dc1, 1);
       
   667 	if (dc1 != dc2)
       
   668 		f2.Open(dc2, 2);
       
   669 
       
   670 	TInt   op1 = 0;
       
   671 	TInt   op2 = 0;
       
   672 	RTimer timer;
       
   673 	TRequestStatus tstat;
       
   674 	TTime startTime;
       
   675 	TTime endTime;
       
   676 	TTimeIntervalMicroSeconds timeTaken;
       
   677 
       
   678 	timer.CreateLocal();
       
   679 
       
   680 	timer.After(tstat, KTimeBM * KSecond);
       
   681 
       
   682 	startTime.HomeTime();
       
   683 
       
   684 	while (tstat == KRequestPending)
       
   685 		{
       
   686 		TInt num = f1.Write();
       
   687 		num += f2.Write();
       
   688 		if (num == 0)
       
   689 			User::WaitForAnyRequest();
       
   690 		}
       
   691 
       
   692 	op1 = f1.End();
       
   693 	op2 = f2.End();
       
   694 
       
   695 	endTime.HomeTime();
       
   696 	timeTaken=endTime.MicroSecondsFrom(startTime);
       
   697 
       
   698 	TInt64 dtime = timeTaken.Int64();
       
   699 
       
   700 	TTest::Printf(_L("%c: %8d writes in %6d mS = %8d bytes per second\n"),
       
   701 				  (TUint)dc1, op1, I64LOW(dtime)/1000, GetSpeed(op1, dtime));
       
   702 
       
   703 	if (dc1 != dc2)
       
   704 		TTest::Printf(_L("%c: %8d writes in %6d mS = %8d bytes per second\n"),
       
   705 					  (TUint)dc2, op2, I64LOW(dtime)/1000, GetSpeed(op2, dtime));
       
   706 
       
   707 	AddStats(gWrStats, MAKE_TINT64(0, op1 + op2) * MAKE_TINT64(0, KBufLen) * MAKE_TINT64(0, KSecond), dtime);
       
   708 
       
   709 	// now the reads!
       
   710 
       
   711 	f1.Reset();
       
   712 	f2.Reset();
       
   713 
       
   714 	timer.After(tstat, KTimeBM * KSecond);
       
   715 
       
   716 	startTime.HomeTime();
       
   717 
       
   718 	while (tstat == KRequestPending)
       
   719 		{
       
   720 		f1.Read();
       
   721 		f2.Read();
       
   722 		User::WaitForAnyRequest();
       
   723 		}
       
   724 
       
   725 	op1 = f1.End();
       
   726 	op2 = f2.End();
       
   727 
       
   728 	endTime.HomeTime();
       
   729 	timeTaken=endTime.MicroSecondsFrom(startTime);
       
   730 
       
   731 	dtime = timeTaken.Int64();
       
   732 
       
   733 	TTest::Printf(_L("%c: %8d reads  in %6d mS = %8d bytes per second\n"),
       
   734 				  (TUint)dc1, op1, I64LOW(dtime)/1000, GetSpeed(op1, dtime));
       
   735 
       
   736 	if (dc1 != dc2)
       
   737 		TTest::Printf(_L("%c: %8d reads  in %6d mS = %8d bytes per second\n"),
       
   738 					  (TUint)dc2, op2, I64LOW(dtime)/1000, GetSpeed(op2, dtime));
       
   739 
       
   740 	AddStats(gRdStats, MAKE_TINT64(0, op1 + op2) * MAKE_TINT64(0, KBufLen) * MAKE_TINT64(0, KSecond), dtime);
       
   741 
       
   742 	test.Printf(_L("\n"));
       
   743 	test.Printf(_L("average write throughput = %d bytes/sec\n"), GetSpeed(gWrStats));
       
   744 	test.Printf(_L("average read  throughput = %d bytes/sec\n"), GetSpeed(gRdStats));
       
   745 	test.Printf(_L("\n"));
       
   746 	gWrStats.Init();
       
   747 	gRdStats.Init();
       
   748 
       
   749 	timer.Cancel();
       
   750 	timer.Close();
       
   751 	f1.Close();
       
   752 	f2.Close();
       
   753 	// delay for a second to allow the close to complete before dismounting.
       
   754 	User::After(1000000);
       
   755 	return KErrNone;
       
   756     }
       
   757 
       
   758 #if defined(TEST_SYNC_IN_THREAD) || defined(TEST_ASYNC_IN_THREAD)
       
   759 
       
   760 LOCAL_C TInt CreateThread(TThreadFunction aFunc, TChar c, TOper aOper)
       
   761 /// Create a thread to do the appropriate operation on a drive.
       
   762 	{
       
   763 	TBuf<2>  drive(_L("?"));
       
   764 	TBuf<64> name;
       
   765     drive[0] = TText(c);
       
   766 	drive.UpperCase();
       
   767 	TThreadData& d = TTest::Data(gThreadNumber);
       
   768 	d.iFile.Format(_L("%S:\\TEST%d.FILE"), &drive, gThreadNumber);
       
   769 	d.iData = (aOper == EWrite ? &aOper : NULL);
       
   770 	name.Format(_L("Test_%S_%d"), &drive, gThreadNumber);
       
   771 	TInt r = TTest::Create(gThreadNumber, aFunc, name);
       
   772 	++gThreadNumber;
       
   773 	return r;
       
   774 	}
       
   775 
       
   776 LOCAL_C TInt RunThreads(TThreadFunction aFunc, TChar aDrive1, TChar aDrive2, TOper aOper)
       
   777 /// Run threads to test one drive against the other at the same time.
       
   778 /// The thread will report any error and return it as a value, the program will
       
   779 /// exit at a higher level after cleaning up.
       
   780 	{
       
   781 	TInt r;
       
   782 	gThreadNumber = 0;
       
   783 	if ((r = CreateThread(aFunc, aDrive1, aOper)) != KErrNone) return r;
       
   784 	if ((r = CreateThread(aFunc, aDrive2, aOper)) != KErrNone) return r;
       
   785 	TTest::Printf();
       
   786 	r = TTest::Run();
       
   787 	TTest::Printf();
       
   788 	return r;
       
   789 	}
       
   790 
       
   791 LOCAL_C TInt testThreads(TThreadFunction aFunc, TChar c, TChar d)
       
   792 /// Run threads testing read and write of the drives both ways round.
       
   793 /// The thread will report any error and return it as a value, the program will
       
   794 /// exit at a higher level after cleaning up.
       
   795 	{
       
   796 	TInt r;
       
   797 	if ((r = RunThreads(aFunc, c, d, EWrite)) != KErrNone) return r;
       
   798 	if ((r = RunThreads(aFunc, c, d, ERead))  != KErrNone) return r;
       
   799 	if ((r = RunThreads(aFunc, d, c, EWrite)) != KErrNone) return r;
       
   800 	if ((r = RunThreads(aFunc, d, c, ERead))  != KErrNone) return r;
       
   801 	// display totals;
       
   802 	test.Printf(_L("average write throughput = %d bytes/sec\n"), GetSpeed(gWrStats));
       
   803 	test.Printf(_L("average read  throughput = %d bytes/sec\n"), GetSpeed(gRdStats));
       
   804 	test.Printf(_L("\n"));
       
   805 	gWrStats.Init();
       
   806 	gRdStats.Init();
       
   807 	return r;
       
   808 	}
       
   809 
       
   810 #endif
       
   811 
       
   812 LOCAL_C TInt parseCmd(TChar& aDrvCh1, TChar& aDrvCh2)
       
   813 /// Get parameters from the comand line; if there aren't enough then
       
   814 /// prompt the user for them and return KErrAbort if ^C is pressed.
       
   815 	{
       
   816 	while (aDrvCh1 < 'A' || aDrvCh1 > 'Z')
       
   817 		{
       
   818 		test.Printf(_L("Enter drive letter: "));
       
   819 		while (aDrvCh1 < 'A' || aDrvCh1 > 'Z')
       
   820 			{
       
   821 			if (aDrvCh1 == 0x03)
       
   822 				return KErrAbort;
       
   823 			aDrvCh1 = User::UpperCase(test.Getch());
       
   824 			}
       
   825 		if (!DriveIsOK(aDrvCh1))
       
   826 			{
       
   827 			test.Printf(_L("%c: is not a valid drive\n"), (TUint)aDrvCh1);
       
   828 			aDrvCh1 = 0;
       
   829 			}
       
   830 		else
       
   831 			{
       
   832 			TInt drv;
       
   833 			TheFs.CharToDrive(aDrvCh1, drv);
       
   834 			TheFs.FileSystemName(gFsName1, drv);
       
   835 			test.Printf(_L("%c: (%S)\n"), (TUint)aDrvCh1, &gFsName1);
       
   836 			}
       
   837 		}
       
   838 
       
   839 	while (aDrvCh2 < 'A' || aDrvCh2 > 'Z')
       
   840 		{
       
   841 		test.Printf(_L("Enter drive letter: "));
       
   842 		while (aDrvCh2 < 'A' || aDrvCh2 > 'Z')
       
   843 			{
       
   844 			if (aDrvCh2 == 0x03)
       
   845 				return KErrAbort;
       
   846 			aDrvCh2 = User::UpperCase(test.Getch());
       
   847 			}
       
   848 		if (!DriveIsOK(aDrvCh2))
       
   849 			{
       
   850 			test.Printf(_L("%c: is not a valid drive\n"), (TUint)aDrvCh2);
       
   851 			aDrvCh2 = 0;
       
   852 			}
       
   853 		else
       
   854 			{
       
   855 			TInt drv;
       
   856 			TheFs.CharToDrive(aDrvCh2, drv);
       
   857 			TheFs.FileSystemName(gFsName2, drv);
       
   858 			test.Printf(_L("%c: (%S)\n"), (TUint)aDrvCh2, &gFsName2);
       
   859 			}
       
   860 		}
       
   861 	return KErrNone;
       
   862 	}
       
   863 
       
   864 GLDEF_C void CallTestsL()
       
   865 //
       
   866 // Do all tests
       
   867 //
       
   868 	{
       
   869 	TInt r = TTest::Init();
       
   870 	test(r == KErrNone);
       
   871 
       
   872 	TChar drvch0 = TTest::DefaultDriveChar();
       
   873 	TChar drvch1 = 0;
       
   874 	TChar drvch2 = 0;
       
   875 	TInt  drive0;
       
   876 	TInt  drive1;
       
   877 	TInt  drive2;
       
   878 
       
   879 	const TInt KMaxArgs = 4;
       
   880 	TPtrC argv[KMaxArgs];
       
   881 	TInt  argc = TTest::ParseCommandArguments(argv, KMaxArgs);
       
   882 	if (argc > 1)
       
   883 		drvch0 = User::UpperCase(argv[1][0]);
       
   884 	if (argc > 2)
       
   885 		drvch1 = User::UpperCase(argv[2][0]);
       
   886 	if (argc > 3)
       
   887 		drvch2 = User::UpperCase(argv[3][0]);
       
   888 
       
   889 	r = TheFs.CharToDrive(drvch0, drive0);
       
   890 	test(r == KErrNone);
       
   891 
       
   892 	if (TheFs.IsValidDrive(drive0))
       
   893 		MountTestFileSystem(drive0);
       
   894 	else
       
   895 		test.Printf(_L("Unable to mount test file system\n"));
       
   896 
       
   897 	r = parseCmd(drvch1, drvch2);
       
   898 	if (r != KErrNone)
       
   899 		{
       
   900 		UnmountFileSystem(drive0);
       
   901 		User::Panic(_L("USER ABORT"), 0);
       
   902 		}
       
   903 
       
   904 	r = TheFs.CharToDrive(drvch1, drive1);
       
   905 	test(r == KErrNone);
       
   906 	r = TheFs.CharToDrive(drvch2, drive2);
       
   907 	test(r == KErrNone);
       
   908 
       
   909 	r = TheFs.FileSystemName(gFsName1, drive1);
       
   910 	test(r == KErrNone || r == KErrNotFound);
       
   911 	r = TheFs.FileSystemName(gFsName2, drive2);
       
   912 	test(r == KErrNone || r == KErrNotFound);
       
   913 
       
   914 	gDataLock.CreateLocal();
       
   915 
       
   916 	if (drive1 == drive2)
       
   917 		{
       
   918 // !!! Disable platform security tests until we get the new APIs
       
   919 //		if (User::Capability() & KCapabilityRoot)
       
   920 //			CheckMountLFFS(TheFs, drvch1);
       
   921 
       
   922 		test.Printf(_L("Using drive %c: (%S)\n"),
       
   923 					(TUint)drvch1, &gFsName1);
       
   924 		if (r == KErrNone)
       
   925 			{
       
   926 			test.Next(_L("Test with drive asynchronous"));
       
   927 			RemountFileSystem(drive1, EFalse);
       
   928 			testAsyncAccess(drvch1, drvch1);
       
   929 			}
       
   930 
       
   931 		if (r == KErrNone)
       
   932 			{
       
   933 			test.Next(_L("Test with drive synchronous"));
       
   934 			RemountFileSystem(drive1, ETrue);
       
   935 			testAsyncAccess(drvch1, drvch1);
       
   936 			}
       
   937 		}
       
   938 	else
       
   939 		{
       
   940 // !!! Disable platform security tests until we get the new APIs
       
   941 /*		if (User::Capability() & KCapabilityRoot)
       
   942 			{
       
   943 			CheckMountLFFS(TheFs, drvch1);
       
   944 			CheckMountLFFS(TheFs, drvch2);
       
   945 			}
       
   946 */
       
   947 		test.Printf(_L("Using drives %c: (%S) and %c: (%S)\n"),
       
   948 					(TUint)drvch1, &gFsName1, (TUint)drvch2, &gFsName2);
       
   949 
       
   950 #if !defined(TEST_ASYNC_IN_THREAD)
       
   951 
       
   952 		if (r == KErrNone)
       
   953 			{
       
   954 			test.Next(_L("Test async r/w with both drives async"));
       
   955 			RemountFileSystem(drive1, EFalse);
       
   956 			RemountFileSystem(drive2, EFalse);
       
   957 			testAsyncAccess(drvch1, drvch2);
       
   958 			}
       
   959 
       
   960 		if (r == KErrNone)
       
   961 			{
       
   962 			test.Next(_L("Test async r/w with 1st drive sync and 2nd async"));
       
   963 			RemountFileSystem(drive1, ETrue);
       
   964 			RemountFileSystem(drive2, EFalse);
       
   965 			testAsyncAccess(drvch1, drvch2);
       
   966 			}
       
   967 
       
   968 		if (r == KErrNone)
       
   969 			{
       
   970 			test.Next(_L("Test async r/w with 1st drive async and 2nd sync"));
       
   971 			RemountFileSystem(drive1, EFalse);
       
   972 			RemountFileSystem(drive2, ETrue);
       
   973 			testAsyncAccess(drvch1, drvch2);
       
   974 			}
       
   975 
       
   976 		if (r == KErrNone)
       
   977 			{
       
   978 			test.Next(_L("Test async r/w with both drives sync"));
       
   979 			RemountFileSystem(drive1, ETrue);
       
   980 			RemountFileSystem(drive2, ETrue);
       
   981 			testAsyncAccess(drvch1, drvch2);
       
   982 			}
       
   983 
       
   984 #else
       
   985 
       
   986 		if (r == KErrNone)
       
   987 			{
       
   988 			test.Next(_L("Test async r/w with both drives asynchronous"));
       
   989 			RemountFileSystem(drive1, EFalse);
       
   990 			RemountFileSystem(drive2, EFalse);
       
   991 			r = testThreads(testAsyncAccess, drvch1, drvch2);
       
   992 			}
       
   993 
       
   994 		if (r == KErrNone)
       
   995 			{
       
   996 			test.Next(_L("Test async r/w with one drive sync and one async"));
       
   997 			RemountFileSystem(drive1, ETrue);
       
   998 			RemountFileSystem(drive2, EFalse);
       
   999 			r = testThreads(testAsyncAccess, drvch1, drvch2);
       
  1000 			}
       
  1001 
       
  1002 		if (r == KErrNone)
       
  1003 			{
       
  1004 			test.Next(_L("Test async r/w with both drives synchronous"));
       
  1005 			RemountFileSystem(drive1, ETrue);
       
  1006 			RemountFileSystem(drive2, ETrue);
       
  1007 			r = testThreads(testAsyncAccess, drvch1, drvch2);
       
  1008 			}
       
  1009 #endif
       
  1010 
       
  1011 #if defined(TEST_SYNC_IN_THREAD)
       
  1012 
       
  1013 		if (r == KErrNone)
       
  1014 			{
       
  1015 			test.Next(_L("Test sync r/w with both drives asynchronous"));
       
  1016 			RemountFileSystem(drive1, EFalse);
       
  1017 			RemountFileSystem(drive2, EFalse);
       
  1018 			r = testThreads(testSyncAccess, drvch1, drvch2);
       
  1019 			}
       
  1020 
       
  1021 		if (r == KErrNone)
       
  1022 			{
       
  1023 			test.Next(_L("Test sync r/w with one drive sync and one async"));
       
  1024 			RemountFileSystem(drive1, ETrue);
       
  1025 			RemountFileSystem(drive2, EFalse);
       
  1026 			r = testThreads(testSyncAccess, drvch1, drvch2);
       
  1027 			}
       
  1028 
       
  1029 		if (r == KErrNone)
       
  1030 			{
       
  1031 			test.Next(_L("Test sync r/w with both drives synchronous"));
       
  1032 			RemountFileSystem(drive1, ETrue);
       
  1033 			RemountFileSystem(drive2, ETrue);
       
  1034 			r = testThreads(testSyncAccess, drvch1, drvch2);
       
  1035 			}
       
  1036 #endif
       
  1037 		}
       
  1038 
       
  1039 	gDataLock.Close();
       
  1040 
       
  1041 	UnmountFileSystem(drive0);
       
  1042 	test(r == 0);
       
  1043 	}
       
  1044 
       
  1045 
       
  1046 GLDEF_C TInt E32Main()
       
  1047 //
       
  1048 // Main entry point
       
  1049 //
       
  1050     {
       
  1051 	TInt r;
       
  1052 
       
  1053     CTrapCleanup* cleanup;
       
  1054     cleanup=CTrapCleanup::New();
       
  1055     __UHEAP_MARK;
       
  1056 
       
  1057     test.Title();
       
  1058     test.Start(_L("Starting tests..."));
       
  1059 
       
  1060     r=TheFs.Connect();
       
  1061     test(r==KErrNone);
       
  1062 
       
  1063     // TheFs.SetAllocFailure(gAllocFailOn);
       
  1064     TTime timerC;
       
  1065     timerC.HomeTime();
       
  1066 
       
  1067 	// Do the tests
       
  1068     TRAP(r,CallTestsL());
       
  1069 
       
  1070     // reset the debug register
       
  1071     TheFs.SetDebugRegister(0);
       
  1072 
       
  1073     TTime endTimeC;
       
  1074     endTimeC.HomeTime();
       
  1075     TTimeIntervalSeconds timeTakenC;
       
  1076     r=endTimeC.SecondsFrom(timerC,timeTakenC);
       
  1077     test(r==KErrNone);
       
  1078     test.Printf(_L("Time taken for test = %d seconds\n"),timeTakenC.Int());
       
  1079     // TheFs.SetAllocFailure(gAllocFailOff);
       
  1080     TheFs.Close();
       
  1081     test.End();
       
  1082     test.Close();
       
  1083     __UHEAP_MARKEND;
       
  1084     delete cleanup;
       
  1085     return(KErrNone);
       
  1086     }