diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kerneltest/e32test/smp_demo/smp_demo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kerneltest/e32test/smp_demo/smp_demo.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,544 @@ +// 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: +// e32test\smp_demo\smp_demo.cpp +// Demonstration for SMP +// +// + +#include +#include +#include +#include +#include +#include + +RTest test(_L("SMP_DEMO")); + +#define DEBUG_PRINT(__args) test.Printf __args ; + +TBool TestThreadsExit = EFalse; +_LIT(KTestBlank, ""); + + +//#define LOCK_TYPE RMutex +//#define LOCK_TYPE_CREATE_PARAM +#define LOCK_TYPE RFastLock +#define LOCK_TYPE_CREATE_PARAM +//#define LOCK_TYPE RSemaphore +//#define LOCK_TYPE_CREATE_PARAM 0 + +#define MAX_THREADS 8 +#define MAX_CHAPTERS 28 + +TUint8 TestGuess[MAX_THREADS]; +TInt TestGuessReady[MAX_THREADS]; +LOCK_TYPE TestGuessLock[MAX_THREADS]; + +TInt TestGuessChanged[MAX_THREADS]; +LOCK_TYPE TestChangedLock[MAX_THREADS]; +TUint8 TestNext[MAX_THREADS]; + +TUint TestGuessMisses[MAX_THREADS]; +TUint TestGuessCorrect[MAX_THREADS]; +TUint TestGuessIncorrect[MAX_THREADS]; +TUint TestGuessCollision[MAX_THREADS]; +TInt TestCpuCount = 0; + +TBool TestUseMathRandom = ETrue; +TBool TestSingleCpu = EFalse; +TBool TestDualCpu = EFalse; +TBool TestNoPrint = EFalse; +TBool TestSingleThread = EFalse; +TBool TestUseAffinity = ETrue; + +TInt LoadChapter(TInt chapterIndex, HBufC8 **aChapterPtrPtr) + { + RFile file; + RFs fs; + if (KErrNone != fs.Connect()) + { + DEBUG_PRINT(_L("LoadChapter : Can't connect to the FS\n")); + return KErrGeneral; + } + + TBuf<32> filename; + filename.Format(_L("z:\\Test\\war_and_peace_ch%d.txt"), chapterIndex); + + TInt ret = file.Open(fs,filename,EFileRead); + if (ret == KErrNone) + { + TInt fileSize = 0; + ret = file.Size(fileSize); + if (ret == KErrNone) + { + HBufC8 *theBuf = HBufC8::New(fileSize + 10); + if (theBuf != NULL) + { + TPtr8 des2=theBuf->Des(); + ret = file.Read((TInt)0, des2,fileSize); + if (ret == KErrNone) + { + *aChapterPtrPtr = theBuf; + } + else + { + DEBUG_PRINT((_L("LoadChapter : Read Failed for %S of %d\n"), &filename, fileSize)); + } + } + else + { + DEBUG_PRINT((_L("LoadChapter : Buffer Alloc Failed for %S\n"), &filename)); + } + } + else + { + DEBUG_PRINT((_L("LoadChapter : Size Failed for %S\n"), &filename)); + } + file.Close(); + } + else + { + DEBUG_PRINT((_L("LoadChapter : Open Failed for %S\n"), &filename)); + } + + return ret; + } + +TInt SetCpuAffinity(TInt aThreadId) + { + if (TestUseAffinity) + { + TUint32 cpu; + + if (TestCpuCount == 4) + cpu = (TUint32)(aThreadId % 3) + 1; + else if (TestCpuCount == 2) + cpu = (TUint32)1; + else + cpu = 0; + + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0); + test(r==KErrNone); + return r; + } + return KErrNone; + } + + +LOCAL_C TInt DemoThread(TAny* aUseTb) + { + TInt threadId = (TInt)aUseTb; + + SetCpuAffinity(threadId); + User::After(100); + + TestGuessChanged[threadId] = EFalse; + TestGuessReady[threadId] = EFalse; + TestGuessMisses[threadId] = 0; + TestGuessCorrect[threadId] = 0; + TestGuessIncorrect[threadId] = 0; + TestGuessCollision[threadId] = 0; + + TUint8 guess = 0; + TUint8 nextChar = TestNext[threadId]; + TBool correct = EFalse; + + while (!TestThreadsExit) + { + correct = EFalse; + + if (TestUseMathRandom) + guess = (TUint8)Math::Random(); + else + guess ++; + + if (TestGuessChanged[threadId]) + { + TestChangedLock[threadId].Wait(); + nextChar = TestNext[threadId]; + TestGuessChanged[threadId] = EFalse; + TestChangedLock[threadId].Signal(); + } + correct = (nextChar == guess); + + if (correct) + { + if (TestGuessReady[threadId] == EFalse) + { + TestGuessLock[threadId].Wait(); + TestGuess[threadId] = guess; + TestGuessReady[threadId] = ETrue; + TestGuessLock[threadId].Signal(); + TestGuessCorrect[threadId] ++; + } + else + { + TestGuessMisses[threadId] ++; + } + } + else + { + TestGuessIncorrect[threadId] ++; + } + if (TestCpuCount == 1) + { + User::After(0); + } + } + return KErrNone; + } + +TInt NumberOfCpus() + { + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + test(r>0); + return r; + } + +TInt ParseArgs(void) + { + TBuf<256> args; + User::CommandLine(args); + TLex lex(args); + + FOREVER + { + TPtrC token=lex.NextToken(); + if(token.Length()!=0) + { + if (token == _L("unbound")) + { + TestUseMathRandom = EFalse; + } + if (token == _L("single")) + { + TestSingleCpu = ETrue; + } + if (token == _L("dual")) + { + TestDualCpu = ETrue; + } + if (token == _L("silent")) + { + TestNoPrint = ETrue; + } + if (token == _L("onethread")) + { + TestSingleCpu = ETrue; + TestSingleThread = ETrue; + } + if (token == _L("help")) + { + test.Printf(_L("smp_demo: unbound | single | onethread | silent | dual | noaffinity | help \n")); + return -1; + } + if (token == _L("noaffinity")) + { + TestUseAffinity = EFalse; + } + } + else + { + break; + } + } + return KErrNone; + } + +TInt E32Main() + { + test.Title(); + test.Start(_L("SMP Demonstration guessing War and Peace....")); + + if (ParseArgs() != KErrNone) + { + test.Getch(); + test.End(); + return KErrNone; + } + + TUint start = User::TickCount(); + TInt tickPeriod = 0; + HAL::Get(HAL::ESystemTickPeriod, tickPeriod); + + if (TestSingleCpu) + { + TestCpuCount = 1; + } + else if (TestDualCpu) + { + TestCpuCount = 2; + } + else + { + TestCpuCount = NumberOfCpus(); + } + + DEBUG_PRINT((_L("CPU Count %d\n"), TestCpuCount)); + + TRequestStatus theStatus[MAX_THREADS]; + RThread theThreads[MAX_THREADS]; + TBool threadInUse[MAX_THREADS]; + + TInt index; + TInt maxChapters = MAX_CHAPTERS; + + if (TestUseMathRandom) + { + maxChapters = 2; + } + + TInt maxIndex = TestCpuCount - 1; + if (maxIndex == 0) + { + maxChapters = 2; + maxIndex = 1; + } + else if ((maxIndex == 1) && (TestUseMathRandom)) + { + maxChapters = 4; + } + + TInt ret; + TUint32 cpu = 0; + + if (TestUseAffinity) + { + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0); + } + + if (TestSingleThread) + { + TInt chapterIndex; + TUint8 guess = 0; + + maxChapters = MAX_CHAPTERS; + + TRequestStatus keyStatus; + CConsoleBase* console=test.Console(); + + console->Read(keyStatus); + + for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++) + { + HBufC8 *chapterPtr = NULL; + ret = LoadChapter(chapterIndex + 1, &chapterPtr); + if ((ret != KErrNone) || (chapterPtr == NULL)) + { + DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret)); + } + else + { + TPtr8 theDes = chapterPtr->Des(); + TUint8 *pData = (TUint8 *)theDes.Ptr(); + TInt dataLength = chapterPtr->Length(); + + + while (dataLength > 0) + { + if (TestUseMathRandom) + guess = (TUint8)Math::Random(); + else + guess ++; + + if (*pData == guess) + { + pData ++; + dataLength --; + if (!TestNoPrint) + { + test.Printf(_L("%c"), (TUint8)guess); + } + } + if (keyStatus != KRequestPending) + { + if (console->KeyCode() == EKeyEscape) + { + TestThreadsExit = ETrue; + break; + } + console->Read(keyStatus); + } + } + // clean up + delete chapterPtr; + test.Printf(_L("\n\n")); + if (TestThreadsExit) + { + break; + } + } + } + console->ReadCancel(); + test.Printf(_L("Finished after %d chapters!\n"),chapterIndex); + } + else + { + for (index = 0; index < maxIndex; index ++) + { + TestGuessLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM); + TestChangedLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM); + ret = theThreads[index].Create(KTestBlank,DemoThread,KDefaultStackSize,NULL,(TAny*) index); + if (ret == KErrNone) + { + theThreads[index].Logon(theStatus[index]); + if (theStatus[index] != KRequestPending) + { + DEBUG_PRINT((_L("E32Main: !KRequestPending %d\n"), theStatus[index].Int() )); + } + theThreads[index].Resume(); + threadInUse[index] = ETrue; + DEBUG_PRINT((_L("E32Main: starting thread %d %d\n"), index, index % TestCpuCount)); + } + else + { + DEBUG_PRINT((_L("E32Main: Create thread failed %d\n"), ret)); + return KErrGeneral; + } + } + + TInt chapterIndex; + TInt index2; + + TRequestStatus keyStatus; + CConsoleBase* console=test.Console(); + + console->Read(keyStatus); + + for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++) + { + HBufC8 *chapterPtr = NULL; + ret = LoadChapter(chapterIndex + 1, &chapterPtr); + if ((ret != KErrNone) || (chapterPtr == NULL)) + { + DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret)); + } + else + { + TPtr8 theDes = chapterPtr->Des(); + TUint8 *pData = (TUint8 *)theDes.Ptr(); + TInt dataLength = chapterPtr->Length(); + for (index2 = 0; index2 < maxIndex; index2 ++) + { + TestChangedLock[index2].Wait(); + TestGuessChanged[index2] = ETrue; + TestNext[index2] = (TUint8)*pData; + TestChangedLock[index2].Signal(); + } + // where the real code goes!! + TUint8 guess = 0; + TBool wasReady = EFalse; + while (dataLength > 0) + { + for (index = 0; index < maxIndex; index ++) + { + wasReady = EFalse; + if (TestGuessReady[index]) + { + wasReady = ETrue; + TestGuessLock[index].Wait(); + guess = (TUint8)TestGuess[index]; + TestGuessReady[index] = EFalse; + TestGuessLock[index].Signal(); + } + if (wasReady) + { + if (*pData == guess) + { + pData ++; + dataLength --; + for (index2 = 0; index2 < maxIndex; index2 ++) + { + TestChangedLock[index2].Wait(); + TestNext[index2] = (TUint8)*pData; + TestGuessChanged[index2] = ETrue; + TestChangedLock[index2].Signal(); + } + if (!TestNoPrint) + { + test.Printf(_L("%c"), (TUint8)guess); + } + } + else + { + TestGuessCollision[index] ++; + } + } + if (TestCpuCount == 1) + { + User::After(0); + } + } + if (keyStatus != KRequestPending) + { + if (console->KeyCode() == EKeyEscape) + { + TestThreadsExit = ETrue; + break; + } + console->Read(keyStatus); + } + } + // clean up + delete chapterPtr; + test.Printf(_L("\n\n")); + if (TestThreadsExit) + { + break; + } + } + } + + console->ReadCancel(); + + test.Printf(_L("Finished after %d chapters!\n"),chapterIndex); + for (index = 0; index < maxIndex; index ++) + { + test.Printf(_L("Thread %d stalls %u correct %u incorrect %u collision %u\n"), index, TestGuessMisses[index],TestGuessCorrect[index],TestGuessIncorrect[index], TestGuessCollision[index]); + } + + // real code ends!! + TestThreadsExit = ETrue; + + TBool anyUsed = ETrue; + + while(anyUsed) + { + anyUsed = EFalse; + + for (index = 0; index < maxIndex; index++) + { + if (threadInUse[index]) + { + if (theThreads[index].ExitType() != EExitPending) + { + threadInUse[index] = EFalse; + TestGuessLock[index].Close(); + TestChangedLock[index].Close(); + } + else + { + anyUsed = ETrue; + } + } + } + } + } + TUint time = TUint((TUint64)(User::TickCount()-start)*(TUint64)tickPeriod/(TUint64)1000000); + test.Printf(_L("Complete in %u seconds\n"), time); + test.Getch(); + test.End(); + return KErrNone; + } +