Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32test\demandpaging\t_pagestress.cpp
// Demand Paging Stress Tests
// t_pagestress.exe basically attempts to cause large ammounts of paging by calling
// functions (256) which are alligned on a page boundary from multiple threads.
// There are mulitple versions of t_pagestress installed on a test system to test rom
// and code paging from various media types.
// Usage:
// t_pagestress and t_pagestress_rom
// Common command lines:
// t_pagestress lowmem
// debug - switch on debugging information
// silent - no output to the screen or serial port
// check - check the allignments
// single - run the tests in a single thread
// multiple <numThreads> - run the tests in multiple threads where <numThreads>
// interleave - force thread interleaving
// prio - each thread reschedules in between each function call, causes lots of context changes
// media - perform media access during the tests, very stressful
// lowmem - low memory tests
// forward - patern in which to execute function calls
// backward - patern in which to execute function calls
// random - patern in which to execute function calls
// all - patern in which to execute function calls (forward, backward and random)
// inst - for debugging a parameter passed to a spawned exe to give it an id.
// iters <count> - the number of times to loop (a '-' means run forever)
// t_pagestress causes a large ammount of paging by repeatedly calling
// 256 functions which have been aligned on page boundaries from
// multiple threads.
// 1 - a single thread calling all functions
// 2 - Multiple threads calling all functions
// 3 - Multiple threads calling all functions with a priority change
// after each function call
// 4 - Multiple threads calling all functions with background
// media activity
// 5 - Multiple threads calling all functions with media activity and
// a priority change after each function call
// 6 - Multiple threads calling all functions with process interleave
// 7 - Multiple threads calling all functions with process interleave
// and a priority change after each function call
// 8 - Multiple threads calling all functions with process interleave
// media acess and a priority change after each function call
// 9 - Multiple threads calling all functions with low available memory
// 10 - Multiple threads calling all functions with low available memory,
// starting with initial free ram.
//
//
//! @SYMTestCaseID KBASE-T_PAGESTRESS-0327
//! @SYMTestType UT
//! @SYMPREQ PREQ1110
//! @SYMTestCaseDesc Demand Paging Stress Tests
//! @SYMTestActions 0 - Check the alignment of all functions
//! @SYMTestExpectedResults All tests should pass.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
#include <e32test.h>
RTest test(_L("T_PAGESTRESS"));
#include <e32rom.h>
#include <e32svr.h>
#include <u32hal.h>
#include <f32file.h>
#include <f32dbg.h>
#include <e32msgqueue.h>
#include <e32math.h>
#include "testdefs.h"
#ifdef __X86__
#define TEST_ON_UNPAGED
#endif
/* The following line will cause t_pagestress.h to declare an array of function
* pointers to page boundary aligned functions that we can use in this test...
*/
#define TPS_DECLARE_ARRAY
#include "t_pagestress.h"
TBool TestDebug = EFalse;
TBool TestSilent = EFalse;
TBool TestExit = EFalse;
TBool TestCheck = EFalse;
TBool TestSingle = EFalse;
TBool TestMultiple = EFalse;
TBool TestForever = EFalse;
TInt TestMaxLoops = 20;
TInt TestMultipleThreadCount = 50;
TInt TestInstanceId = 0;
#define TEST_INTERLEAVE_PRIO EPriorityMore//EPriorityRealTime //23 // KNandThreadPriority - 1
TBool TestInterleave = EFalse;
TBool TestWeAreTheTestBase = EFalse;
TBool TestBootedFromMmc = EFalse;
TInt DriveNumber=-1; // Parameter - Which drive? -1 = autodetect.
#define TEST_NONE 0x0
#define TEST_FORWARD 0x2
#define TEST_BACKWARD 0x4
#define TEST_RANDOM 0x8
#define TEST_ALL (TEST_RANDOM | TEST_BACKWARD | TEST_FORWARD)
TUint32 TestWhichTests = TEST_ALL;
TBuf<32> TestNameBuffer;
TBool TestPrioChange = ETrue;
TBool TestStopMedia = EFalse;
TBool TestMediaAccess = EFalse;
#define TEST_LM_NUM_FREE 0
#define TEST_LM_BLOCKSIZE 1
#define TEST_LM_BLOCKS_FREE 4
TBool TestLowMem = EFalse;
RPageStressTestLdd Ldd;
TInt TestPageSize = 4096;
RSemaphore TestMultiSem;
RMsgQueue<TBuf <64> > TestMsgQueue;
TBool TestIsDemandPaged = ETrue;
#define TEST_NEXT(__args) \
if (!TestSilent)\
test.Next __args;
#define DBGS_PRINT(__args)\
if (!TestSilent)\
test.Printf __args ;
#define DBGD_PRINT(__args)\
if (TestDebug)\
test.Printf __args ;\
#define DEBUG_PRINT(__args)\
if (!TestSilent)\
{\
if (aMsgQueue && aBuffer && aTheSem)\
{\
aBuffer->Zero();\
aBuffer->Format __args ;\
aTheSem->Wait();\
aMsgQueue->SendBlocking(*aBuffer);\
aTheSem->Signal();\
}\
else\
{\
test.Printf __args ;\
}\
}
#define RUNTEST(__test, __error)\
if (!TestSilent)\
test(__test == __error);\
else\
__test;
#define RUNTEST1(__test)\
if (!TestSilent)\
test(__test);
#define DEBUG_PRINT1(__args)\
if (TestDebug)\
{\
DEBUG_PRINT(__args)\
}
//
// CheckAlignments
//
// The following functions wanders through the function pointer array
// declared in t_pagestress.h and ensures that the alignment has worked,
// (a good start!) and then calls each of the functions in turn to
// ensure that they work, simple first sanity check test.
//
TInt CheckAlignments()
{
// now it's time to play with the array of function pointers...
TInt seed = 1;
TUint32 index = 0;
TInt ret = KErrNone;
while (index < (PAGESTRESS_FUNC_COUNT - 1))
{
DBGD_PRINT((_L("\nAddress (%u) 0x%x difference to next %u\n"), index, (TUint32)PagestressFuncPtrs[index], (TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[index]));
if ((((TUint32)PagestressFuncPtrs[index + 1] - (TUint32)PagestressFuncPtrs[0]) % 4096) != 0)
{
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]));
ret = KErrGeneral;
}
//seed = PagestressFuncPtrs[index](seed, index);
seed = CallTestFunc(seed, index, index);
index ++;
}
return ret;
}
//
// RunThreadForward
//
// Walk through the function pointer array (forwards) calling each function
//
void RunThreadForward()
{
TInt seed = 1;
TUint32 index = 0;
RThread thisThread;
while (index < PAGESTRESS_FUNC_COUNT)
{
if (TestPrioChange)
{
TThreadPriority originalThreadPriority = thisThread.Priority();
thisThread.SetPriority(EPriorityLess);
User::AfterHighRes(0);
thisThread.SetPriority(originalThreadPriority);
}
//seed = PagestressFuncPtrs[index](seed, index);
seed = CallTestFunc(seed, index, index);
index ++;
}
}
//
// RunThreadBackward
//
// Walk through the function pointer array (backwards) calling each function
//
void RunThreadBackward()
{
TInt seed = 1;
TInt index = PAGESTRESS_FUNC_COUNT;
RThread thisThread;
while (index > 0)
{
if (TestPrioChange)
{
TThreadPriority originalThreadPriority = thisThread.Priority();
thisThread.SetPriority(EPriorityLess);
User::AfterHighRes(0);
thisThread.SetPriority(originalThreadPriority);
}
index --;
//seed = PagestressFuncPtrs[index](seed, index);
seed = CallTestFunc(seed, index, index);
}
}
//
// RunThreadRandom
//
// Walk through the function pointer array in a random order a number of times calling each function
//
void RunThreadRandom()
{
TInt seed = 1;
TInt index = 0;
TInt randNum;
RThread thisThread;
while (index < (TInt)PAGESTRESS_FUNC_COUNT)
{
if (TestPrioChange)
{
TThreadPriority originalThreadPriority = thisThread.Priority();
thisThread.SetPriority(EPriorityLess);
User::AfterHighRes(0);
thisThread.SetPriority(originalThreadPriority);
}
randNum = Math::Random();
randNum %= PAGESTRESS_FUNC_COUNT;
//seed = PagestressFuncPtrs[randNum](seed, randNum);
seed = CallTestFunc(seed, randNum, randNum);
index ++;
}
}
//
// PerformTestThread
//
// This is the function that actually does the work.
// It is complicated a little because test.Printf can only be called from the first thread that calls it
// so if we are using multiple threads we need to use a message queue to pass the debug info from the
// child threads back to the parent for the parent to then call printf.
//
//
LOCAL_C void PerformTestThread(TInt aThreadIndex,
RMsgQueue<TBuf <64> > *aMsgQueue = NULL,
TBuf<64> *aBuffer = NULL,
RSemaphore *aTheSem = NULL)
{
TUint start = User::TickCount();
DEBUG_PRINT1((_L("%S : thread Starting %d\n"), &TestNameBuffer, aThreadIndex));
// now select how we do the test...
TInt iterIndex;
if (TEST_ALL == (TestWhichTests & TEST_ALL))
{
#define LOCAL_ORDER_INDEX1 6
#define LOCAL_ORDER_INDEX2 3
TInt order[LOCAL_ORDER_INDEX1][LOCAL_ORDER_INDEX2] = { {TEST_FORWARD, TEST_BACKWARD,TEST_RANDOM},
{TEST_FORWARD, TEST_RANDOM, TEST_BACKWARD},
{TEST_BACKWARD,TEST_FORWARD, TEST_RANDOM},
{TEST_BACKWARD,TEST_RANDOM, TEST_FORWARD},
{TEST_RANDOM, TEST_FORWARD, TEST_BACKWARD},
{TEST_RANDOM, TEST_BACKWARD,TEST_FORWARD}};
TInt whichOrder = 0;
for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
{
TInt selOrder = ((aThreadIndex + 1) * (iterIndex + 1)) % LOCAL_ORDER_INDEX1;
for (whichOrder = 0; whichOrder < LOCAL_ORDER_INDEX2; whichOrder ++)
{
switch (order[selOrder][whichOrder])
{
case TEST_FORWARD:
DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadForward();
break;
case TEST_BACKWARD:
DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadBackward();
break;
case TEST_RANDOM:
DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadRandom();
break;
default: // this is really an error.
break;
}
}
}
}
else
{
if (TestWhichTests & TEST_FORWARD)
{
for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
{
DEBUG_PRINT1((_L("%S : %d Iter %d Forward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadForward();
}
}
if (TestWhichTests & TEST_BACKWARD)
{
for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
{
DEBUG_PRINT1((_L("%S : %d Iter %d Backward\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadBackward();
}
}
if (TestWhichTests & TEST_RANDOM)
{
for (iterIndex = 0; iterIndex < TestMaxLoops; iterIndex ++)
{
DEBUG_PRINT1((_L("%S : %d Iter %d Random\n"), &TestNameBuffer, aThreadIndex, iterIndex));
RunThreadRandom();
}
}
}
DEBUG_PRINT1((_L("%S : thread Exiting %d (tickcount %u)\n"), &TestNameBuffer, aThreadIndex, User::TickCount() - start));
}
//
// MultipleTestThread
//
// Thread function, one created for each thread in a multiple thread test.
//
LOCAL_C TInt MultipleTestThread(TAny* aUseTb)
{
TBuf<64> localBuffer;
if (TestInterleave)
{
RThread thisThread;
thisThread.SetPriority((TThreadPriority) TEST_INTERLEAVE_PRIO);
}
PerformTestThread((TInt) aUseTb, &TestMsgQueue, &localBuffer, &TestMultiSem);
return KErrNone;
}
//
// DoSingleTest
//
// Perform the single thread test, spawning a number of threads.
//
LOCAL_C void DoSingleTest()
{
PerformTestThread((TInt) TestInstanceId);
}
//
// FindDriveNumber
//
// Find the first read write drive.
//
TInt FindDriveNumber(RFs fs)
{
TDriveInfo driveInfo;
for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
{
TInt r = fs.Drive(driveInfo, drvNum);
if (r >= 0)
{
if (driveInfo.iType == EMediaHardDisk)
return (drvNum);
}
}
return -1;
}
//
// FindFsNANDDrive
//
// Find the NAND drive
//
static TInt FindFsNANDDrive(RFs& aFs)
{
TDriveList driveList;
TDriveInfo driveInfo;
TInt r=aFs.DriveList(driveList);
if (r == KErrNone)
{
for (TInt drvNum= (DriveNumber<0)?0:DriveNumber; drvNum<KMaxDrives; ++drvNum)
{
if(!driveList[drvNum])
continue; //-- skip unexisting drive
if (aFs.Drive(driveInfo, drvNum) == KErrNone)
{
if(driveInfo.iMediaAtt&KMediaAttPageable)
{
TBool readOnly = driveInfo.iMediaAtt & KMediaAttWriteProtected; // skip ROFS partitions
if(!readOnly)
{
if ((drvNum==DriveNumber) || (DriveNumber<0)) // only test if running on this drive
{
return (drvNum);
}
}
}
}
}
}
return -1;
}
//
// FindMMCDriveNumber
//
// Find the first read write drive.
//
TInt FindMMCDriveNumber(RFs& aFs)
{
TDriveInfo driveInfo;
for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
{
TInt r = aFs.Drive(driveInfo, drvNum);
if (r >= 0)
{
if (driveInfo.iType == EMediaHardDisk)
return (drvNum);
}
}
return -1;
}
//
// PerformRomAndFileSystemAccess
//
// Access the rom and dump it out to one of the writeable partitions...
// really just to make the media server a little busy during the test.
//
TInt PerformRomAndFileSystemAccessThread(RMsgQueue<TBuf <64> > *aMsgQueue = NULL,
TBuf<64> *aBuffer = NULL,
RSemaphore *aTheSem = NULL)
{
TUint maxBytes = KMaxTUint;
TInt startTime = User::TickCount();
RFs fs;
RFile file;
if (KErrNone != fs.Connect())
{
DEBUG_PRINT(_L("PerformRomAndFileSystemAccessThread : Can't connect to the FS\n"));
return KErrGeneral;
}
// get info about the ROM...
TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
TUint8* start;
TUint8* end;
if(romHeader->iPageableRomStart)
{
start = (TUint8*)romHeader + romHeader->iPageableRomStart;
end = start + romHeader->iPageableRomSize;
}
else
{
start = (TUint8*)romHeader;
end = start + romHeader->iUncompressedSize;
}
if (end <= start)
return KErrGeneral;
// read all ROM pages in a random order...and write out to file in ROFs,
TUint size = end - start - TestPageSize;
if(size > maxBytes)
size = maxBytes;
TUint32 random=1;
TPtrC8 rom;
TUint8 *theAddr;
TInt drvNum = TestBootedFromMmc ? FindMMCDriveNumber(fs) : FindFsNANDDrive(fs);
TBuf<32> filename = _L("d:\\Pageldrtst.tmp");
if (drvNum >= 0)
{
filename[0] = 'a' + drvNum;
DEBUG_PRINT((_L("%S : Filename %S\n"), &TestNameBuffer, &filename));
}
else
DEBUG_PRINT((_L("PerformRomAndFileSystemAccessThread : error getting drive num\n")));
for(TInt i=size/(TestPageSize); i>0; --i)
{
DEBUG_PRINT1((_L("%S : Opening the file\n"), &TestNameBuffer));
if (KErrNone != file.Replace(fs, filename, EFileWrite))
{
DEBUG_PRINT((_L("%S : Opening the file Failed!\n"), &TestNameBuffer));
}
random = random*69069+1;
theAddr = (TUint8*)(start+((TInt64(random)*TInt64(size))>>32));
if (theAddr + TestPageSize > end)
{
DEBUG_PRINT((_L("%S : address is past the end 0x%x / 0x%x\n"), &TestNameBuffer, (TInt)theAddr, (TInt)end));
}
rom.Set(theAddr,TestPageSize);
DEBUG_PRINT1((_L("%S : Writing the file\n"), &TestNameBuffer));
TInt ret = file.Write(rom);
if (ret != KErrNone)
{
DEBUG_PRINT1((_L("%S : Write returned error %d\n"), &TestNameBuffer, ret));
}
DEBUG_PRINT1((_L("%S : Closing the file\n"), &TestNameBuffer));
file.Close();
DEBUG_PRINT1((_L("%S : Deleting the file\n"), &TestNameBuffer));
ret = fs.Delete(filename);
if (KErrNone != ret)
{
DEBUG_PRINT((_L("%S : Delete returned error %d\n"), &TestNameBuffer, ret));
}
if (TestStopMedia)
break;
}
fs.Close();
DEBUG_PRINT1((_L("Done in %d ticks\n"), User::TickCount() - startTime));
return KErrNone;
}
//
// PerformRomAndFileSystemAccess
//
// Thread function, kicks off the file system access.
//
LOCAL_C TInt PerformRomAndFileSystemAccess(TAny* )
{
TBuf<64> localBuffer;
PerformRomAndFileSystemAccessThread(&TestMsgQueue, &localBuffer, &TestMultiSem);
return KErrNone;
}
//
// DoMultipleTest
//
// Perform the multiple thread test, spawning a number of threads.
// It is complicated a little because test.Printf can only be called from the first thread that calls it
// so if we are using multiple threads we need to use a message queue to pass the debug info from the
// child threads back to the parent for the parent to then call printf.
//
#define DOTEST(__operation, __condition)\
if (aLowMem) \
{\
__operation;\
while (!__condition)\
{\
Ldd.DoReleaseSomeRam(TEST_LM_BLOCKS_FREE);\
__operation;\
}\
RUNTEST1(__condition);\
}\
else\
{\
__operation;\
RUNTEST1(__condition);\
}
void DoMultipleTest(TBool aLowMem = EFalse)
{
TInt index;
RThread *pTheThreads = (RThread *)User::AllocZ(sizeof(RThread) * TestMultipleThreadCount);
TInt *pThreadInUse = (TInt *)User::AllocZ(sizeof(TInt) * TestMultipleThreadCount);
TRequestStatus mediaStatus;
RThread mediaThread;
TInt ret;
DOTEST((ret = TestMsgQueue.CreateLocal(TestMultipleThreadCount * 10, EOwnerProcess)),
(KErrNone == ret));
DOTEST((ret = TestMultiSem.CreateLocal(1)),
(KErrNone == ret));
// make sure we have a priority higher than that of the threads we spawn...
RThread thisThread;
TThreadPriority savedThreadPriority = thisThread.Priority();
const TThreadPriority KMainThreadPriority = EPriorityMuchMore;
__ASSERT_COMPILE(KMainThreadPriority>TEST_INTERLEAVE_PRIO);
thisThread.SetPriority(KMainThreadPriority);
if (TestMediaAccess)
{
TestStopMedia = EFalse;
mediaThread.Create(_L(""),PerformRomAndFileSystemAccess,KDefaultStackSize,NULL,NULL);
mediaThread.Logon(mediaStatus);
RUNTEST1(mediaStatus == KRequestPending);
mediaThread.Resume();
}
// spawn some processes to call the functions....
for (index = 0; index < TestMultipleThreadCount; index++)
{
DBGD_PRINT((_L("%S : Starting thread.%d!\n"), &TestNameBuffer, index));
DOTEST((ret = pTheThreads[index].Create(_L(""),MultipleTestThread,KDefaultStackSize,NULL,(TAny*) index)),
(ret == KErrNone));
pTheThreads[index].Resume();
pThreadInUse[index] = 1;
}
// now process any messages sent from the child threads.
TBool anyUsed = ETrue;
TBuf<64> localBuffer;
while(anyUsed)
{
anyUsed = EFalse;
// check the message queue and call printf if we get a message.
while (KErrNone == TestMsgQueue.Receive(localBuffer))
{
DBGS_PRINT((localBuffer));
}
// walk through the thread list to check which are still alive.
for (index = 0; index < TestMultipleThreadCount; index++)
{
if (pThreadInUse[index])
{
if (pTheThreads[index].ExitType() != EExitPending)
{
if (pTheThreads[index].ExitType() == EExitPanic)
{
DBGS_PRINT((_L("%S : Thread Panic'd %d...\n"), &TestNameBuffer, index));
}
pThreadInUse[index] = EFalse;
pTheThreads[index].Close();
}
else
{
anyUsed = ETrue;
}
}
}
User::AfterHighRes(50000);
}
if (TestMediaAccess)
{
TestStopMedia = ETrue;
DBGD_PRINT((_L("%S : Waiting for media thread to exit...\n"), &TestNameBuffer));
User::WaitForRequest(mediaStatus);
mediaThread.Close();
}
TestMsgQueue.Close();
TestMultiSem.Close();
// cleanup the resources and exit.
User::Free(pTheThreads);
User::Free(pThreadInUse);
thisThread.SetPriority(savedThreadPriority);
}
//
// ParseCommandLine
//
// read the arguments passed from the command line and set global variables to
// control the tests.
//
TBool ParseCommandLine()
{
TBuf<256> args;
User::CommandLine(args);
TLex lex(args);
TBool retVal = ETrue;
// initially test for arguments, the parse them, if not apply some sensible defaults.
TBool foundArgs = EFalse;
FOREVER
{
TPtrC token=lex.NextToken();
if(token.Length()!=0)
{
if ((token == _L("help")) || (token == _L("-h")) || (token == _L("-?")))
{
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));
test.Getch();
}
else if (token == _L("debug"))
{
if (!TestSilent)
{
TestDebug = ETrue;
TestPrioChange = ETrue;
}
}
else if (token == _L("silent"))
{
TestSilent = ETrue;
TestDebug = EFalse;
}
else if (token == _L("check"))
{
TestCheck = ETrue;
}
else if (token == _L("single"))
{
TestSingle = ETrue;
}
else if (token == _L("multiple"))
{
TPtrC val=lex.NextToken();
TLex lexv(val);
TInt value;
if (lexv.Val(value)==KErrNone)
{
if ((value <= 0) || (value > 100))
{
TestMultipleThreadCount = 10;
}
else
{
TestMultipleThreadCount = value;
}
}
else
{
DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
retVal = EFalse;
break;
}
TestMultiple = ETrue;
}
else if (token == _L("prio"))
{
TestPrioChange = !TestPrioChange;
}
else if (token == _L("lowmem"))
{
TestLowMem = ETrue;
}
else if (token == _L("media"))
{
TestMediaAccess = ETrue;
}
else if (token == _L("forward"))
{
TestWhichTests = TEST_FORWARD;
}
else if (token == _L("backward"))
{
TestWhichTests = TEST_BACKWARD;
}
else if (token == _L("random"))
{
TestWhichTests = TEST_RANDOM;
}
else if (token == _L("all"))
{
TestWhichTests = TEST_ALL;
}
else if (token == _L("iters"))
{
TPtrC val=lex.NextToken();
TLex lexv(val);
TInt value;
if (val==_L("-"))
{
TestForever = ETrue;
TestMaxLoops = KMaxTInt;
}
else
{
if (lexv.Val(value)==KErrNone)
{
TestMaxLoops = value;
}
else
{
DBGS_PRINT((_L("Bad value for thread count '%S' was ignored.\n"), &val));
retVal = EFalse;
break;
}
}
}
else if (token == _L("interleave"))
{
TestInterleave = ETrue;
}
else if (token == _L("inst"))
{
TPtrC val=lex.NextToken();
TLex lexv(val);
TInt value;
if (lexv.Val(value)==KErrNone)
{
TestInstanceId = value;
}
}
else
{
if ((foundArgs == EFalse) && (token.Length() == 1))
{
// Single letter argument...only run on MMC drive
if (token.CompareF(_L("d")) == 0)
{
break;
}
else
{
if (!TestSilent)
{
test.Title();
test.Start(_L("Skipping non drive 'd' - Test Exiting."));
test.End();
}
foundArgs = ETrue;
TestExit = ETrue;
break;
}
}
DBGS_PRINT((_L("Unknown argument '%S' was ignored.\n"), &token));
break;
}
foundArgs = ETrue;
}
else
{
break;
}
}
if (!foundArgs)
{
retVal = EFalse;
}
return retVal;
}
//
// AreWeTheTestBase
//
// Test whether we are the root of the tests.
//
void AreWeTheTestBase(void)
{
if (!TestSilent)
{
TFileName filename(RProcess().FileName());
TParse myParse;
myParse.Set(filename, NULL, NULL);
TestNameBuffer.Zero();
TestNameBuffer.Append(myParse.Name());
TestNameBuffer.Append(_L(".exe"));
TestWeAreTheTestBase = !TestNameBuffer.Compare(_L("t_pagestress.exe"));
RFs fs;
if (KErrNone != fs.Connect())
{
TEntry anEntry;
TInt retVal = fs.Entry(_L("z:\\test\\mmcdemandpaginge32tests.bat"), anEntry);
if (retVal == KErrNone)
{
TestBootedFromMmc = ETrue;
}
else
{
TestBootedFromMmc = EFalse;
}
fs.Close();
}
}
else
{
TestNameBuffer.Zero();
TestNameBuffer.Append(_L("t_pagestress.exe"));
}
}
//
// PerformAutoTest
//
// Perform the autotest
//
void PerformAutoTest()
{
SVMCacheInfo tempPages;
if (TestIsDemandPaged)
{
UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
DBGS_PRINT((_L("PerformAutoTest : Start cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
}
TestInterleave = EFalse;
TestPrioChange = EFalse;
TestMediaAccess = EFalse;
#if defined __ARMCC__ || defined __X86__
// Currently we only build aligned DLLs on ARMV5 and X86 builds.
TEST_NEXT((_L("Alignment Check.")));
RUNTEST1(CheckAlignments() == KErrNone);
#endif
TestMaxLoops = 2;
TestWhichTests = TEST_RANDOM;
TEST_NEXT((_L("Single thread all.")));
DoSingleTest();
TEST_NEXT((_L("Multiple threads all.")));
DoMultipleTest();
TestPrioChange = ETrue;
TEST_NEXT((_L("Multiple threads all with prio.")));
DoMultipleTest();
TestPrioChange = EFalse;
TestMediaAccess = ETrue;
TEST_NEXT((_L("Multiple threads all with media activity.")));
DoMultipleTest();
TestPrioChange = ETrue;
TestMediaAccess = ETrue;
TEST_NEXT((_L("Multiple threads all with media activity and prio.")));
DoMultipleTest();
TestInterleave = ETrue;
TestPrioChange = EFalse;
TestMediaAccess = EFalse;
TEST_NEXT((_L("Multiple threads random with interleave.")));
DoMultipleTest();
TestPrioChange = ETrue;
TEST_NEXT((_L("Multiple threads random with interleave and prio.")));
DoMultipleTest();
TestMediaAccess = ETrue;
TEST_NEXT((_L("Multiple threads random with media interleave and prio.")));
DoMultipleTest();
if (TestIsDemandPaged)
{
UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
DBGS_PRINT((_L("PerformAutoTest : End cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d\n"),
tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize));
}
TestInterleave = EFalse;
TestPrioChange = EFalse;
TestMediaAccess = EFalse;
}
//
// DoLowMemTest
//
// Low Memory Test
//
void DoLowMemTest()
{
TInt r = User::LoadLogicalDevice(KPageStressTestLddName);
RUNTEST1(r==KErrNone || r==KErrAlreadyExists);
RUNTEST(Ldd.Open(),KErrNone);
SVMCacheInfo tempPages;
memset(&tempPages, 0, sizeof(tempPages));
if (TestIsDemandPaged)
{
// get the old cache info
UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
TInt minSize = 8 * 4096;
TInt maxSize = 256 * 4096;
UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
}
// First load some pages onto the page cache
TestMaxLoops = 1;
TestWhichTests = TEST_RANDOM;
DoSingleTest();
Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
TEST_NEXT((_L("Single thread with Low memory.")));
TestMultipleThreadCount = 25;
TestInterleave = EFalse;
TestMaxLoops = 20;
TestPrioChange = EFalse;
TestMediaAccess = EFalse;
TestWhichTests = TEST_ALL;
DoSingleTest();
Ldd.DoConsumeRamFinish();
TEST_NEXT((_L("Multiple thread with Low memory.")));
// First load some pages onto the page cache
TestMaxLoops = 1;
TestWhichTests = TEST_RANDOM;
DoSingleTest();
Ldd.DoConsumeRamSetup(TEST_LM_NUM_FREE, TEST_LM_BLOCKSIZE);
TestWhichTests = TEST_ALL;
TestMaxLoops = 10;
TestMultipleThreadCount = 25;
DoMultipleTest(ETrue);
Ldd.DoConsumeRamFinish();
TEST_NEXT((_L("Multiple thread with Low memory, with starting free ram.")));
// First load some pages onto the page cache
TestMaxLoops = 1;
TestWhichTests = TEST_RANDOM;
DoSingleTest();
Ldd.DoConsumeRamSetup(32, TEST_LM_BLOCKSIZE);
TestWhichTests = TEST_ALL;
TestMaxLoops = 10;
TestMultipleThreadCount = 25;
DoMultipleTest(ETrue);
Ldd.DoConsumeRamFinish();
TEST_NEXT((_L("Close test driver")));
Ldd.Close();
RUNTEST(User::FreeLogicalDevice(KPageStressTestLddName), KErrNone);
if (TestIsDemandPaged)
{
TInt minSize = tempPages.iMinSize;
TInt maxSize = tempPages.iMaxSize;
UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
}
}
//
// E32Main
//
// Main entry point.
//
TInt E32Main()
{
#ifndef TEST_ON_UNPAGED
TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
if(!romHeader->iPageableRomStart)
{
TestIsDemandPaged = EFalse;
}
#endif
TUint start = User::TickCount();
TBool parseResult = ParseCommandLine();
if (TestExit)
{
return KErrNone;
}
AreWeTheTestBase();
TInt minSize = 8 * 4096;
TInt maxSize = 64 * 4096;
SVMCacheInfo tempPages;
memset(&tempPages, 0, sizeof(tempPages));
if (TestIsDemandPaged)
{
// get the old cache info
UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0);
// set the cache to our test value
UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
}
// get the page size.
UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&TestPageSize,0);
if (!TestSilent)
{
test.Title();
test.Start(_L("Demand Paging stress tests..."));
test.Printf(_L("%S\n"), &TestNameBuffer);
}
if (parseResult)
{
if (!TestSilent)
{
extern TInt *CheckLdmiaInstr(void);
test.Printf(_L("%S : CheckLdmiaInstr\n"), &TestNameBuffer);
TInt *theAddr = CheckLdmiaInstr();
test.Printf(_L("%S : CheckLdmiaInstr complete 0x%x...\n"), &TestNameBuffer, (TInt)theAddr);
}
if (TestCheck)
{
CheckAlignments();
}
if (TestLowMem)
{
DoLowMemTest();
}
if (TestSingle)
{
DoSingleTest();
}
if (TestMultiple)
{
DoMultipleTest();
}
}
else
{
PerformAutoTest();
DoLowMemTest();
if (TestWeAreTheTestBase)
{
RProcess theProcess;
TRequestStatus status;
TInt retVal = theProcess.Create(_L("t_pagestress_rom.exe"),_L(""));
if (retVal != KErrNotFound)
{
RUNTEST1(retVal == KErrNone);
theProcess.Logon(status);
RUNTEST1(status == KRequestPending);
theProcess.Resume();
User::WaitForRequest(status);
if (theProcess.ExitType() != EExitPending)
{
RUNTEST1(theProcess.ExitType() != EExitPanic);
}
}
}
}
if (TestIsDemandPaged)
{
minSize = tempPages.iMinSize;
maxSize = tempPages.iMaxSize;
// put the cache back to the the original values.
UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
}
if (!TestSilent)
{
test.Printf(_L("%S : Complete (%u ticks)\n"), &TestNameBuffer, User::TickCount() - start);
test.End();
}
return 0;
}