sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\smp_demo\smp_demo.cpp sl@0: // Demonstration for SMP sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: RTest test(_L("SMP_DEMO")); sl@0: sl@0: #define DEBUG_PRINT(__args) test.Printf __args ; sl@0: sl@0: TBool TestThreadsExit = EFalse; sl@0: _LIT(KTestBlank, ""); sl@0: sl@0: sl@0: //#define LOCK_TYPE RMutex sl@0: //#define LOCK_TYPE_CREATE_PARAM sl@0: #define LOCK_TYPE RFastLock sl@0: #define LOCK_TYPE_CREATE_PARAM sl@0: //#define LOCK_TYPE RSemaphore sl@0: //#define LOCK_TYPE_CREATE_PARAM 0 sl@0: sl@0: #define MAX_THREADS 8 sl@0: #define MAX_CHAPTERS 28 sl@0: sl@0: TUint8 TestGuess[MAX_THREADS]; sl@0: TInt TestGuessReady[MAX_THREADS]; sl@0: LOCK_TYPE TestGuessLock[MAX_THREADS]; sl@0: sl@0: TInt TestGuessChanged[MAX_THREADS]; sl@0: LOCK_TYPE TestChangedLock[MAX_THREADS]; sl@0: TUint8 TestNext[MAX_THREADS]; sl@0: sl@0: TUint TestGuessMisses[MAX_THREADS]; sl@0: TUint TestGuessCorrect[MAX_THREADS]; sl@0: TUint TestGuessIncorrect[MAX_THREADS]; sl@0: TUint TestGuessCollision[MAX_THREADS]; sl@0: TInt TestCpuCount = 0; sl@0: sl@0: TBool TestUseMathRandom = ETrue; sl@0: TBool TestSingleCpu = EFalse; sl@0: TBool TestDualCpu = EFalse; sl@0: TBool TestNoPrint = EFalse; sl@0: TBool TestSingleThread = EFalse; sl@0: TBool TestUseAffinity = ETrue; sl@0: sl@0: TInt LoadChapter(TInt chapterIndex, HBufC8 **aChapterPtrPtr) sl@0: { sl@0: RFile file; sl@0: RFs fs; sl@0: if (KErrNone != fs.Connect()) sl@0: { sl@0: DEBUG_PRINT(_L("LoadChapter : Can't connect to the FS\n")); sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: TBuf<32> filename; sl@0: filename.Format(_L("z:\\Test\\war_and_peace_ch%d.txt"), chapterIndex); sl@0: sl@0: TInt ret = file.Open(fs,filename,EFileRead); sl@0: if (ret == KErrNone) sl@0: { sl@0: TInt fileSize = 0; sl@0: ret = file.Size(fileSize); sl@0: if (ret == KErrNone) sl@0: { sl@0: HBufC8 *theBuf = HBufC8::New(fileSize + 10); sl@0: if (theBuf != NULL) sl@0: { sl@0: TPtr8 des2=theBuf->Des(); sl@0: ret = file.Read((TInt)0, des2,fileSize); sl@0: if (ret == KErrNone) sl@0: { sl@0: *aChapterPtrPtr = theBuf; sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT((_L("LoadChapter : Read Failed for %S of %d\n"), &filename, fileSize)); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT((_L("LoadChapter : Buffer Alloc Failed for %S\n"), &filename)); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT((_L("LoadChapter : Size Failed for %S\n"), &filename)); sl@0: } sl@0: file.Close(); sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT((_L("LoadChapter : Open Failed for %S\n"), &filename)); sl@0: } sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: TInt SetCpuAffinity(TInt aThreadId) sl@0: { sl@0: if (TestUseAffinity) sl@0: { sl@0: TUint32 cpu; sl@0: sl@0: if (TestCpuCount == 4) sl@0: cpu = (TUint32)(aThreadId % 3) + 1; sl@0: else if (TestCpuCount == 2) sl@0: cpu = (TUint32)1; sl@0: else sl@0: cpu = 0; sl@0: sl@0: TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0); sl@0: test(r==KErrNone); sl@0: return r; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: LOCAL_C TInt DemoThread(TAny* aUseTb) sl@0: { sl@0: TInt threadId = (TInt)aUseTb; sl@0: sl@0: SetCpuAffinity(threadId); sl@0: User::After(100); sl@0: sl@0: TestGuessChanged[threadId] = EFalse; sl@0: TestGuessReady[threadId] = EFalse; sl@0: TestGuessMisses[threadId] = 0; sl@0: TestGuessCorrect[threadId] = 0; sl@0: TestGuessIncorrect[threadId] = 0; sl@0: TestGuessCollision[threadId] = 0; sl@0: sl@0: TUint8 guess = 0; sl@0: TUint8 nextChar = TestNext[threadId]; sl@0: TBool correct = EFalse; sl@0: sl@0: while (!TestThreadsExit) sl@0: { sl@0: correct = EFalse; sl@0: sl@0: if (TestUseMathRandom) sl@0: guess = (TUint8)Math::Random(); sl@0: else sl@0: guess ++; sl@0: sl@0: if (TestGuessChanged[threadId]) sl@0: { sl@0: TestChangedLock[threadId].Wait(); sl@0: nextChar = TestNext[threadId]; sl@0: TestGuessChanged[threadId] = EFalse; sl@0: TestChangedLock[threadId].Signal(); sl@0: } sl@0: correct = (nextChar == guess); sl@0: sl@0: if (correct) sl@0: { sl@0: if (TestGuessReady[threadId] == EFalse) sl@0: { sl@0: TestGuessLock[threadId].Wait(); sl@0: TestGuess[threadId] = guess; sl@0: TestGuessReady[threadId] = ETrue; sl@0: TestGuessLock[threadId].Signal(); sl@0: TestGuessCorrect[threadId] ++; sl@0: } sl@0: else sl@0: { sl@0: TestGuessMisses[threadId] ++; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TestGuessIncorrect[threadId] ++; sl@0: } sl@0: if (TestCpuCount == 1) sl@0: { sl@0: User::After(0); sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt NumberOfCpus() sl@0: { sl@0: TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); sl@0: test(r>0); sl@0: return r; sl@0: } sl@0: sl@0: TInt ParseArgs(void) sl@0: { sl@0: TBuf<256> args; sl@0: User::CommandLine(args); sl@0: TLex lex(args); sl@0: sl@0: FOREVER sl@0: { sl@0: TPtrC token=lex.NextToken(); sl@0: if(token.Length()!=0) sl@0: { sl@0: if (token == _L("unbound")) sl@0: { sl@0: TestUseMathRandom = EFalse; sl@0: } sl@0: if (token == _L("single")) sl@0: { sl@0: TestSingleCpu = ETrue; sl@0: } sl@0: if (token == _L("dual")) sl@0: { sl@0: TestDualCpu = ETrue; sl@0: } sl@0: if (token == _L("silent")) sl@0: { sl@0: TestNoPrint = ETrue; sl@0: } sl@0: if (token == _L("onethread")) sl@0: { sl@0: TestSingleCpu = ETrue; sl@0: TestSingleThread = ETrue; sl@0: } sl@0: if (token == _L("help")) sl@0: { sl@0: test.Printf(_L("smp_demo: unbound | single | onethread | silent | dual | noaffinity | help \n")); sl@0: return -1; sl@0: } sl@0: if (token == _L("noaffinity")) sl@0: { sl@0: TestUseAffinity = EFalse; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: test.Start(_L("SMP Demonstration guessing War and Peace....")); sl@0: sl@0: if (ParseArgs() != KErrNone) sl@0: { sl@0: test.Getch(); sl@0: test.End(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TUint start = User::TickCount(); sl@0: TInt tickPeriod = 0; sl@0: HAL::Get(HAL::ESystemTickPeriod, tickPeriod); sl@0: sl@0: if (TestSingleCpu) sl@0: { sl@0: TestCpuCount = 1; sl@0: } sl@0: else if (TestDualCpu) sl@0: { sl@0: TestCpuCount = 2; sl@0: } sl@0: else sl@0: { sl@0: TestCpuCount = NumberOfCpus(); sl@0: } sl@0: sl@0: DEBUG_PRINT((_L("CPU Count %d\n"), TestCpuCount)); sl@0: sl@0: TRequestStatus theStatus[MAX_THREADS]; sl@0: RThread theThreads[MAX_THREADS]; sl@0: TBool threadInUse[MAX_THREADS]; sl@0: sl@0: TInt index; sl@0: TInt maxChapters = MAX_CHAPTERS; sl@0: sl@0: if (TestUseMathRandom) sl@0: { sl@0: maxChapters = 2; sl@0: } sl@0: sl@0: TInt maxIndex = TestCpuCount - 1; sl@0: if (maxIndex == 0) sl@0: { sl@0: maxChapters = 2; sl@0: maxIndex = 1; sl@0: } sl@0: else if ((maxIndex == 1) && (TestUseMathRandom)) sl@0: { sl@0: maxChapters = 4; sl@0: } sl@0: sl@0: TInt ret; sl@0: TUint32 cpu = 0; sl@0: sl@0: if (TestUseAffinity) sl@0: { sl@0: UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0); sl@0: } sl@0: sl@0: if (TestSingleThread) sl@0: { sl@0: TInt chapterIndex; sl@0: TUint8 guess = 0; sl@0: sl@0: maxChapters = MAX_CHAPTERS; sl@0: sl@0: TRequestStatus keyStatus; sl@0: CConsoleBase* console=test.Console(); sl@0: sl@0: console->Read(keyStatus); sl@0: sl@0: for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++) sl@0: { sl@0: HBufC8 *chapterPtr = NULL; sl@0: ret = LoadChapter(chapterIndex + 1, &chapterPtr); sl@0: if ((ret != KErrNone) || (chapterPtr == NULL)) sl@0: { sl@0: DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret)); sl@0: } sl@0: else sl@0: { sl@0: TPtr8 theDes = chapterPtr->Des(); sl@0: TUint8 *pData = (TUint8 *)theDes.Ptr(); sl@0: TInt dataLength = chapterPtr->Length(); sl@0: sl@0: sl@0: while (dataLength > 0) sl@0: { sl@0: if (TestUseMathRandom) sl@0: guess = (TUint8)Math::Random(); sl@0: else sl@0: guess ++; sl@0: sl@0: if (*pData == guess) sl@0: { sl@0: pData ++; sl@0: dataLength --; sl@0: if (!TestNoPrint) sl@0: { sl@0: test.Printf(_L("%c"), (TUint8)guess); sl@0: } sl@0: } sl@0: if (keyStatus != KRequestPending) sl@0: { sl@0: if (console->KeyCode() == EKeyEscape) sl@0: { sl@0: TestThreadsExit = ETrue; sl@0: break; sl@0: } sl@0: console->Read(keyStatus); sl@0: } sl@0: } sl@0: // clean up sl@0: delete chapterPtr; sl@0: test.Printf(_L("\n\n")); sl@0: if (TestThreadsExit) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: console->ReadCancel(); sl@0: test.Printf(_L("Finished after %d chapters!\n"),chapterIndex); sl@0: } sl@0: else sl@0: { sl@0: for (index = 0; index < maxIndex; index ++) sl@0: { sl@0: TestGuessLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM); sl@0: TestChangedLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM); sl@0: ret = theThreads[index].Create(KTestBlank,DemoThread,KDefaultStackSize,NULL,(TAny*) index); sl@0: if (ret == KErrNone) sl@0: { sl@0: theThreads[index].Logon(theStatus[index]); sl@0: if (theStatus[index] != KRequestPending) sl@0: { sl@0: DEBUG_PRINT((_L("E32Main: !KRequestPending %d\n"), theStatus[index].Int() )); sl@0: } sl@0: theThreads[index].Resume(); sl@0: threadInUse[index] = ETrue; sl@0: DEBUG_PRINT((_L("E32Main: starting thread %d %d\n"), index, index % TestCpuCount)); sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT((_L("E32Main: Create thread failed %d\n"), ret)); sl@0: return KErrGeneral; sl@0: } sl@0: } sl@0: sl@0: TInt chapterIndex; sl@0: TInt index2; sl@0: sl@0: TRequestStatus keyStatus; sl@0: CConsoleBase* console=test.Console(); sl@0: sl@0: console->Read(keyStatus); sl@0: sl@0: for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++) sl@0: { sl@0: HBufC8 *chapterPtr = NULL; sl@0: ret = LoadChapter(chapterIndex + 1, &chapterPtr); sl@0: if ((ret != KErrNone) || (chapterPtr == NULL)) sl@0: { sl@0: DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret)); sl@0: } sl@0: else sl@0: { sl@0: TPtr8 theDes = chapterPtr->Des(); sl@0: TUint8 *pData = (TUint8 *)theDes.Ptr(); sl@0: TInt dataLength = chapterPtr->Length(); sl@0: for (index2 = 0; index2 < maxIndex; index2 ++) sl@0: { sl@0: TestChangedLock[index2].Wait(); sl@0: TestGuessChanged[index2] = ETrue; sl@0: TestNext[index2] = (TUint8)*pData; sl@0: TestChangedLock[index2].Signal(); sl@0: } sl@0: // where the real code goes!! sl@0: TUint8 guess = 0; sl@0: TBool wasReady = EFalse; sl@0: while (dataLength > 0) sl@0: { sl@0: for (index = 0; index < maxIndex; index ++) sl@0: { sl@0: wasReady = EFalse; sl@0: if (TestGuessReady[index]) sl@0: { sl@0: wasReady = ETrue; sl@0: TestGuessLock[index].Wait(); sl@0: guess = (TUint8)TestGuess[index]; sl@0: TestGuessReady[index] = EFalse; sl@0: TestGuessLock[index].Signal(); sl@0: } sl@0: if (wasReady) sl@0: { sl@0: if (*pData == guess) sl@0: { sl@0: pData ++; sl@0: dataLength --; sl@0: for (index2 = 0; index2 < maxIndex; index2 ++) sl@0: { sl@0: TestChangedLock[index2].Wait(); sl@0: TestNext[index2] = (TUint8)*pData; sl@0: TestGuessChanged[index2] = ETrue; sl@0: TestChangedLock[index2].Signal(); sl@0: } sl@0: if (!TestNoPrint) sl@0: { sl@0: test.Printf(_L("%c"), (TUint8)guess); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TestGuessCollision[index] ++; sl@0: } sl@0: } sl@0: if (TestCpuCount == 1) sl@0: { sl@0: User::After(0); sl@0: } sl@0: } sl@0: if (keyStatus != KRequestPending) sl@0: { sl@0: if (console->KeyCode() == EKeyEscape) sl@0: { sl@0: TestThreadsExit = ETrue; sl@0: break; sl@0: } sl@0: console->Read(keyStatus); sl@0: } sl@0: } sl@0: // clean up sl@0: delete chapterPtr; sl@0: test.Printf(_L("\n\n")); sl@0: if (TestThreadsExit) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: console->ReadCancel(); sl@0: sl@0: test.Printf(_L("Finished after %d chapters!\n"),chapterIndex); sl@0: for (index = 0; index < maxIndex; index ++) sl@0: { sl@0: test.Printf(_L("Thread %d stalls %u correct %u incorrect %u collision %u\n"), index, TestGuessMisses[index],TestGuessCorrect[index],TestGuessIncorrect[index], TestGuessCollision[index]); sl@0: } sl@0: sl@0: // real code ends!! sl@0: TestThreadsExit = ETrue; sl@0: sl@0: TBool anyUsed = ETrue; sl@0: sl@0: while(anyUsed) sl@0: { sl@0: anyUsed = EFalse; sl@0: sl@0: for (index = 0; index < maxIndex; index++) sl@0: { sl@0: if (threadInUse[index]) sl@0: { sl@0: if (theThreads[index].ExitType() != EExitPending) sl@0: { sl@0: threadInUse[index] = EFalse; sl@0: TestGuessLock[index].Close(); sl@0: TestChangedLock[index].Close(); sl@0: } sl@0: else sl@0: { sl@0: anyUsed = ETrue; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: } sl@0: TUint time = TUint((TUint64)(User::TickCount()-start)*(TUint64)tickPeriod/(TUint64)1000000); sl@0: test.Printf(_L("Complete in %u seconds\n"), time); sl@0: test.Getch(); sl@0: test.End(); sl@0: return KErrNone; sl@0: } sl@0: