diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/mmu/t_mmustress.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/mmu/t_mmustress.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,669 @@ +// Copyright (c) 2008-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: +// e32test\mmu\t_mmustress.cpp +// Stress test for memory management services performed by the kernel's memory model. +// +// + +/** + @file +*/ + +#define __E32TEST_EXTENSION__ +#include +#include "u32std.h" +#include +#include +#include +#include +#include +#include "d_memorytest.h" +#include "..\defrag\d_pagemove.h" + +TBool TRACE = 0; + +LOCAL_D RTest test(_L("T_MMUSTRESS")); + +TUint32 MemModelAttributes; +TUint32 MemModel; +TInt PageSize; +TInt PageMask; + +#if !defined(__WINS__) && !defined(__X86__) +const TPtrC KMoveLddFileName=_L("D_PAGEMOVE.LDD"); +RPageMove MoveLdd; +#endif + +RMemoryTestLdd Ldd; + +const TUint KNumTestChunks = 6; +RChunk Chunks[KNumTestChunks]; +TInt Committed[KNumTestChunks] = {0}; // for each chunk, is the 'owned' region uncommited(0), commited(1) or mixed(-1) +class TNicePtr8 : public TPtr8 { public: TNicePtr8() : TPtr8(0,0) {} } ChunkPtr[KNumTestChunks]; + +const TUint KNumSlaveProcesses = 4; +RProcess Slaves[KNumSlaveProcesses]; +TRequestStatus SlaveLogons[KNumSlaveProcesses]; +TRequestStatus SlaveRendezvous[KNumSlaveProcesses]; + +TInt SlaveNumber = -1; // master process is slave -1 + +const TInt KLocalIpcBufferSize = 0x10000; +TUint8* LocalIpcBuffer = 0; + +RSemaphore StartSemaphore; + +// +// Random number generation +// + +TUint32 RandomSeed; + +TUint32 Random() + { + RandomSeed = RandomSeed*69069+1; + return RandomSeed; + } + +TUint32 Random(TUint32 aRange) + { + return (TUint32)((TUint64(Random())*TUint64(aRange))>>32); + } + +void RandomInit(TUint32 aSeed) + { + RandomSeed = aSeed+(aSeed<<8)+(aSeed<<16)+(aSeed<<24); + Random(); + Random(); + } + + + +// +// Chunk utils +// + +TBuf ChunkName(TInt aChunkNumber) + { + TBuf name; + name.Format(_L("T_MMUSTRESS-Chunk%d"),aChunkNumber); + return name; + } + +#ifdef __WINS__ +TInt KChunkShift = 16; +#elif defined(__X86__) +TInt KChunkShift = 22; +#else +TInt KChunkShift = 20; +#endif + +TInt ChunkSize(TInt aChunkNumber) + { + // biggest chunk (number 0) is big enough for each slave to own a region which is + // 2 page tables ('chunks') in size... + return (2*KNumSlaveProcesses)<<(KChunkShift-aChunkNumber); + } + +// check smallest chunk is less than 'chunk' size... +__ASSERT_COMPILE((2*KNumSlaveProcesses>>(KNumTestChunks-1))==0); + + +/* Memory region 'owned' by this slave process */ +void ChunkOwnedRegion(TInt aChunkNumber,TInt& aOffset,TInt& aSize) + { + TInt size = ChunkSize(aChunkNumber)/KNumSlaveProcesses; + aSize = size; + aOffset = SlaveNumber*size; + test_Equal(0,size&PageMask); + } + +void ChunkMarkRegion(TInt aChunkNumber,TInt aOffset,TInt aSize) + { + TInt pageSize = PageSize; + TUint32 mark = aOffset|aChunkNumber|(SlaveNumber<<4); + TUint8* ptr = Chunks[aChunkNumber].Base()+aOffset; + TUint8* ptrEnd = ptr+aSize; + while(ptr ServerName(TInt aSlaveNumber) + { + TBuf name; + name.Format(_L("T_MMUSTRESS-Server%d"),aSlaveNumber); + return name; + } + +RServer2 Server; +RMessage2 ServerMessage; +TRequestStatus ServerStatus; + +class RTestSession : public RSessionBase + { +public: + TInt Connect(TInt aServerNumber) + { + return CreateSession(ServerName(aServerNumber),TVersion(),1,EIpcSession_Unsharable,0,&iStatus); + } + TInt Send(TInt aChunkNumber) + { + return RSessionBase::Send(0,TIpcArgs(SlaveNumber,aChunkNumber,&ChunkPtr[aChunkNumber])); + } + TRequestStatus iStatus; + }; +RTestSession Sessions[KNumSlaveProcesses]; + + +// +// +// + +void SlaveInit() + { + RDebug::Printf("Slave %d initialising",SlaveNumber); + + TBuf name; + name.Format(_L("T_MMUSTRESS-Slave%d"),SlaveNumber); + User::RenameThread(name); + + test_KErrNone(StartSemaphore.Open(2)); + TInt r; +#if !defined(__WINS__) && !defined(__X86__) + // Move ldd may not be in the ROM so needs to be loaded. + r=User::LoadLogicalDevice(KMoveLddFileName); + test_Value(r, r==KErrNone || r==KErrAlreadyExists); + test_KErrNone(MoveLdd.Open()); +#endif + + test_KErrNone(Ldd.Open()); + test_KErrNone(Ldd.CreateVirtualPinObject()); + + LocalIpcBuffer = (TUint8*)User::Alloc(KLocalIpcBufferSize); + test(LocalIpcBuffer!=0); + + test_KErrNone(Server.CreateGlobal(ServerName(SlaveNumber))); + + TUint i; + + // create sessions with other slaves... + for(i=0; i%d",SlaveNumber,chunkNumber,randomSlave); +// ChunkPtr[chunkNumber].Set(chunk.Base(),ChunkSize(chunkNumber),ChunkSize(chunkNumber)); + ChunkPtr[chunkNumber].Set(chunk.Base()+offset,size,size); + Sessions[randomSlave].Send(chunkNumber); + break; + + case 9: + // process IPC messages... + if(ServerStatus.Int()==KRequestPending) + continue; + User::WaitForRequest(ServerStatus); + + { + TInt sourceSlave = ServerMessage.Int0(); + chunkNumber = ServerMessage.Int1(); + if(TRACE) RDebug::Printf("%d %d IPC Receive<-%d",SlaveNumber,chunkNumber,sourceSlave); + test_Equal(0,ServerMessage.Function()); + + // get local descriptor for owned region in chunk... + size = ServerMessage.GetDesMaxLength(2); + test_NotNegative(size); + if(size>KLocalIpcBufferSize) + size = KLocalIpcBufferSize; + TPtr8 local(LocalIpcBuffer,size,size); + +// if(Random(2)) + { + // IPC read from other slave... + if(TRACE) RDebug::Printf("%d %d IPC Read<-%d",SlaveNumber,chunkNumber,sourceSlave); + TInt panicTrace = Ldd.SetPanicTrace(EFalse); + r = ServerMessage.Read(2,local); + Ldd.SetPanicTrace(panicTrace); + if(r!=KErrBadDescriptor) + test_KErrNone(r); + } +// else +// { +// // IPC write to other slave... +// if(TRACE) RDebug::Printf("%d %d IPC Write->%d",SlaveNumber,chunkNumber,sourceSlave); +// r = ServerMessage.Write(2,local,offset); +// if(r!=KErrBadDescriptor) +// test_KErrNone(r); +// if(Committed[chunkNumber]==1) +// ChunkMarkRegion(chunkNumber,offset,size); +// } + } + + ServerMessage.Complete(KErrNone); + Server.Receive(ServerMessage,ServerStatus); + break; + + case 10: + case 11: + // pin memory... + { + test_KErrNone(Ldd.UnpinVirtualMemory()); + for(TInt tries=10; tries>0; --tries) + { + TInt chunkSize = ChunkSize(chunkNumber); + offset = Random(chunkSize); + TInt maxSize = chunkSize-offset; + if(maxSize>0x1000) + maxSize = 0x1000; + size = Random(maxSize); + r = Ldd.PinVirtualMemory((TLinAddr)chunk.Base()+offset, size); + if(r!=KErrNotFound && r!=KErrNoMemory) + { + test_KErrNone(r); + break; + } + } + } + break; + case 12: + case 13: + // Move any page in the chunk, not just the owned region. + { +#if !defined(__WINS__) && !defined(__X86__) + for(TInt tries=10; tries>0; --tries) + { + TInt chunkSize = ChunkSize(chunkNumber); + offset = Random(chunkSize); + MoveLdd.TryMovingUserPage((TAny*)(chunk.Base()+offset), ETrue); + // Allow the move to fail for any reason as the page of the chunk + // may or may not be currently committed, pinned, or accessed. + } +#endif + } + break; + default: + test(false); // can't happen + break; + } + } + } + + + +TInt E32Main() + { + // get system info... + MemModelAttributes = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL); + MemModel = MemModelAttributes&EMemModelTypeMask; + UserHal::PageSizeInBytes(PageSize); + PageMask = PageSize-1; + + // see if we are a slave process... + if(User::GetTIntParameter(1,SlaveNumber)==KErrNone) + { + // do testing... + SlaveInit(); + DoTest(); + return KErrGeneral; // shouldn't have returned from testing + } + + // master process... + TBool pass = true; // final test result + test.Title(); + if((MemModelAttributes&EMemModelAttrVA)==false) + { + test.Start(_L("TESTS NOT RUN - Not relevent for the memory model")); + test.End(); + return KErrNone; + } + + // get time to run tests for... + TInt timeout = 10; // time in seconds + TInt cmdLineLen = User::CommandLineLength(); + if(cmdLineLen) + { + // get timeout value from command line + RBuf cmdLine; + test_KErrNone(cmdLine.Create(cmdLineLen)); + User::CommandLine(cmdLine); + test_KErrNone(TLex(cmdLine).Val(timeout)); + if(timeout==0) + timeout = KMaxTInt; + } + TTimeIntervalMicroSeconds32 tickTime; + test_KErrNone(UserHal::TickPeriod(tickTime)); + TInt ticksPerSecond = 1000000/tickTime.Int(); + TInt timeoutTicks; + if(timeout>10); + test_KErrNone(Chunks[i].CreateDisconnectedGlobal(ChunkName(i),0,0,ChunkSize(i))); + } + + test.Next(_L("Spawning slave processes")); + test_KErrNone(StartSemaphore.CreateGlobal(KNullDesC,0)); + TFileName processFile(RProcess().FileName()); + for(i=0; i text; + text.Format(_L("Stressing for %d seconds..."),timeout); + test.Next(text); + timer.AfterTicks(timeoutStatus,timeoutTicks); + StartSemaphore.Signal(KNumSlaveProcesses); // release slaves to start testing + User::WaitForAnyRequest(); // wait for timeout or slave death via logon completion + + pass = timeoutStatus.Int()==KErrNone; // timeout means slaves are still running OK + + test.Next(_L("Check slaves still running")); + for(i=0; i