diff -r 96e5fb8b040d -r 36bfc973b146 kerneltest/e32test/smpsoak/t_smpsoakprocess.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/smpsoak/t_smpsoakprocess.cpp Thu Jan 07 13:38:45 2010 +0200 @@ -0,0 +1,596 @@ +// Copyright (c) 2002-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\smpsoak\t_smpsoakprocess.cpp + +// User Includes +#include "t_smpsoak.h" + +#define PRINT(args)\ + if (!TestSilent)\ + test.Printf args + +void ParseCmdLine(); + +//class for soak process and same executable(t_smpsoakprocess.exe) will be lauched with different process operation +//Example: IPC Read, IPC Write, File Process, Timer Process +class CSMPSoakProcess + { +public: + CSMPSoakProcess(); + ~CSMPSoakProcess(); + void CreateThread(TPtrC aThreadType); +private: + //Thread Functions + static TInt FileThread(TAny*); + static TInt TimerThread(TAny*); + static TInt MemoryThread(TAny*); +private: + // Thread member functions + TInt DoFileThread(); + TInt DoTimerThread(); + TInt DoMemoryThread(); + void DoCreateThread(TAny*); + void ResumeThread(); + //IPC's + void WriteProcess(); + void ReadProcess(); + //Thread Priority + void SetThreadPriority(); + //Utils for soak process + void SetSoakProcessPriority(); + void CommitChunk(RChunk& aChunk, TInt aSize); + void ReadChunk(RChunk& aChunk, TInt aSize); + void WriteToChunk(RChunk& aChunk, TInt aSize); + void DeleteChunk(RChunk& aChunk); +private: + //Thread tables + static TThread KOOMemoryTable[]; + static TThread KFileTable[]; + static TThread KTimerTable[]; +private: + TThreadData iThreadData; + RThread iThread; + TInt iPriority; + }; + +//Memory thread data +TThread CSMPSoakProcess::KOOMemoryTable[] = + { + { _L("SMPOOMemoryThread1"), CSMPSoakProcess::MemoryThread, {{EPriorityAbsoluteLowNormal, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, NULL,NULL}}, + { _L("SMPOOMemoryThread2"), CSMPSoakProcess::MemoryThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, NULL,NULL}}, + { _L("SMPOOMemoryThread3"), CSMPSoakProcess::MemoryThread, {{EPriorityMore, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, NULL,NULL}}, + { _L("SMPOOMemoryThread4"), CSMPSoakProcess::MemoryThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, NULL,NULL}}, + }; + +//File thread data +TThread CSMPSoakProcess::KFileTable[] = + { + { _L("SMPFileThread1"), CSMPSoakProcess::FileThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, 11, 5}}, + { _L("SMPFileThread2"), CSMPSoakProcess::FileThread, {{EPriorityNormal, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, 22, 10}}, + { _L("SMPFileThread3"), CSMPSoakProcess::FileThread, {{EPriorityMore, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, 33, 15}}, + { _L("SMPFileThread4"), CSMPSoakProcess::FileThread, {{EPriorityAbsoluteVeryLow, EPriorityMore, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 0, 4, NULL, 44, 20}}, + }; + +//Timer thread data +TThread CSMPSoakProcess::KTimerTable[] = + { + { _L("SMPTimerThread1"), CSMPSoakProcess::TimerThread, {{EPriorityAbsoluteLowNormal, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 1000, 2, NULL, NULL,NULL}}, + { _L("SMPTimerThread2"), CSMPSoakProcess::TimerThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 1500, 2, NULL, NULL,NULL}}, + }; +//Constructor +CSMPSoakProcess::CSMPSoakProcess() + { + } +//Destructor +CSMPSoakProcess::~CSMPSoakProcess() + { + } +//Set the process priority each time for each process +void CSMPSoakProcess::SetSoakProcessPriority() + { + RProcess proc; + TInt priority; + static TInt priorityindex = 0; + static const TProcessPriority priorityTable[]= + { + EPriorityLow, + EPriorityBackground, + EPriorityForeground, + EPriorityHigh + }; + if(++priorityindex >= 4) + priorityindex=0; + priority = priorityTable[priorityindex]; + proc.SetPriority((TProcessPriority)priority); + PRINT((_L("Process Priority:%d \n"),proc.Priority())); + } +//Changes the thread priority each time time, for each thread by Random, Increment, from List, Fixed. +//pick up the priority option from thread table +void CSMPSoakProcess::SetThreadPriority() + { + static TInt64 randSeed = KRandSeed; + static const TThreadPriority priorityTable[]= + { + EPriorityMuchLess, EPriorityLess, EPriorityNormal, EPriorityMore, EPriorityMuchMore, + EPriorityRealTime, EPriorityRealTime, EPriorityAbsoluteVeryLow, EPriorityAbsoluteLowNormal, + EPriorityAbsoluteLow, EPriorityAbsoluteBackgroundNormal, EPriorityAbsoluteBackground, + EPriorityAbsoluteForegroundNormal, EPriorityAbsoluteForeground, EPriorityAbsoluteHighNormal, EPriorityAbsoluteHigh + }; + TInt priorityIndex = 0; + switch (iThreadData.threadPriorityChange) + { + case EpriorityFixed: + break; + + case EPriorityList: + if (++iPriority >= KPriorityOrder) + iPriority = 0; + if (iThreadData.threadPriorities[iPriority] == 0) + iPriority = 0; + // PRINT(_L("SetPriority List CPU %d index %d priority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread),iPriority, iThreadData.threadPriorities[iPriority]); + iThread.SetPriority((TThreadPriority)iThreadData.threadPriorities[iPriority]); + break; + + case EPriorityIncrement: + while (priorityTable[priorityIndex] <= iPriority) + { + priorityIndex++; + } + iPriority = priorityTable[priorityIndex]; + if (iPriority > iThreadData.threadPriorities[2]) + iPriority = iThreadData.threadPriorities[1]; + // PRINT(_L("SetPriority Increment CPU %d priority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread), iPriority); + iThread.SetPriority((TThreadPriority)iPriority); + break; + + case EPriorityRandom: + iPriority = Math::Rand(randSeed) % (iThreadData.threadPriorities[2] - iThreadData.threadPriorities[1] + 1); + iPriority += iThreadData.threadPriorities[1]; + while (priorityTable[priorityIndex] < iPriority) + { + priorityIndex++; + } + iPriority = priorityTable[priorityIndex]; + // PRINT(_L("SetPriority Random CPU %d iPriority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread), iPriority); + iThread.SetPriority((TThreadPriority)iPriority); + break; + } + } +//Resume each thread +void CSMPSoakProcess::ResumeThread() + { + iThread.Resume(); + } +// CSMPSoakProcess Thread Creation. +// @param aThread thread table data +void CSMPSoakProcess::DoCreateThread(TAny* aThread) + { + //Initialize each thread data + iThreadData = ((TThread*)aThread)->threadData; + test.Next(_L("Create Thread")); + PRINT ((_L("%s CPU affinity %d Priority %d\n"),((TThread*)aThread)->threadName.Ptr(),iThreadData.cpuAffinity,iThreadData.threadPriorities[0])); + TInt r = iThread.Create(((TThread*)aThread)->threadName, ((TThread*)aThread)->threadFunction, KDefaultStackSize, KHeapMinSize, KHeapMaxSize,(TAny*)this); + test_KErrNone(r); + if (iThreadData.threadPriorityChange == EPriorityList) + { + iPriority = 0; + } + else + { + iPriority = iThreadData.threadPriorities[0]; + } + iThread.SetPriority((TThreadPriority)iThreadData.threadPriorities[0]); + //Set the thread CPU Affinity + gSMPStressDrv.ChangeThreadAffinity(&iThread, iThreadData.cpuAffinity); + } +//Commit the chunk with aSize +void CSMPSoakProcess::CommitChunk(RChunk& aChunk, TInt aSize) + { + //PRINT ((_L("Commit Chunk \n"))); + test_KErrNone(aChunk.Adjust(aSize)); + } +//Write some data into the chunk +void CSMPSoakProcess::WriteToChunk(RChunk& aChunk, TInt aSize) + { + TUint8 *writeaddr = aChunk.Base(); + TPtr8 write(writeaddr,aSize); + write.Fill('S',aSize); + write.Copy(memData); + } +//Read the data from chunk and verify +void CSMPSoakProcess::ReadChunk(RChunk& aChunk, TInt aSize) + { + TUint8 *readaddr = aChunk.Base(); + TPtr8 read(readaddr,aSize); + test_KErrNone(read.Compare(memData)); + } +//Cleaunup chunk +void CSMPSoakProcess::DeleteChunk(RChunk& aChunk) + { + test_KErrNone(aChunk.Adjust(0)); + } +//IPC Read operation +void CSMPSoakProcess::ReadProcess() + { + RTest test(_L("SMPSoakReadProcess")); + FOREVER + { + // SetSoakProcessPriority(); + gWriteSem.Wait(); //Wait for write completion + PRINT((_L("Read Chunk\n"))); + ReadChunk( gChunk,KChunkSize); + PRINT((_L("Delete Chunk\n"))); + DeleteChunk(gChunk); + gReadSem.Signal(); //Read completion + } + } +//IPC Write operation +void CSMPSoakProcess::WriteProcess() + { + RTest test(_L("SMPSoakWriteProcess")); + FOREVER + { + // SetSoakProcessPriority(); + CommitChunk( gChunk, KChunkSize); + PRINT((_L("Write To Chunk\n"))); + WriteToChunk( gChunk,KChunkSize); + gWriteSem.Signal(); //Write completion + gReadSem.Wait(); //Wait for read completion + } + } +//File Thread - creates Dir's, Files, Fileread, Filewrite and verify +//param aSoakThread - CSMPSoakUtil pointer +TInt CSMPSoakProcess::FileThread(TAny* aSoakThread) + { + CSMPSoakProcess* self = (CSMPSoakProcess*)aSoakThread; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakProcess::TimerThread Panic"),0)); + return self->DoFileThread(); + } +//Member Filethread + TInt CSMPSoakProcess::DoFileThread() + { + RTest test(_L("SMPFileThread")); + TInt r = KErrNone; + + TFileName sessionPath; + TBuf8 fileData; + fileData.Copy(KFileData); + RFs fs; + RFile file; + + TBuf filename; + TBuf directory; + TBuf tempdir; + + //Setup Dir structure + tempdir.Format(KDir,iThreadData.dirID); + test_KErrNone(fs.Connect()); + sessionPath=KSessionPath; + TChar driveLetter; + + //Setup Drive and Session + test_KErrNone(fs.DriveToChar(EDriveD,driveLetter)); + sessionPath[0]=(TText)driveLetter; + test_KErrNone(fs.SetSessionPath(sessionPath)); + test.Printf(_L("SessionPath=%S\n"),&sessionPath); + directory=sessionPath; + directory.Append(tempdir); + PRINT((_L("Dir Level =%S Creation\n"),&directory)); + + FOREVER + { + r= fs.MkDirAll(directory); + test(r == KErrNone || r == KErrAlreadyExists); + + //Create Number of files then write data into it. + for (TInt i = 0; i < iThreadData.numFile; i++) + { + filename.Format(KFile,iThreadData.dirID,i); + PRINT((_L("File = %S Write\n"),&filename)); + test_KErrNone(file.Create(fs,filename,EFileWrite)); + test_KErrNone(file.Write(fileData)); + file.Close(); + } + + //Read those files and verify it + for (TInt i = 0; i < iThreadData.numFile; i++) + { + TBuf8 readData; + filename.Format(KFile,iThreadData.dirID,i); + PRINT((_L("File = %S Read/Verify\n"),&filename)); + test_KErrNone(file.Open(fs,filename,EFileRead)); + test_KErrNone(file.Read(readData)); + test_KErrNone(readData.Compare(fileData)); + file.Close(); + } + + //Delete files + for (TInt i = 0; i < iThreadData.numFile; i++) + { + filename.Format(KFile,iThreadData.dirID,i); + PRINT((_L("File = %S Delete\n"),&filename)); + test_KErrNone(fs.Delete(filename)); + } + + //Remove Dir's + PRINT((_L("Dir Level =%S Removed\n"),&directory)); + test_KErrNone(fs.RmDir(directory)); + SetThreadPriority(); + if (gAbort) + break; + User::After(gPeriod); + } + fs.Close(); + return 0x00; + } +//Timer Thread - produces DFC's in the kernel side +//param aSoakThread - CSMPSoakUtil pointer + TInt CSMPSoakProcess::TimerThread(TAny* aSoakThread) + { + CSMPSoakProcess* self = (CSMPSoakProcess*)aSoakThread; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakProcess::TimerThread Panic"),0)); + return self->DoTimerThread(); + } +//Member TimerThread +TInt CSMPSoakProcess::DoTimerThread() + { + RTest test(_L("SMPSoakTimerThread")); + + RTimer timer; + test_KErrNone(timer.CreateLocal()); + TRequestStatus status; + + FOREVER + { + timer.After(status, iThreadData.delayTime*1000); + User::WaitForRequest(status); + test(status == KErrNone); + PRINT((_L("$"))); + SetThreadPriority(); + if (gAbort) + break; + User::After(gPeriod); + } + + timer.Close(); + return 0x00; + } + + //OOM Thread - produces out of memory condition on SMP threads run on different cpu cores + //param aSoakThread - this pointer + TInt CSMPSoakProcess::MemoryThread(TAny* aSoakThread) + { + CSMPSoakProcess* self = (CSMPSoakProcess*)aSoakThread; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakProcess::MemoryThread Panic"),0)); + return self->DoMemoryThread(); + } +//Memory thread member + TInt CSMPSoakProcess::DoMemoryThread() + { + RTest test(_L("SMPOOMemoryThread")); + + static TInt memOKCount =0; + TAny* oomheap = NULL; + TAny* prev = NULL; + + //Reserve the memory in heap + RHeap* heap; + heap = UserHeap::ChunkHeap(NULL, KHeapMinSize, KHeapMaxiSize); + + //Keep produce OOM condition and inform to other threads (run on different CPU cores) + FOREVER + { + TInt allocsize = KHeapMaxiSize - KHeapReserveSize; + + if(memOKCount == iThreadData.numThreads-1) + allocsize = KHeapMaxiSize; + + prev = oomheap; + oomheap = heap->Alloc(allocsize); + if(oomheap == NULL) + { + PRINT(_L("Out Of Memory\n")); + heap->Free(prev); + PRINT(_L("Recover Back Memory\n")); + memOKCount = 0; + ooMemSem.Signal(iThreadData.numThreads - 1); + } + else + { + ++memOKCount; + PRINT((_L("%d:Here MemOK\n"),memOKCount)); + ooMemSem.Wait(); + } + //Change Thread Priority + SetThreadPriority(); + if (gAbort) + break; + User::After(gPeriod); + } + if(heap != NULL) + heap->Close(); + return 0x00; + } +//Create thread + void CSMPSoakProcess::CreateThread(TPtrC aThreadType) + { + if (aThreadType == _L("-W")) + { + CSMPSoakProcess smpipcwrite; + smpipcwrite.WriteProcess(); + } + else if (aThreadType == _L("-R")) + { + CSMPSoakProcess smpipcread; + smpipcread.ReadProcess(); + } + else if (aThreadType == _L("-F")) + { + CSMPSoakProcess smpfilethread[KNumFileThreads]; + for (TInt i = 0; i < KNumFileThreads; i++) + smpfilethread[i].DoCreateThread(&KFileTable[i]); + for (TInt i = 0; i < KNumFileThreads; i++) + smpfilethread[i].ResumeThread(); + } + else if (aThreadType == _L("-T")) + { + CSMPSoakProcess smptimerthread[KNumTimerThreads]; + for (TInt i = 0; i < KNumTimerThreads; i++) + smptimerthread[i].DoCreateThread(&KTimerTable[i]); + for (TInt i = 0; i < KNumTimerThreads; i++) + smptimerthread[i].ResumeThread(); + } + else if (aThreadType == _L("-O")) + { + CSMPSoakProcess smpoomthread[KNumOOMThreads]; + for (TInt i = 0; i < KNumOOMThreads; i++) + smpoomthread[i].DoCreateThread(&KOOMemoryTable[i]); + for (TInt i = 0; i < KNumOOMThreads; i++) + smpoomthread[i].ResumeThread(); + } + /* else + { + test.Printf(_L("Invalid Argument for Soak Process \n")); + test(EFalse); + }*/ + } +//Command line arg to launch operation specific process +void ParseCmdLine() + { + TBuf<256> cmd; + User::CommandLine(cmd); + TLex lex(cmd); + PRINT ((_L("Command for Process = %s\n"), cmd.PtrZ())); + CSMPSoakProcess smpp; + FOREVER + { + TPtrC token=lex.NextToken(); + if(token.Length()!=0) + { + if (token.Length()==0) + break; // ignore trailing whitespace + else if (token.Mid(0) == _L("-b")) + { + test.Printf(_L("SMPSOAKPROCESS: Silent Mode\n")); + TestSilent = ETrue; + lex.SkipSpaceAndMark(); + token.Set(lex.NextToken()); + test.Printf(_L("-b Thread Type = %s\n"), token.Ptr()); + smpp.CreateThread(token); + break; + } + else if (token.Left(2) == _L("-p")) + { + test.Printf(_L("SMPSOAKPROCESS: period\n")); + lex.SkipSpaceAndMark(); + token.Set(lex.NextToken()); + TLex lexNum(token); + lexNum.Val(gPeriod,EDecimal); + test.Printf(_L("SMPSOAKPROCESS:period in mSeconds=%d \n"),gPeriod); + token.Set(lex.NextToken()); + test.Printf(_L("-p Thread Type = %s\n"), token.Ptr()); + smpp.CreateThread(token); + break; + } + else + { + test.Printf(_L("-d Thread Type = %s\n"), token.Ptr()); + smpp.CreateThread(token); + break; + } + } + break; + } + } +// Child process called by (T_SMPSOAK) Main Process +TInt E32Main() + { + test.Title(); + __UHEAP_MARK; + test.Start(_L("t_SMPSoakProcess.exe")); + test.Next(_L("Load device driver")); + TInt r = User::LoadLogicalDevice(_L("d_smpsoak.ldd")); + if (r == KErrNotFound) + { + PRINT (_L("Test not supported on this platform because the D_SMPSOAK.LDD Driver is Not Present\n")); + test(EFalse); + } + + PRINT (_L("Calling SMPStressDrv.Open\n")); + r = gSMPStressDrv.Open(); + test_KErrNone(r); + + PRINT (_L("Create/Open Global Write Semaphores\n")); + r = gWriteSem.CreateGlobal(KGlobalWriteSem,0); + if (r==KErrAlreadyExists) + { + r = gWriteSem.OpenGlobal(KGlobalWriteSem); + } + if (r!=KErrNone) + { + PRINT ((_L("Error- OpenGlobal Write Semaphore:%d\n"),r)); + test(EFalse); + } + + PRINT (_L("Create/Open Global Read Semaphores\n")); + r = gReadSem.CreateGlobal(KGlobalReadSem,0); + if (r==KErrAlreadyExists) + { + r = gReadSem.OpenGlobal(KGlobalReadSem); + } + if (r!=KErrNone) + { + PRINT( (_L("Error- OpenGlobal Read Semaphore:%d\n"),r)); + test(EFalse); + } + + PRINT (_L("Creating Global Chunk\n")); + r = gChunk.CreateGlobal(KGlobalWRChunk,KChunkSize,KChunkMaxSize); + if(r==KErrAlreadyExists) + { + test_KErrNone( gChunk.OpenGlobal(KGlobalWRChunk,EFalse)); + } + + PRINT (_L("Creating local OOM Memory semaphore\n")); + r=ooMemSem.CreateLocal(0); + if (r!=KErrNone) + { + PRINT ((_L("Error- Creating local OOM Memory semaphore:%d\n"),r)); + test(EFalse); + } + + ParseCmdLine(); + + CActiveScheduler* myScheduler = new (ELeave) CActiveScheduler(); + test(myScheduler != NULL); + CActiveScheduler::Install(myScheduler); + CActiveScheduler::Start(); + + ooMemSem.Close(); + gWriteSem.Close(); + gReadSem.Close(); + gChunk.Close(); + gSMPStressDrv.Close(); + CActiveScheduler::Stop(); + __UHEAP_MARKEND; + test.End(); + return 0x00; + } + + + + + + +