os/kernelhwsrv/kerneltest/e32test/smp_demo/smp_demo.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\smp_demo\smp_demo.cpp
    15 // Demonstration for SMP
    16 // 
    17 //
    18 
    19 #include <e32test.h>
    20 #include <u32hal.h>
    21 #include <e32svr.h>
    22 #include <f32file.h>
    23 #include <hal.h>
    24 #include <e32math.h>
    25 
    26 RTest test(_L("SMP_DEMO"));
    27 
    28 #define DEBUG_PRINT(__args)		test.Printf __args ;
    29 
    30 TBool   TestThreadsExit = EFalse;
    31 _LIT(KTestBlank, "");
    32 
    33 
    34 //#define LOCK_TYPE	RMutex
    35 //#define LOCK_TYPE_CREATE_PARAM	
    36 #define LOCK_TYPE	RFastLock
    37 #define LOCK_TYPE_CREATE_PARAM	
    38 //#define LOCK_TYPE	RSemaphore
    39 //#define LOCK_TYPE_CREATE_PARAM	0
    40 
    41 #define MAX_THREADS		8		
    42 #define MAX_CHAPTERS	28
    43 
    44 TUint8		TestGuess[MAX_THREADS];
    45 TInt		TestGuessReady[MAX_THREADS];
    46 LOCK_TYPE	TestGuessLock[MAX_THREADS];
    47 
    48 TInt		TestGuessChanged[MAX_THREADS];
    49 LOCK_TYPE	TestChangedLock[MAX_THREADS];
    50 TUint8		TestNext[MAX_THREADS];
    51 
    52 TUint		TestGuessMisses[MAX_THREADS];
    53 TUint		TestGuessCorrect[MAX_THREADS];
    54 TUint		TestGuessIncorrect[MAX_THREADS];
    55 TUint		TestGuessCollision[MAX_THREADS];
    56 TInt		TestCpuCount = 0;
    57 
    58 TBool		TestUseMathRandom = ETrue;
    59 TBool		TestSingleCpu = EFalse;
    60 TBool		TestDualCpu = EFalse;
    61 TBool		TestNoPrint = EFalse;
    62 TBool		TestSingleThread = EFalse;
    63 TBool		TestUseAffinity = ETrue;
    64 
    65 TInt LoadChapter(TInt chapterIndex, HBufC8 **aChapterPtrPtr)
    66 	{
    67 	RFile file;
    68 	RFs fs;
    69 	if (KErrNone != fs.Connect())
    70 		{
    71 		DEBUG_PRINT(_L("LoadChapter : Can't connect to the FS\n"));
    72 		return KErrGeneral;
    73 		}
    74 
    75 	TBuf<32>	filename;
    76 	filename.Format(_L("z:\\Test\\war_and_peace_ch%d.txt"), chapterIndex);
    77 
    78 	TInt ret = file.Open(fs,filename,EFileRead);
    79 	if (ret == KErrNone)
    80 		{
    81 		TInt fileSize = 0;
    82 		ret = file.Size(fileSize);
    83 		if (ret == KErrNone)
    84 			{
    85 			HBufC8 *theBuf = HBufC8::New(fileSize + 10);
    86 			if (theBuf != NULL)
    87 				{
    88 				TPtr8 des2=theBuf->Des();
    89 				ret = file.Read((TInt)0, des2,fileSize);
    90 				if (ret == KErrNone)
    91 					{
    92 					*aChapterPtrPtr = theBuf;
    93 					}
    94 				else
    95 					{
    96 					DEBUG_PRINT((_L("LoadChapter : Read Failed for %S of %d\n"), &filename, fileSize));
    97 					}
    98 				}
    99 			else
   100 				{
   101 				DEBUG_PRINT((_L("LoadChapter : Buffer Alloc Failed for %S\n"), &filename));
   102 				}
   103 			}
   104 		else
   105 			{
   106 			DEBUG_PRINT((_L("LoadChapter : Size Failed for %S\n"), &filename));
   107 			}
   108 		file.Close();
   109 		}
   110 	else
   111 		{
   112 		DEBUG_PRINT((_L("LoadChapter : Open Failed for %S\n"), &filename));
   113 		}
   114 	
   115 	return ret;
   116 	}	
   117 
   118 TInt SetCpuAffinity(TInt aThreadId)
   119 	{
   120 	if (TestUseAffinity)
   121 		{
   122 		TUint32 cpu;
   123 
   124 		if (TestCpuCount == 4)
   125 			cpu = (TUint32)(aThreadId % 3) + 1;
   126 		else if (TestCpuCount == 2)
   127 			cpu = (TUint32)1;
   128 		else
   129 			cpu = 0;
   130 
   131 		TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0);
   132 		test(r==KErrNone);	
   133 		return r;
   134 		}
   135 	return KErrNone;
   136 	}
   137 
   138 
   139 LOCAL_C TInt DemoThread(TAny* aUseTb)
   140 	{
   141 	TInt	threadId = (TInt)aUseTb;
   142 	
   143 	SetCpuAffinity(threadId);
   144 	User::After(100);
   145 
   146 	TestGuessChanged[threadId] = EFalse;
   147 	TestGuessReady[threadId] = EFalse;
   148 	TestGuessMisses[threadId] = 0;
   149 	TestGuessCorrect[threadId] = 0;
   150 	TestGuessIncorrect[threadId] = 0;
   151 	TestGuessCollision[threadId] = 0;
   152 
   153 	TUint8	guess = 0;
   154 	TUint8	nextChar = TestNext[threadId];
   155 	TBool	correct = EFalse;
   156 
   157 	while (!TestThreadsExit)
   158 		{
   159 		correct = EFalse;
   160 
   161 		if (TestUseMathRandom)
   162 			guess = (TUint8)Math::Random();
   163 		else
   164 			guess ++;
   165 
   166 		if (TestGuessChanged[threadId])
   167 			{
   168 			TestChangedLock[threadId].Wait();
   169 			nextChar = TestNext[threadId];
   170 			TestGuessChanged[threadId] = EFalse;
   171 			TestChangedLock[threadId].Signal();			
   172 			}
   173 		correct = (nextChar == guess);
   174 
   175 		if (correct)
   176 			{
   177 			if (TestGuessReady[threadId] == EFalse)
   178 				{
   179 				TestGuessLock[threadId].Wait();
   180 				TestGuess[threadId] = guess;
   181 				TestGuessReady[threadId] = ETrue;
   182 				TestGuessLock[threadId].Signal();
   183 				TestGuessCorrect[threadId] ++;
   184 				}
   185 			else
   186 				{
   187 				TestGuessMisses[threadId] ++;
   188 				}
   189 			}
   190 		else
   191 			{
   192 			TestGuessIncorrect[threadId] ++;
   193 			}
   194 		if (TestCpuCount == 1)
   195 			{
   196 			User::After(0);
   197 			}
   198 		}
   199 	return KErrNone;
   200 	}
   201 
   202 TInt NumberOfCpus()
   203 	{
   204 	TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
   205 	test(r>0);
   206 	return r;
   207 	}
   208 
   209 TInt ParseArgs(void)
   210 	{
   211 	TBuf<256> args;
   212 	User::CommandLine(args);
   213 	TLex	lex(args);
   214 
   215 	FOREVER
   216 		{
   217 		TPtrC  token=lex.NextToken();
   218 		if(token.Length()!=0)
   219 			{
   220 			if (token == _L("unbound"))
   221 				{
   222 				TestUseMathRandom = EFalse;
   223 				}
   224 			if (token == _L("single"))
   225 				{
   226 				TestSingleCpu = ETrue;
   227 				}
   228 			if (token == _L("dual"))
   229 				{
   230 				TestDualCpu = ETrue;
   231 				}
   232 			if (token == _L("silent"))
   233 				{
   234 				TestNoPrint = ETrue;
   235 				}
   236 			if (token == _L("onethread"))
   237 				{
   238 				TestSingleCpu = ETrue;
   239 				TestSingleThread = ETrue;
   240 				}
   241 			if (token == _L("help"))
   242 				{
   243 				test.Printf(_L("smp_demo: unbound | single | onethread | silent | dual | noaffinity | help \n"));
   244 				return -1;
   245 				}
   246 			if (token == _L("noaffinity"))
   247 				{
   248 				TestUseAffinity = EFalse;
   249 				}
   250 			}
   251 		else
   252 			{
   253 			break;
   254 			}
   255 		}
   256 		return KErrNone;
   257 	}
   258 
   259 TInt E32Main()
   260 	{
   261 	test.Title();
   262 	test.Start(_L("SMP Demonstration guessing War and Peace...."));
   263 	
   264 	if (ParseArgs() != KErrNone)
   265 		{
   266 		test.Getch();
   267 		test.End();
   268 		return KErrNone;
   269 		}
   270 
   271 	TUint   start = User::TickCount();
   272 	TInt	tickPeriod = 0;
   273 	HAL::Get(HAL::ESystemTickPeriod, tickPeriod);
   274 
   275 	if (TestSingleCpu)
   276 		{
   277 		TestCpuCount = 1;
   278 		}
   279 	else if (TestDualCpu)
   280 		{
   281 		TestCpuCount = 2;
   282 		}
   283 	else
   284 		{
   285 		TestCpuCount = NumberOfCpus();
   286 		}
   287 	
   288 	DEBUG_PRINT((_L("CPU Count %d\n"), TestCpuCount));
   289 
   290 	TRequestStatus	theStatus[MAX_THREADS];
   291 	RThread			theThreads[MAX_THREADS];
   292 	TBool			threadInUse[MAX_THREADS];
   293 
   294 	TInt	index;
   295 	TInt	maxChapters = MAX_CHAPTERS;
   296 
   297 	if (TestUseMathRandom)
   298 		{
   299 		maxChapters = 2;
   300 		}
   301 
   302 	TInt	maxIndex = TestCpuCount - 1;
   303 	if (maxIndex == 0)
   304 		{
   305 		maxChapters = 2;
   306 		maxIndex = 1;
   307 		}
   308 	else if ((maxIndex == 1) && (TestUseMathRandom))
   309 		{
   310 		maxChapters = 4;
   311 		}
   312 
   313 	TInt	ret;
   314 	TUint32 cpu = 0;
   315 
   316 	if (TestUseAffinity)
   317 		{
   318 		UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0);
   319 		}
   320 
   321 	if (TestSingleThread)
   322 		{
   323 		TInt	chapterIndex;
   324 		TUint8	guess = 0;
   325 		
   326 		maxChapters = MAX_CHAPTERS;
   327 
   328 		TRequestStatus keyStatus;
   329 		CConsoleBase*  console=test.Console();
   330 		
   331 		console->Read(keyStatus);
   332 
   333 		for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++)
   334 			{
   335 			HBufC8 *chapterPtr = NULL;
   336 			ret = LoadChapter(chapterIndex + 1, &chapterPtr);
   337 			if ((ret != KErrNone) || (chapterPtr == NULL))
   338 				{
   339 				DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret));
   340 				}
   341 			else
   342 				{
   343 				TPtr8			theDes = chapterPtr->Des();
   344 				TUint8		   *pData = (TUint8 *)theDes.Ptr();
   345 				TInt			dataLength = chapterPtr->Length();
   346 
   347 
   348 				while (dataLength > 0)
   349 					{
   350 					if (TestUseMathRandom)
   351 						guess = (TUint8)Math::Random();
   352 					else
   353 						guess ++;
   354 
   355  					if (*pData == guess)
   356 						{
   357 						pData ++;
   358 						dataLength --;
   359 						if (!TestNoPrint)
   360 							{
   361 							test.Printf(_L("%c"), (TUint8)guess);
   362 							}
   363 						}
   364 					if (keyStatus != KRequestPending)
   365 						{
   366 						if (console->KeyCode() == EKeyEscape)
   367 							{
   368 							TestThreadsExit = ETrue;
   369 							break;
   370 							}
   371 						console->Read(keyStatus);
   372 						}
   373 					}
   374 				// clean up
   375 				delete chapterPtr;
   376 				test.Printf(_L("\n\n"));
   377 				if (TestThreadsExit)
   378 					{
   379 					break;
   380 					}
   381 				}
   382 			}
   383 		console->ReadCancel();
   384 		test.Printf(_L("Finished after %d chapters!\n"),chapterIndex);
   385 		}
   386 	else
   387 		{
   388 		for (index = 0; index < maxIndex; index ++)
   389 			{
   390 			TestGuessLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM);
   391 			TestChangedLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM);
   392 			ret = theThreads[index].Create(KTestBlank,DemoThread,KDefaultStackSize,NULL,(TAny*) index);
   393 			if (ret == KErrNone)
   394 				{
   395 				theThreads[index].Logon(theStatus[index]);
   396 				if (theStatus[index] != KRequestPending)
   397 					{
   398 					DEBUG_PRINT((_L("E32Main: !KRequestPending %d\n"), theStatus[index].Int() ));
   399 					}	
   400 				theThreads[index].Resume();
   401 				threadInUse[index] = ETrue;
   402 				DEBUG_PRINT((_L("E32Main: starting thread %d %d\n"), index, index % TestCpuCount));
   403 				}
   404 			else
   405 				{
   406 				DEBUG_PRINT((_L("E32Main: Create thread failed %d\n"), ret));
   407 				return KErrGeneral;
   408 				}
   409 			}
   410 
   411 		TInt	chapterIndex;
   412 		TInt    index2;
   413 
   414 		TRequestStatus keyStatus;
   415 		CConsoleBase*  console=test.Console();
   416 		
   417 		console->Read(keyStatus);
   418 
   419 		for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++)
   420 			{
   421 			HBufC8 *chapterPtr = NULL;
   422 			ret = LoadChapter(chapterIndex + 1, &chapterPtr);
   423 			if ((ret != KErrNone) || (chapterPtr == NULL))
   424 				{
   425 				DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret));
   426 				}
   427 			else
   428 				{
   429 				TPtr8			theDes = chapterPtr->Des();
   430 				TUint8		   *pData = (TUint8 *)theDes.Ptr();
   431 				TInt			dataLength = chapterPtr->Length();
   432 				for (index2 = 0; index2 < maxIndex; index2 ++)
   433 					{
   434 					TestChangedLock[index2].Wait();
   435 					TestGuessChanged[index2] = ETrue;
   436 					TestNext[index2] = (TUint8)*pData;
   437 					TestChangedLock[index2].Signal();
   438 					}
   439 				// where the real code goes!!
   440 				TUint8	guess = 0;
   441 				TBool	wasReady = EFalse;
   442 				while (dataLength > 0)
   443 					{
   444 					for (index = 0; index < maxIndex; index ++)
   445 						{
   446 						wasReady = EFalse;
   447 						if (TestGuessReady[index])
   448 							{
   449 							wasReady = ETrue;
   450 							TestGuessLock[index].Wait();
   451 							guess = (TUint8)TestGuess[index];
   452 							TestGuessReady[index] = EFalse;
   453 							TestGuessLock[index].Signal();
   454 							}
   455 						if (wasReady)
   456 							{
   457 							if (*pData == guess)
   458 								{
   459 								pData ++;
   460 								dataLength --;
   461 								for (index2 = 0; index2 < maxIndex; index2 ++)
   462 									{
   463 									TestChangedLock[index2].Wait();
   464 									TestNext[index2] = (TUint8)*pData;
   465 									TestGuessChanged[index2] = ETrue;
   466 									TestChangedLock[index2].Signal();
   467 									}
   468 								if (!TestNoPrint)
   469 									{
   470 									test.Printf(_L("%c"), (TUint8)guess);
   471 									}
   472 								}
   473 							else
   474 								{
   475 								TestGuessCollision[index] ++;
   476 								}
   477 							}
   478 						if (TestCpuCount == 1)
   479 							{
   480 							User::After(0);
   481 							}
   482 						}
   483 					if (keyStatus != KRequestPending)
   484 						{
   485 						if (console->KeyCode() == EKeyEscape)
   486 							{
   487 							TestThreadsExit = ETrue;
   488 							break;
   489 							}
   490 						console->Read(keyStatus);
   491 						}
   492 					}
   493 				// clean up
   494 				delete chapterPtr;
   495 				test.Printf(_L("\n\n"));
   496 				if (TestThreadsExit)
   497 					{
   498 					break;
   499 					}
   500 				}
   501 			}
   502 
   503 		console->ReadCancel();
   504 		
   505 		test.Printf(_L("Finished after %d chapters!\n"),chapterIndex);
   506 		for (index = 0; index < maxIndex; index ++)
   507 			{
   508 			test.Printf(_L("Thread %d stalls %u correct %u incorrect %u collision %u\n"), index, TestGuessMisses[index],TestGuessCorrect[index],TestGuessIncorrect[index], TestGuessCollision[index]);
   509 			}
   510 			
   511 		// real code ends!!
   512 		TestThreadsExit = ETrue;
   513 		
   514 		TBool		anyUsed = ETrue;
   515 
   516 		while(anyUsed)
   517 			{
   518 			anyUsed = EFalse;
   519 
   520 			for (index = 0; index < maxIndex; index++)
   521 				{
   522 				if (threadInUse[index])
   523 					{
   524 					if (theThreads[index].ExitType() != EExitPending)
   525 						{
   526 						threadInUse[index] = EFalse;
   527 						TestGuessLock[index].Close();
   528 						TestChangedLock[index].Close();
   529 						}
   530 					else
   531 						{
   532 						anyUsed = ETrue;
   533 						}
   534 					}
   535 				}
   536 			}
   537 		}		
   538 	TUint time = TUint((TUint64)(User::TickCount()-start)*(TUint64)tickPeriod/(TUint64)1000000);
   539 	test.Printf(_L("Complete in %u seconds\n"), time);	
   540 	test.Getch();
   541 	test.End();
   542 	return KErrNone;
   543 	}
   544