--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/smp_demo/smp_demo.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,543 @@
+// 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 <e32test.h>
+#include <u32hal.h>
+#include <f32file.h>
+#include <hal.h>
+#include <e32math.h>
+
+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;
+ }
+