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