os/kernelhwsrv/kerneltest/f32test/demandpaging/t_pagestress.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32test\demandpaging\t_pagestress.cpp
    15 // Demand Paging Stress Tests
    16 // t_pagestress.exe basically attempts to cause large ammounts of paging by calling
    17 // functions (256) which are alligned on a page boundary from multiple threads.
    18 // There are mulitple versions of t_pagestress installed on a test system to test rom
    19 // and code paging from various media types.
    20 // Usage:
    21 // t_pagestress and t_pagestress_rom
    22 // Common command lines:
    23 // t_pagestress lowmem
    24 // debug - switch on debugging information
    25 // silent - no output to the screen or serial port
    26 // check - check the allignments
    27 // single - run the tests in a single thread
    28 // multiple <numThreads> - run the tests in multiple threads where <numThreads>
    29 // interleave - force thread interleaving
    30 // prio - each thread reschedules in between each function call, causes lots of context changes
    31 // media - perform media access during the tests, very stressful
    32 // lowmem - low memory tests
    33 // forward - patern in which to execute function calls 
    34 // backward - patern in which to execute function calls 			
    35 // random - patern in which to execute function calls 			
    36 // all - patern in which to execute function calls (forward, backward and random)
    37 // inst - for debugging a parameter passed to a spawned exe to give it an id.
    38 // iters <count> - the number of times to loop (a '-' means run forever)
    39 // t_pagestress causes a large ammount of paging by repeatedly calling 
    40 // 256 functions which have been aligned on page boundaries from 
    41 // multiple threads.
    42 // 1  - a single thread calling all functions
    43 // 2  - Multiple threads calling all functions
    44 // 3  - Multiple threads calling all functions with a priority change 
    45 // after each function call
    46 // 4  - Multiple threads calling all functions with background 
    47 // media activity
    48 // 5  - Multiple threads calling all functions with media activity and 
    49 // a priority change after each function call
    50 // 6  - Multiple threads calling all functions with process interleave
    51 // 7  - Multiple threads calling all functions with process interleave 
    52 // and a priority change after each function call
    53 // 8  - Multiple threads calling all functions with process interleave 
    54 // media acess and a priority change after each function call
    55 // 9  - Multiple threads calling all functions with low available memory
    56 // 10 - Multiple threads calling all functions with low available memory,
    57 // starting with initial free ram.
    58 // 
    59 //
    60 
    61 //! @SYMTestCaseID			KBASE-T_PAGESTRESS-0327
    62 //! @SYMTestType			UT
    63 //! @SYMPREQ				PREQ1110
    64 //! @SYMTestCaseDesc		Demand Paging Stress Tests
    65 //! @SYMTestActions			0  - Check the alignment of all functions
    66 //! @SYMTestExpectedResults All tests should pass.
    67 //! @SYMTestPriority        High
    68 //! @SYMTestStatus          Implemented
    69 
    70 #include <e32test.h>
    71 RTest test(_L("T_PAGESTRESS"));
    72 
    73 #include <e32rom.h>
    74 #include <e32svr.h>
    75 #include <u32hal.h>
    76 #include <f32file.h>
    77 #include <f32dbg.h>
    78 #include <e32msgqueue.h>
    79 #include <e32math.h>
    80 
    81 #include "testdefs.h"
    82 
    83 #ifdef __X86__
    84 #define TEST_ON_UNPAGED
    85 #endif
    86 
    87 
    88 /* The following line will cause t_pagestress.h to declare an array of function
    89  * pointers to  page boundary aligned functions that we can use in this test...
    90  */
    91 #define TPS_DECLARE_ARRAY
    92 #include "t_pagestress.h"
    93 
    94 TBool   	TestDebug					= EFalse;
    95 TBool		TestSilent					= EFalse;
    96 TBool		TestExit					= EFalse;
    97 
    98 TBool   	TestCheck					= EFalse;
    99 TBool   	TestSingle					= EFalse;
   100 TBool   	TestMultiple				= EFalse;
   101 TBool   	TestForever					= EFalse;
   102 TInt		TestMaxLoops				= 20;
   103 TInt		TestMultipleThreadCount		= 50;
   104 TInt		TestInstanceId				= 0;
   105 
   106 #define TEST_INTERLEAVE_PRIO		EPriorityMore//EPriorityRealTime //23 // KNandThreadPriority - 1
   107 TBool		TestInterleave				= EFalse;
   108 TBool		TestWeAreTheTestBase		= EFalse;
   109 TBool		TestBootedFromMmc			= EFalse;
   110 TInt		DriveNumber=-1;   // Parameter - Which drive?  -1 = autodetect.
   111 #define TEST_NONE		0x0
   112 #define TEST_FORWARD	0x2
   113 #define TEST_BACKWARD	0x4
   114 #define TEST_RANDOM		0x8
   115 #define TEST_ALL		(TEST_RANDOM | TEST_BACKWARD | TEST_FORWARD)
   116 TUint32		TestWhichTests				= TEST_ALL;
   117 TBuf<32>	TestNameBuffer;
   118 TBool		TestPrioChange				= ETrue;
   119 TBool		TestStopMedia				= EFalse;
   120 TBool		TestMediaAccess				= EFalse;
   121 #define TEST_LM_NUM_FREE	0
   122 #define TEST_LM_BLOCKSIZE	1
   123 #define TEST_LM_BLOCKS_FREE	4
   124 TBool		TestLowMem					= EFalse;
   125 RPageStressTestLdd Ldd;
   126 TInt		TestPageSize				= 4096;
   127 RSemaphore	TestMultiSem;
   128 RMsgQueue<TBuf <64> >	TestMsgQueue;
   129 TBool		TestIsDemandPaged = ETrue;
   130 
   131 
   132 #define TEST_NEXT(__args) \
   133 	if (!TestSilent)\
   134 		test.Next __args;
   135 
   136 #define DBGS_PRINT(__args)\
   137 	if (!TestSilent)\
   138 		test.Printf __args ;
   139 
   140 #define DBGD_PRINT(__args)\
   141 	if (TestDebug)\
   142 		test.Printf __args ;\
   143 
   144 #define DEBUG_PRINT(__args)\
   145 if (!TestSilent)\
   146 	{\
   147 	if (aMsgQueue && aBuffer && aTheSem)\
   148 		{\
   149 		aBuffer->Zero();\
   150 		aBuffer->Format __args ;\
   151 		aTheSem->Wait();\
   152 		aMsgQueue->SendBlocking(*aBuffer);\
   153 		aTheSem->Signal();\
   154 		}\
   155 	else\
   156 		{\
   157 		test.Printf __args ;\
   158 		}\
   159 	}
   160 
   161 #define RUNTEST(__test, __error)\
   162 	if (!TestSilent)\
   163 		test(__test == __error);\
   164 	else\
   165 		__test;
   166 
   167 #define RUNTEST1(__test)\
   168 	if (!TestSilent)\
   169 		test(__test);
   170 
   171 #define DEBUG_PRINT1(__args)\
   172 if (TestDebug)\
   173 	{\
   174 	DEBUG_PRINT(__args)\
   175 	}
   176 
   177 //
   178 // CheckAlignments
   179 //
   180 // The following functions wanders through the function pointer array
   181 // declared in t_pagestress.h and ensures that the alignment has worked, 
   182 // (a good start!) and then calls each of the functions in turn to 
   183 // ensure that they work, simple first sanity check test.
   184 //
   185 
   186 TInt CheckAlignments()
   187 	{
   188 	// now it's time to play with the array of function pointers...
   189 	TInt  seed = 1;
   190 	TUint32 index = 0;
   191 	TInt ret = KErrNone;
   192 
   193 	while (index < (PAGESTRESS_FUNC_COUNT - 1))
   194 		{
   195 		DBGD_PRINT((_L("\nAddress (%u) 0x%x difference to next %u\n"), index, (TUint32)PagestressFuncPtrs[index], (TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[index]));	
   196 		if ((((TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[0]) % 4096) != 0)
   197 			{
   198 			DBGS_PRINT((_L("\nError! Allignment for %u is not offset of 4096 from index 0 0x%x 0x%x\n"), index, (TUint32)PagestressFuncPtrs[index + 1], (TUint32)PagestressFuncPtrs[0]));	
   199 			ret = KErrGeneral;
   200 			}
   201 		//seed = PagestressFuncPtrs[index](seed, index);
   202 		seed = CallTestFunc(seed, index, index);
   203 		index ++;
   204 		}
   205 	return ret;
   206 	}
   207 
   208 //
   209 // RunThreadForward
   210 //
   211 // Walk through the function pointer array (forwards) calling each function
   212 //
   213 
   214 void RunThreadForward()
   215 	{
   216 	TInt	seed = 1;
   217 	TUint32 index = 0;
   218 	RThread thisThread;
   219 
   220 	while (index < PAGESTRESS_FUNC_COUNT)
   221 		{
   222 		if (TestPrioChange)
   223 			{
   224 			TThreadPriority originalThreadPriority = thisThread.Priority();
   225 			thisThread.SetPriority(EPriorityLess);
   226 			User::AfterHighRes(0);
   227 			thisThread.SetPriority(originalThreadPriority);
   228 			}
   229 		//seed = PagestressFuncPtrs[index](seed, index);
   230 		seed = CallTestFunc(seed, index, index);
   231 		index ++;
   232 		}
   233 	}
   234 
   235 //
   236 // RunThreadBackward
   237 //
   238 // Walk through the function pointer array (backwards) calling each function
   239 //
   240 
   241 void RunThreadBackward()
   242 	{
   243 	TInt	seed = 1;
   244 	TInt	index = PAGESTRESS_FUNC_COUNT;
   245 	RThread thisThread;
   246 
   247 	while (index > 0)
   248 		{
   249 		if (TestPrioChange)
   250 			{
   251 			TThreadPriority originalThreadPriority = thisThread.Priority();
   252 			thisThread.SetPriority(EPriorityLess);
   253 			User::AfterHighRes(0);
   254 			thisThread.SetPriority(originalThreadPriority);
   255 			}
   256 		index --;
   257 		//seed = PagestressFuncPtrs[index](seed, index);
   258 		seed = CallTestFunc(seed, index, index);
   259 		}
   260 	}
   261 
   262 //
   263 // RunThreadRandom
   264 //
   265 // Walk through the function pointer array in a random order a number of times calling each function
   266 //
   267 
   268 void RunThreadRandom()
   269 	{
   270 	TInt	seed = 1;
   271 	TInt	index = 0;
   272 	TInt	randNum;
   273 	RThread thisThread;
   274 
   275 	while (index < (TInt)PAGESTRESS_FUNC_COUNT)
   276 		{
   277 		if (TestPrioChange)
   278 			{
   279 			TThreadPriority originalThreadPriority = thisThread.Priority();
   280 			thisThread.SetPriority(EPriorityLess);
   281 			User::AfterHighRes(0);
   282 			thisThread.SetPriority(originalThreadPriority);
   283 			}
   284 		randNum = Math::Random();
   285 		randNum %= PAGESTRESS_FUNC_COUNT;
   286 		//seed = PagestressFuncPtrs[randNum](seed, randNum);
   287 		seed = CallTestFunc(seed, randNum, randNum);
   288 		index ++;
   289 		}
   290 	}
   291 
   292 
   293 //
   294 // PerformTestThread
   295 //
   296 // This is the function that actually does the work.
   297 // It is complicated a little because test.Printf can only be called from the first thread that calls it 
   298 // so if we are using multiple threads we need to use a message queue to pass the debug info from the
   299 // child threads back to the parent for the parent to then call printf.
   300 //
   301 //
   302 
   303 LOCAL_C void PerformTestThread(TInt					  aThreadIndex, 
   304 							   RMsgQueue<TBuf <64> > *aMsgQueue = NULL, 
   305 							   TBuf<64>				 *aBuffer = NULL,
   306 							   RSemaphore			 *aTheSem = NULL)
   307 	{
   308 	TUint start = User::TickCount();
   309 
   310 	DEBUG_PRINT1((_L("%S : thread Starting %d\n"), &TestNameBuffer, aThreadIndex));
   311 	
   312 	// now select how we do the test...
   313 	TInt	iterIndex;
   314 
   315 	if (TEST_ALL == (TestWhichTests & TEST_ALL))
   316 		{
   317 		#define LOCAL_ORDER_INDEX1	6
   318 		#define LOCAL_ORDER_INDEX2	3
   319 		TInt	order[LOCAL_ORDER_INDEX1][LOCAL_ORDER_INDEX2] = {	{TEST_FORWARD, TEST_BACKWARD,TEST_RANDOM},
   320 																	{TEST_FORWARD, TEST_RANDOM,  TEST_BACKWARD},
   321 																	{TEST_BACKWARD,TEST_FORWARD, TEST_RANDOM},
   322 																	{TEST_BACKWARD,TEST_RANDOM,  TEST_FORWARD},
   323 																	{TEST_RANDOM,  TEST_FORWARD, TEST_BACKWARD},
   324 																	{TEST_RANDOM,  TEST_BACKWARD,TEST_FORWARD}};
   325 		TInt	whichOrder = 0;
   326 
   327 		for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
   328 			{
   329 			TInt    selOrder = ((aThreadIndex + 1) * (iterIndex + 1)) % LOCAL_ORDER_INDEX1;
   330 			for (whichOrder = 0; whichOrder < LOCAL_ORDER_INDEX2; whichOrder ++)
   331 				{
   332 				switch (order[selOrder][whichOrder])
   333 					{
   334 						case TEST_FORWARD:
   335 						DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   336 						RunThreadForward();
   337 						break;
   338 
   339 						case TEST_BACKWARD:
   340 						DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   341 						RunThreadBackward();
   342 						break;
   343 
   344 						case TEST_RANDOM:
   345 						DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   346 						RunThreadRandom();
   347 						break;
   348 						
   349 						default: // this is really an error.
   350 						break;
   351 					}
   352 				}
   353 			}
   354 		}
   355 	else
   356 		{
   357 		if (TestWhichTests & TEST_FORWARD)
   358 			{
   359 			for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
   360 				{
   361 				DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   362 				RunThreadForward();
   363 				}
   364 			}
   365 			
   366 		if (TestWhichTests & TEST_BACKWARD)
   367 			{
   368 			for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
   369 				{
   370 				DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   371 				RunThreadBackward();
   372 				}
   373 			}
   374 
   375 		if (TestWhichTests & TEST_RANDOM)
   376 			{
   377 			for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
   378 				{
   379 				DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
   380 				RunThreadRandom();
   381 				}
   382 			}
   383 		}
   384 	DEBUG_PRINT1((_L("%S : thread Exiting %d (tickcount %u)\n"), &TestNameBuffer, aThreadIndex, User::TickCount() - start));
   385 	}
   386 
   387 
   388 //
   389 // MultipleTestThread
   390 //
   391 // Thread function, one created for each thread in a multiple thread test.
   392 //
   393 
   394 LOCAL_C TInt MultipleTestThread(TAny* aUseTb)
   395 	{
   396 	TBuf<64>					localBuffer;
   397 
   398 	if (TestInterleave)	
   399 		{
   400 		RThread				thisThread;
   401 		thisThread.SetPriority((TThreadPriority) TEST_INTERLEAVE_PRIO);
   402 		}
   403 
   404 	PerformTestThread((TInt) aUseTb, &TestMsgQueue, &localBuffer, &TestMultiSem);
   405 	
   406 	return KErrNone;
   407 	}
   408 
   409 //
   410 // DoSingleTest
   411 // 
   412 // Perform the single thread test, spawning a number of threads.
   413 //
   414 
   415 LOCAL_C void DoSingleTest()
   416 	{
   417 	PerformTestThread((TInt) TestInstanceId);
   418 	}
   419 
   420 //
   421 // FindDriveNumber
   422 // 
   423 // Find the first read write drive.
   424 //
   425 
   426 TInt FindDriveNumber(RFs fs)
   427 	{
   428 	TDriveInfo driveInfo;
   429 	for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
   430 		{
   431 		TInt r = fs.Drive(driveInfo, drvNum);
   432 		if (r >= 0)
   433 			{
   434 			if (driveInfo.iType == EMediaHardDisk)
   435 				return (drvNum);
   436 			}
   437 		}
   438 	return -1;
   439 	}
   440 
   441 //
   442 // FindFsNANDDrive
   443 //
   444 // Find the NAND drive
   445 //
   446 
   447 static TInt FindFsNANDDrive(RFs& aFs)
   448 	{
   449 	TDriveList driveList;
   450 	TDriveInfo driveInfo;
   451 	TInt r=aFs.DriveList(driveList);
   452     if (r == KErrNone)
   453 		{
   454 		for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum<KMaxDrives; ++drvNum)
   455 			{
   456 			if(!driveList[drvNum])
   457 				continue;   //-- skip unexisting drive
   458 
   459 			if (aFs.Drive(driveInfo, drvNum) == KErrNone)
   460 				{
   461 				if(driveInfo.iMediaAtt&KMediaAttPageable)
   462 					{
   463 					TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected;		// skip ROFS partitions
   464 					if(!readOnly)
   465 						{
   466 						if ((drvNum==DriveNumber) || (DriveNumber<0))		// only test if running on this drive
   467 							{
   468 							return (drvNum);
   469 							}
   470 						}
   471 					}
   472 				}
   473 			}
   474 		}
   475 	return -1;
   476 	}
   477 
   478 //
   479 // FindMMCDriveNumber
   480 // 
   481 // Find the first read write drive.
   482 //
   483 
   484 TInt FindMMCDriveNumber(RFs& aFs)
   485 	{
   486 	TDriveInfo driveInfo;
   487 	for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
   488 		{
   489 		TInt r = aFs.Drive(driveInfo, drvNum);
   490 		if (r >= 0)
   491 			{
   492 			if (driveInfo.iType == EMediaHardDisk)
   493 				return (drvNum);
   494 			}
   495 		}
   496 	return -1; 
   497 	}
   498 
   499 //
   500 // PerformRomAndFileSystemAccess
   501 // 
   502 // Access the rom and dump it out to one of the writeable partitions...
   503 // really just to make the media server a little busy during the test.
   504 //
   505 
   506 TInt PerformRomAndFileSystemAccessThread(RMsgQueue<TBuf <64> > *aMsgQueue = NULL, 
   507 										 TBuf<64>			   *aBuffer = NULL,
   508 										 RSemaphore			   *aTheSem = NULL)
   509 	{
   510 	TUint maxBytes = KMaxTUint;
   511 	TInt startTime = User::TickCount();
   512 
   513 	RFs fs;
   514 	RFile file;
   515 	if (KErrNone != fs.Connect())
   516 		{
   517 		DEBUG_PRINT(_L("PerformRomAndFileSystemAccessThread : Can't connect to the FS\n"));
   518 		return KErrGeneral;
   519 		}
   520 
   521 	// get info about the ROM...
   522 	TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
   523 	TUint8* start;
   524 	TUint8* end;
   525 	if(romHeader->iPageableRomStart)
   526 		{
   527 		start = (TUint8*)romHeader + romHeader->iPageableRomStart;
   528 		end = start + romHeader->iPageableRomSize;
   529 		}
   530 	else
   531 		{
   532 		start = (TUint8*)romHeader;
   533 		end = start + romHeader->iUncompressedSize;
   534 		}
   535 	if (end <= start)
   536 		return KErrGeneral;
   537 
   538 	// read all ROM pages in a random order...and write out to file in ROFs, 
   539 	TUint size = end - start - TestPageSize;
   540 	if(size > maxBytes)
   541 		size = maxBytes;
   542 
   543 	TUint32 random=1;
   544 	TPtrC8 rom;
   545 	TUint8 *theAddr;
   546 
   547 	TInt		drvNum = TestBootedFromMmc ? FindMMCDriveNumber(fs) : FindFsNANDDrive(fs);
   548 	TBuf<32>	filename = _L("d:\\Pageldrtst.tmp");
   549 	if (drvNum >= 0)
   550 		{
   551 		filename[0] = 'a' + drvNum;
   552 		DEBUG_PRINT((_L("%S : Filename %S\n"), &TestNameBuffer, &filename));
   553 		}
   554 	else
   555 		DEBUG_PRINT((_L("PerformRomAndFileSystemAccessThread : error getting drive num\n")));
   556 
   557 	for(TInt i=size/(TestPageSize); i>0; --i)
   558 		{
   559 		DEBUG_PRINT1((_L("%S : Opening the file\n"), &TestNameBuffer));
   560 		if (KErrNone != file.Replace(fs, filename, EFileWrite))
   561 			{
   562 			DEBUG_PRINT((_L("%S : Opening the file Failed!\n"), &TestNameBuffer));
   563 			}
   564 
   565 		random = random*69069+1;
   566 		theAddr = (TUint8*)(start+((TInt64(random)*TInt64(size))>>32));
   567 		if (theAddr + TestPageSize > end)
   568 			{
   569 			DEBUG_PRINT((_L("%S : address is past the end 0x%x / 0x%x\n"), &TestNameBuffer, (TInt)theAddr, (TInt)end));
   570 			}
   571 		rom.Set(theAddr,TestPageSize);
   572 		DEBUG_PRINT1((_L("%S : Writing the file\n"), &TestNameBuffer));
   573 		TInt ret = file.Write(rom);
   574 		if (ret != KErrNone)
   575 			{
   576 			DEBUG_PRINT1((_L("%S : Write returned error %d\n"), &TestNameBuffer, ret));
   577 			}
   578 		DEBUG_PRINT1((_L("%S : Closing the file\n"), &TestNameBuffer));
   579 		file.Close();
   580 
   581 		DEBUG_PRINT1((_L("%S : Deleting the file\n"), &TestNameBuffer));
   582 		ret = fs.Delete(filename);
   583 		if (KErrNone != ret)
   584 			{
   585 			DEBUG_PRINT((_L("%S : Delete returned error %d\n"), &TestNameBuffer, ret));
   586 			}
   587 		if (TestStopMedia)
   588 			break;
   589 		}
   590 	fs.Close();
   591 	DEBUG_PRINT1((_L("Done in %d ticks\n"), User::TickCount() - startTime));
   592 	return KErrNone;
   593 	}
   594 
   595 
   596 //
   597 // PerformRomAndFileSystemAccess
   598 //
   599 // Thread function, kicks off the file system access.
   600 //
   601 
   602 LOCAL_C TInt PerformRomAndFileSystemAccess(TAny* )
   603 	{
   604 	TBuf<64>					localBuffer;
   605 
   606 	PerformRomAndFileSystemAccessThread(&TestMsgQueue, &localBuffer, &TestMultiSem);
   607 	
   608 	return KErrNone;
   609 	}
   610 
   611 //
   612 // DoMultipleTest
   613 // 
   614 // Perform the multiple thread test, spawning a number of threads.
   615 // It is complicated a little because test.Printf can only be called from the first thread that calls it 
   616 // so if we are using multiple threads we need to use a message queue to pass the debug info from the
   617 // child threads back to the parent for the parent to then call printf.
   618 //
   619 #define DOTEST(__operation, __condition)\
   620 	if (aLowMem) \
   621 		{\
   622 		__operation;\
   623 		while (!__condition)\
   624 			{\
   625 			Ldd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\
   626 			__operation;\
   627 			}\
   628 		RUNTEST1(__condition);\
   629 		}\
   630 	else\
   631 		{\
   632 		__operation;\
   633 		RUNTEST1(__condition);\
   634 		}
   635 
   636 void DoMultipleTest(TBool aLowMem = EFalse)
   637 	{
   638 	TInt			 index;
   639 
   640 	RThread			*pTheThreads  = (RThread *)User::AllocZ(sizeof(RThread) * TestMultipleThreadCount);
   641 	TInt			*pThreadInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount);
   642 
   643 	TRequestStatus	mediaStatus;
   644 	RThread			mediaThread;
   645 	
   646 	TInt ret;
   647 	DOTEST((ret = TestMsgQueue.CreateLocal(TestMultipleThreadCount * 10, EOwnerProcess)),
   648 	       (KErrNone == ret));
   649 
   650 	DOTEST((ret = TestMultiSem.CreateLocal(1)),
   651 	       (KErrNone == ret));
   652 
   653 	// make sure we have a priority higher than that of the threads we spawn...
   654 	RThread thisThread;
   655 	TThreadPriority savedThreadPriority = thisThread.Priority();
   656 	const TThreadPriority KMainThreadPriority = EPriorityMuchMore;
   657 	__ASSERT_COMPILE(KMainThreadPriority>TEST_INTERLEAVE_PRIO);
   658 	thisThread.SetPriority(KMainThreadPriority);
   659 
   660 	if (TestMediaAccess)
   661 		{
   662 		TestStopMedia = EFalse;
   663 		mediaThread.Create(_L(""),PerformRomAndFileSystemAccess,KDefaultStackSize,NULL,NULL);
   664 		mediaThread.Logon(mediaStatus);
   665 		RUNTEST1(mediaStatus == KRequestPending);
   666 		mediaThread.Resume();
   667 		}
   668 
   669 	// spawn some processes to call the functions....
   670 	for (index = 0; index < TestMultipleThreadCount; index++)
   671 		{
   672 		DBGD_PRINT((_L("%S : Starting thread.%d!\n"), &TestNameBuffer, index));
   673 		DOTEST((ret = pTheThreads[index].Create(_L(""),MultipleTestThread,KDefaultStackSize,NULL,(TAny*) index)),
   674 		       (ret == KErrNone));
   675 		pTheThreads[index].Resume();
   676 		pThreadInUse[index] = 1;
   677 		}
   678 	
   679 	// now process any messages sent from the child threads.
   680 	TBool		anyUsed = ETrue;
   681 	TBuf<64>	localBuffer;
   682 
   683 	while(anyUsed)
   684 		{
   685 		anyUsed = EFalse;
   686 		// check the message queue and call printf if we get a message.
   687 		while (KErrNone == TestMsgQueue.Receive(localBuffer))
   688 			{
   689 			DBGS_PRINT((localBuffer));
   690 			}
   691 
   692 		// walk through the thread list to check which are still alive.
   693 		for (index = 0; index < TestMultipleThreadCount; index++)
   694 			{
   695 			if (pThreadInUse[index])
   696 				{
   697 				if (pTheThreads[index].ExitType() != EExitPending)
   698 					{
   699 					if (pTheThreads[index].ExitType() == EExitPanic)
   700 						{
   701 						DBGS_PRINT((_L("%S : Thread Panic'd  %d...\n"), &TestNameBuffer, index));	
   702 						}
   703 					pThreadInUse[index] = EFalse;
   704 					pTheThreads[index].Close();
   705 					}
   706 				else
   707 					{
   708 					anyUsed = ETrue;
   709 					}
   710 				}
   711 			}
   712 		User::AfterHighRes(50000);
   713 		}
   714 
   715 	if (TestMediaAccess)
   716 		{
   717 		TestStopMedia = ETrue;
   718 		DBGD_PRINT((_L("%S : Waiting for media thread to exit...\n"), &TestNameBuffer));	
   719 		User::WaitForRequest(mediaStatus);
   720 		mediaThread.Close();
   721 		}
   722 
   723 	TestMsgQueue.Close();
   724 	TestMultiSem.Close();
   725 
   726 	// cleanup the resources and exit.
   727 	User::Free(pTheThreads);
   728 	User::Free(pThreadInUse);
   729 
   730 	thisThread.SetPriority(savedThreadPriority);
   731 	}
   732 
   733 
   734 //
   735 // ParseCommandLine 
   736 //
   737 // read the arguments passed from the command line and set global variables to 
   738 // control the tests.
   739 //
   740 
   741 TBool ParseCommandLine()
   742 	{
   743 	TBuf<256> args;
   744 	User::CommandLine(args);
   745 	TLex	lex(args);
   746 	TBool	retVal = ETrue;
   747 	
   748 	// initially test for arguments, the parse them, if not apply some sensible defaults.
   749 	TBool	foundArgs = EFalse;	
   750 	
   751 	FOREVER
   752 		{
   753 		TPtrC  token=lex.NextToken();
   754 		if(token.Length()!=0)
   755 			{
   756 			if ((token == _L("help")) || (token == _L("-h")) || (token == _L("-?")))
   757 				{
   758 				DBGS_PRINT((_L("\nUsage:  %S [debug] [check] [single | multiple <numThreads>]  [forward | backward | random | all] [iters <iters>] [media] [lowmem] [interleave]\n'-' indicated infinity.\n\n"), &TestNameBuffer));
   759 				test.Getch();
   760 				}
   761 			else if (token == _L("debug"))
   762 				{
   763 				if (!TestSilent)
   764 					{
   765 					TestDebug = ETrue;
   766 					TestPrioChange = ETrue;
   767 					}
   768 				}
   769 			else if (token == _L("silent"))
   770 				{
   771 				TestSilent = ETrue;
   772 				TestDebug = EFalse;
   773 				}
   774 			else if (token == _L("check"))
   775 				{
   776 				TestCheck = ETrue;
   777 				}
   778 			else if (token == _L("single"))
   779 				{
   780 				TestSingle = ETrue;
   781 				}
   782 			else if (token == _L("multiple"))
   783 				{
   784 				TPtrC val=lex.NextToken();
   785 				TLex lexv(val);
   786 				TInt value;
   787 
   788 				if (lexv.Val(value)==KErrNone)
   789 					{
   790 					if ((value <= 0) || (value > 100))
   791 						{
   792 						TestMultipleThreadCount = 10;
   793 						}
   794 					else
   795 						{
   796 						TestMultipleThreadCount = value;
   797 						}
   798 					}
   799 				else
   800 					{
   801 					DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
   802 					retVal = EFalse;
   803 					break;
   804 					}
   805 				TestMultiple = ETrue;
   806 				}
   807 			else if (token == _L("prio"))
   808 				{
   809 				TestPrioChange = !TestPrioChange;
   810 				}
   811 			else if (token == _L("lowmem"))
   812 				{
   813 				TestLowMem = ETrue;
   814 				}
   815 			else if (token == _L("media"))
   816 				{
   817 				TestMediaAccess = ETrue;
   818 				}
   819 			else if (token == _L("forward"))
   820 				{
   821 				TestWhichTests = TEST_FORWARD;
   822 				}
   823 			else if (token == _L("backward"))
   824 				{
   825 				TestWhichTests = TEST_BACKWARD;
   826 				}
   827 			else if (token == _L("random"))
   828 				{
   829 				TestWhichTests = TEST_RANDOM;
   830 				}
   831 			else if (token == _L("all"))
   832 				{
   833 				TestWhichTests = TEST_ALL;
   834 				}
   835 			else  if (token == _L("iters"))
   836 				{
   837 				TPtrC val=lex.NextToken();
   838 				TLex lexv(val);
   839 				TInt value;
   840 
   841 				if (val==_L("-"))
   842 					{
   843 					TestForever = ETrue;
   844 					TestMaxLoops = KMaxTInt;
   845 					}
   846 				else
   847 					{
   848 					if (lexv.Val(value)==KErrNone)
   849 						{
   850 						TestMaxLoops = value;
   851 						}
   852 					else
   853 						{
   854 						DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
   855 						retVal = EFalse;
   856 						break;
   857 						}
   858 					}
   859 				}
   860 			else  if (token == _L("interleave"))
   861 				{
   862 				TestInterleave = ETrue;
   863 				}
   864 			else  if (token == _L("inst"))
   865 				{
   866 				TPtrC val=lex.NextToken();
   867 				TLex lexv(val);
   868 				TInt value;
   869 
   870 				if (lexv.Val(value)==KErrNone)
   871 					{
   872 					TestInstanceId = value;
   873 					}
   874 				}
   875 			else
   876 				{
   877 				if ((foundArgs == EFalse) && (token.Length() == 1))
   878 					{
   879 					// Single letter argument...only run on MMC drive
   880 					if (token.CompareF(_L("d")) == 0)
   881 						{
   882 						break;
   883 						}
   884 					else
   885 						{
   886 						if (!TestSilent)
   887 							{
   888 							test.Title();
   889 							test.Start(_L("Skipping non drive 'd' - Test Exiting."));
   890 							test.End();
   891 							}
   892 						foundArgs = ETrue;
   893 						TestExit = ETrue;
   894 						break;
   895 						}
   896 					}
   897 				DBGS_PRINT((_L("Unknown argument '%S' was ignored.\n"), &token));
   898 				break;
   899 				}
   900 			foundArgs = ETrue;
   901 			}
   902 		else
   903 			{
   904 			break;
   905 			}
   906 		}
   907 	if (!foundArgs)
   908 		{
   909 		retVal = EFalse;
   910 		}
   911 	return retVal;
   912 	}
   913 
   914 //
   915 // AreWeTheTestBase
   916 //
   917 // Test whether we are the root of the tests.
   918 //
   919 
   920 void AreWeTheTestBase(void)
   921 	{
   922 	if (!TestSilent)
   923 		{
   924 		TFileName  filename(RProcess().FileName());
   925 
   926 		TParse	myParse;
   927 		myParse.Set(filename, NULL, NULL);
   928 		TestNameBuffer.Zero();
   929 		TestNameBuffer.Append(myParse.Name());
   930 		TestNameBuffer.Append(_L(".exe"));
   931 
   932 		TestWeAreTheTestBase = !TestNameBuffer.Compare(_L("t_pagestress.exe"));
   933 
   934 		RFs fs;
   935 		if (KErrNone != fs.Connect())
   936 			{
   937 			TEntry  anEntry;
   938 			TInt retVal = fs.Entry(_L("z:\\test\\mmcdemandpaginge32tests.bat"), anEntry);
   939 			if (retVal == KErrNone)
   940 				{
   941 				TestBootedFromMmc = ETrue;
   942 				}
   943 			else
   944 				{
   945 				TestBootedFromMmc = EFalse;
   946 				}
   947 			fs.Close();
   948 			}
   949 
   950 		}
   951 	else
   952 		{
   953 		TestNameBuffer.Zero();
   954 		TestNameBuffer.Append(_L("t_pagestress.exe"));
   955 		}
   956 	}
   957 
   958 //
   959 // PerformAutoTest
   960 //
   961 // Perform the autotest
   962 //
   963 void PerformAutoTest()
   964 	{
   965 	SVMCacheInfo  tempPages;
   966 
   967 	if (TestIsDemandPaged)
   968 		{
   969 		UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
   970 		DBGS_PRINT((_L("PerformAutoTest : Start cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
   971 					 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
   972 		}
   973 	TestInterleave = EFalse;
   974 	TestPrioChange = EFalse;
   975 	TestMediaAccess = EFalse;
   976 
   977 #if defined __ARMCC__ || defined __X86__
   978 	// Currently we only build aligned DLLs on ARMV5 and X86 builds.
   979 	TEST_NEXT((_L("Alignment Check.")));
   980 	RUNTEST1(CheckAlignments() == KErrNone);
   981 #endif
   982 
   983 	TestMaxLoops = 2;
   984 	TestWhichTests = TEST_RANDOM;
   985 
   986 	TEST_NEXT((_L("Single thread all.")));
   987 	DoSingleTest();
   988 
   989 	TEST_NEXT((_L("Multiple threads all.")));
   990 	DoMultipleTest();
   991 	
   992 	TestPrioChange = ETrue;
   993 	TEST_NEXT((_L("Multiple threads all with prio.")));
   994 	DoMultipleTest();
   995 
   996 	TestPrioChange = EFalse;
   997 	TestMediaAccess = ETrue;
   998 	TEST_NEXT((_L("Multiple threads all with media activity.")));
   999 	DoMultipleTest();
  1000 
  1001 	TestPrioChange = ETrue;
  1002 	TestMediaAccess = ETrue;
  1003 	TEST_NEXT((_L("Multiple threads all with media activity and prio.")));
  1004 	DoMultipleTest();
  1005 
  1006 	TestInterleave = ETrue;
  1007 	TestPrioChange = EFalse;
  1008 	TestMediaAccess = EFalse;
  1009 	
  1010 	TEST_NEXT((_L("Multiple threads random with interleave.")));
  1011 	DoMultipleTest();
  1012 
  1013 	TestPrioChange = ETrue;
  1014 	TEST_NEXT((_L("Multiple threads random with interleave and prio.")));
  1015 	DoMultipleTest();
  1016 
  1017 	TestMediaAccess = ETrue;
  1018 	TEST_NEXT((_L("Multiple threads random with media interleave and prio.")));
  1019 	DoMultipleTest();
  1020 
  1021 	if (TestIsDemandPaged)
  1022 		{
  1023 		UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
  1024 		DBGS_PRINT((_L("PerformAutoTest : End cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
  1025 					 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
  1026 		}
  1027 	TestInterleave = EFalse;
  1028 	TestPrioChange = EFalse;
  1029 	TestMediaAccess = EFalse;
  1030 	}
  1031 
  1032 //
  1033 // DoLowMemTest
  1034 //
  1035 // Low Memory Test
  1036 //
  1037 
  1038 void DoLowMemTest()
  1039 	{
  1040 	TInt r = User::LoadLogicalDevice(KPageStressTestLddName);
  1041 	RUNTEST1(r==KErrNone || r==KErrAlreadyExists);
  1042 	RUNTEST(Ldd.Open(),KErrNone);
  1043 	
  1044 	SVMCacheInfo  tempPages;
  1045 	memset(&tempPages, 0, sizeof(tempPages));
  1046 
  1047 	if (TestIsDemandPaged)
  1048 		{
  1049 		// get the old cache info
  1050 		UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
  1051 		TInt	minSize = 8 * 4096;
  1052 		TInt	maxSize = 256 * 4096;
  1053 		UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
  1054 		}
  1055 
  1056 	// First load some pages onto the page cache 
  1057 	TestMaxLoops = 1;
  1058 	TestWhichTests = TEST_RANDOM;
  1059 	DoSingleTest();
  1060 
  1061 	Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
  1062 	TEST_NEXT((_L("Single thread with Low memory.")));
  1063 	TestMultipleThreadCount	= 25;
  1064 	TestInterleave = EFalse;
  1065 	TestMaxLoops = 20;
  1066 	TestPrioChange = EFalse;
  1067 	TestMediaAccess = EFalse;
  1068 	TestWhichTests = TEST_ALL;
  1069 	
  1070 	DoSingleTest();
  1071 	
  1072 	Ldd.DoConsumeRamFinish();
  1073 
  1074 	TEST_NEXT((_L("Multiple thread with Low memory.")));
  1075 	// First load some pages onto the page cache 
  1076 	TestMaxLoops = 1;
  1077 	TestWhichTests = TEST_RANDOM;
  1078 	DoSingleTest();
  1079 
  1080 	Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
  1081 	
  1082 	TestWhichTests = TEST_ALL;
  1083 	TestMaxLoops = 10;
  1084 	TestMultipleThreadCount	= 25;
  1085 	DoMultipleTest(ETrue);
  1086 
  1087 	Ldd.DoConsumeRamFinish();
  1088 
  1089 	TEST_NEXT((_L("Multiple thread with Low memory, with starting free ram.")));
  1090 	// First load some pages onto the page cache 
  1091 	TestMaxLoops = 1;
  1092 	TestWhichTests = TEST_RANDOM;
  1093 	DoSingleTest();
  1094 
  1095 	Ldd.DoConsumeRamSetup(32, TEST_LM_BLOCKSIZE);
  1096 	
  1097 	TestWhichTests = TEST_ALL;
  1098 	TestMaxLoops = 10;
  1099 	TestMultipleThreadCount	= 25;
  1100 	DoMultipleTest(ETrue);
  1101 
  1102 	Ldd.DoConsumeRamFinish();
  1103 	
  1104 	TEST_NEXT((_L("Close test driver")));
  1105 	Ldd.Close();
  1106 	RUNTEST(User::FreeLogicalDevice(KPageStressTestLddName), KErrNone);
  1107 	if (TestIsDemandPaged)
  1108 		{
  1109 		TInt minSize = tempPages.iMinSize;
  1110 		TInt maxSize = tempPages.iMaxSize;
  1111 		UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
  1112 		}
  1113 	}
  1114 
  1115 //
  1116 // E32Main
  1117 //
  1118 // Main entry point.
  1119 //
  1120 
  1121 TInt E32Main()
  1122 	{
  1123 #ifndef TEST_ON_UNPAGED
  1124 	TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
  1125 	if(!romHeader->iPageableRomStart)
  1126 		{
  1127 		TestIsDemandPaged = EFalse;
  1128 		}
  1129 #endif
  1130 	TUint start = User::TickCount();
  1131 
  1132 	TBool parseResult = ParseCommandLine();
  1133 
  1134 	if (TestExit)
  1135 		{
  1136 		return KErrNone;
  1137 		}
  1138 
  1139 	AreWeTheTestBase();
  1140 
  1141 	TInt  minSize = 8 * 4096;
  1142 	TInt  maxSize = 64 * 4096;
  1143 	SVMCacheInfo  tempPages;
  1144 	memset(&tempPages, 0, sizeof(tempPages));
  1145 	if (TestIsDemandPaged)
  1146 		{
  1147 		// get the old cache info
  1148 		UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
  1149 		// set the cache to our test value
  1150 		UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
  1151 		}
  1152 
  1153 	// get the page size.
  1154 	UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&TestPageSize,0);
  1155 
  1156 	if (!TestSilent)
  1157 		{
  1158 		test.Title();
  1159 		test.Start(_L("Demand Paging stress tests..."));
  1160 		test.Printf(_L("%S\n"), &TestNameBuffer);
  1161 		}
  1162 
  1163 	if (parseResult)
  1164 		{
  1165 		if (!TestSilent)
  1166 			{
  1167 			extern TInt *CheckLdmiaInstr(void);
  1168 			test.Printf(_L("%S : CheckLdmiaInstr\n"), &TestNameBuffer);
  1169 			TInt   *theAddr = CheckLdmiaInstr();
  1170 			test.Printf(_L("%S : CheckLdmiaInstr complete 0x%x...\n"), &TestNameBuffer, (TInt)theAddr);
  1171 			}
  1172 		if (TestCheck)
  1173 			{
  1174 			CheckAlignments();
  1175 			}
  1176 		if (TestLowMem)
  1177 			{
  1178 			DoLowMemTest();
  1179 			}
  1180 		if (TestSingle)
  1181 			{
  1182 			DoSingleTest();
  1183 			}
  1184 		if (TestMultiple)
  1185 			{
  1186 			DoMultipleTest();
  1187 			}
  1188 		}
  1189 	else
  1190 		{
  1191 		PerformAutoTest();
  1192 
  1193 		DoLowMemTest();
  1194 
  1195 		if (TestWeAreTheTestBase)
  1196 			{
  1197 			RProcess		theProcess;
  1198 			TRequestStatus	status;
  1199 
  1200 			TInt retVal = theProcess.Create(_L("t_pagestress_rom.exe"),_L(""));
  1201 			if (retVal != KErrNotFound)
  1202 				{
  1203 				RUNTEST1(retVal == KErrNone);
  1204 				theProcess.Logon(status);
  1205 				RUNTEST1(status == KRequestPending);
  1206 				theProcess.Resume();
  1207 				User::WaitForRequest(status);
  1208 				if (theProcess.ExitType() != EExitPending)
  1209 					{
  1210 					RUNTEST1(theProcess.ExitType() != EExitPanic);
  1211 					}
  1212 				}
  1213 			}
  1214 		}
  1215 
  1216 	if (TestIsDemandPaged)
  1217 		{
  1218 		minSize = tempPages.iMinSize;
  1219 		maxSize = tempPages.iMaxSize;
  1220 		// put the cache back to the the original values.
  1221 		UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
  1222 		}
  1223 
  1224 	if (!TestSilent)
  1225 		{
  1226 		test.Printf(_L("%S : Complete (%u ticks)\n"), &TestNameBuffer, User::TickCount() - start);	
  1227 		test.End();
  1228 		}
  1229 	return 0;
  1230 	}
  1231 
  1232