37 |
38 |
38 volatile TBool gRunThrashTest = EFalse; |
39 volatile TBool gRunThrashTest = EFalse; |
39 |
40 |
40 _LIT(KChunkName, "t_thrash chunk"); |
41 _LIT(KChunkName, "t_thrash chunk"); |
41 |
42 |
42 class TRandom |
43 class TPRNG |
43 { |
44 { |
44 public: |
45 public: |
45 TRandom(); |
46 TPRNG(); |
46 TUint32 Next(); |
47 TUint32 IntRand(); |
|
48 TReal FloatRand(); |
47 |
49 |
48 private: |
50 private: |
49 enum |
51 enum |
50 { |
52 { |
51 KA = 1664525, |
53 KA = 1664525, |
52 KB = 1013904223 |
54 KB = 1013904223 |
53 }; |
55 }; |
54 TUint32 iV; |
56 TUint32 iV; |
55 }; |
57 }; |
56 |
58 |
57 TRandom::TRandom() |
59 TPRNG::TPRNG() |
58 { |
60 { |
59 iV = (TUint32)this + RThread().Id() + User::FastCounter() + 23; |
61 iV = (TUint32)this + RThread().Id() + User::FastCounter() + 23; |
60 } |
62 } |
61 |
63 |
62 TUint32 TRandom::Next() |
64 TUint32 TPRNG::IntRand() |
63 { |
65 { |
64 iV = KA * iV + KB; |
66 iV = KA * iV + KB; |
65 return iV; |
67 return iV; |
|
68 } |
|
69 |
|
70 TReal TPRNG::FloatRand() |
|
71 { |
|
72 return (TReal)IntRand() / KMaxTUint32; |
|
73 } |
|
74 |
|
75 class TRandom |
|
76 { |
|
77 public: |
|
78 virtual ~TRandom() { } |
|
79 virtual TUint32 Next() = 0; |
|
80 }; |
|
81 |
|
82 class TUniformRandom : public TRandom |
|
83 { |
|
84 public: |
|
85 void SetParams(TUint aMax) { iMax = aMax; } |
|
86 virtual TUint32 Next(); |
|
87 |
|
88 private: |
|
89 TPRNG iRand; |
|
90 TUint iMax; |
|
91 }; |
|
92 |
|
93 TUint32 TUniformRandom::Next() |
|
94 { |
|
95 return iRand.IntRand() % iMax; |
|
96 } |
|
97 |
|
98 class TNormalRandom : public TRandom |
|
99 { |
|
100 public: |
|
101 void SetParams(TInt aMax, TInt aSd); |
|
102 virtual TUint32 Next(); |
|
103 |
|
104 private: |
|
105 TUint32 GetNext(); |
|
106 |
|
107 private: |
|
108 TPRNG iRand; |
|
109 TInt iMax; |
|
110 TInt iExpectation; |
|
111 TInt iSd; |
|
112 TUint32 iCached; |
|
113 }; |
|
114 |
|
115 void TNormalRandom::SetParams(TInt aMax, TInt aSd) |
|
116 { |
|
117 iMax = aMax; |
|
118 iExpectation = aMax / 2; |
|
119 iSd = aSd; |
|
120 iCached = KMaxTUint32; |
|
121 } |
|
122 |
|
123 TUint32 TNormalRandom::Next() |
|
124 { |
|
125 TUint32 r; |
|
126 do |
|
127 { |
|
128 r = GetNext(); |
|
129 } |
|
130 while (r > (TUint)iMax); |
|
131 return r; |
|
132 } |
|
133 |
|
134 TUint32 TNormalRandom::GetNext() |
|
135 { |
|
136 if (iCached != KMaxTUint32) |
|
137 { |
|
138 TUint32 r = iCached; |
|
139 iCached = KMaxTUint32; |
|
140 return r; |
|
141 } |
|
142 |
|
143 // box-muller transform |
|
144 // from http://www.taygeta.com/random/gaussian.html |
|
145 |
|
146 TReal x1, x2, w, ln_w, y1, y2; |
|
147 do |
|
148 { |
|
149 x1 = 2.0 * iRand.FloatRand() - 1.0; |
|
150 x2 = 2.0 * iRand.FloatRand() - 1.0; |
|
151 w = x1 * x1 + x2 * x2; |
|
152 } |
|
153 while ( w >= 1.0 ); |
|
154 |
|
155 TInt r = Math::Ln(ln_w, w); |
|
156 __ASSERT_ALWAYS(r == KErrNone, User::Invariant()); |
|
157 w = (-2.0 * ln_w ) / w; |
|
158 TReal w2; |
|
159 r = Math::Sqrt(w2, w); |
|
160 __ASSERT_ALWAYS(r == KErrNone, User::Invariant()); |
|
161 y1 = x1 * w2; |
|
162 y2 = x2 * w2; |
|
163 |
|
164 y1 = y1 * iSd + iExpectation; |
|
165 y2 = y2 * iSd + iExpectation; |
|
166 |
|
167 iCached = (TUint32)y2; |
|
168 |
|
169 return (TUint32)y1; |
|
170 } |
|
171 |
|
172 static TBool BenchmarksSupported = EFalse; |
|
173 static TReal BenchmarkMultiplier; |
|
174 |
|
175 static TInt InitBenchmarks() |
|
176 { |
|
177 BenchmarksSupported = UserSvr::HalFunction(EHalGroupVM, EVMHalResetPagingBenchmark, (TAny*)EPagingBmReadRomPage, NULL) == KErrNone; |
|
178 if (!BenchmarksSupported) |
|
179 return KErrNone; |
|
180 |
|
181 TInt freq = 0; |
|
182 TInt r = HAL::Get(HAL::EFastCounterFrequency, freq); |
|
183 if (r != KErrNone) |
|
184 return r; |
|
185 BenchmarkMultiplier = 1000000.0 / freq; |
|
186 return KErrNone; |
|
187 } |
|
188 |
|
189 static void ResetBenchmarks() |
|
190 { |
|
191 if (!BenchmarksSupported) |
|
192 return; |
|
193 for (TInt i = 0 ; i < EMaxPagingBm ; ++i) |
|
194 { |
|
195 TInt r = UserSvr::HalFunction(EHalGroupVM, EVMHalResetPagingBenchmark, (TAny*)i, NULL); |
|
196 if (r != KErrNone) |
|
197 test.Printf(_L("Error resetting benchmark %d\n"), i); |
|
198 test_KErrNone(r); |
|
199 } |
|
200 } |
|
201 |
|
202 static TInt GetBenchmark(TPagingBenchmark aBenchmark, TInt& aCountOut, TInt& aTotalTimeInMicrosOut) |
|
203 { |
|
204 |
|
205 SPagingBenchmarkInfo info; |
|
206 TInt r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetPagingBenchmark, (TAny*)aBenchmark, &info); |
|
207 if (r!=KErrNone) |
|
208 return r; |
|
209 |
|
210 aCountOut = info.iCount; |
|
211 aTotalTimeInMicrosOut = (TInt)(info.iTotalTime * BenchmarkMultiplier); |
|
212 return KErrNone; |
|
213 } |
|
214 |
|
215 static TInt GetAllBenchmarks(TInt aTestLengthInSeconds, TInt aCountOut[EMaxPagingBm], TInt aTimeOut[EMaxPagingBm]) |
|
216 { |
|
217 for (TInt i = 0 ; i < EMaxPagingBm ; ++i) |
|
218 { |
|
219 TInt count = 0; |
|
220 TInt timeInMicros = 0; |
|
221 TInt r = GetBenchmark((TPagingBenchmark)i, count, timeInMicros); |
|
222 if (r != KErrNone) |
|
223 return r; |
|
224 |
|
225 aCountOut[i] = count / aTestLengthInSeconds; |
|
226 aTimeOut[i] = timeInMicros / aTestLengthInSeconds; |
|
227 } |
|
228 return KErrNone; |
66 } |
229 } |
67 |
230 |
68 void CreatePagedChunk(TInt aSizeInPages) |
231 void CreatePagedChunk(TInt aSizeInPages) |
69 { |
232 { |
70 test_Equal(0,gChunk.Handle()); |
233 test_Equal(0,gChunk.Handle()); |
103 |
325 |
104 TInt ThrashTestFunc(TAny* aArg) |
326 TInt ThrashTestFunc(TAny* aArg) |
105 { |
327 { |
106 SThrashTestArgs* args = (SThrashTestArgs*)aArg; |
328 SThrashTestArgs* args = (SThrashTestArgs*)aArg; |
107 |
329 |
108 TRandom random; |
330 TPRNG random; |
|
331 TUniformRandom uniformRand; |
|
332 TNormalRandom normalRand; |
|
333 |
109 TInt startPage = args->iThreadGroup * args->iGroupSize; |
334 TInt startPage = args->iThreadGroup * args->iGroupSize; |
110 TInt* ptr = (TInt*)(args->iBasePtr + startPage * gPageSize); |
335 TInt* ptr = (TInt*)(args->iBasePtr + startPage * gPageSize); |
|
336 |
|
337 |
111 switch (args->iWorkload) |
338 switch (args->iWorkload) |
112 { |
339 { |
113 case EWorkloadSequential: |
340 case EWorkloadSequential: |
114 while (gRunThrashTest) |
341 while (gRunThrashTest) |
115 { |
342 { |
116 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); |
343 for (TUint i = 0 ; |
117 for (TInt i = 0 ; i < size && gRunThrashTest ; ++i) |
344 gRunThrashTest && i < (args->iPageCount * gPageSize) / sizeof(TInt) ; |
|
345 ++i) |
118 { |
346 { |
119 ptr[i] = random.Next(); |
347 ptr[i] = 1; |
120 __e32_atomic_add_ord64(&args->iAccesses, 1); |
348 __e32_atomic_add_ord64(&args->iAccesses, 1); |
121 } |
349 } |
122 } |
350 } |
123 break; |
351 break; |
124 |
352 |
125 case EWorkloadRandom: |
353 case EWorkloadUniformRandom: |
|
354 case EWorkloadNormalRandom1: |
|
355 case EWorkloadNormalRandom2: |
126 { |
356 { |
127 TInt acc = 0; |
357 TInt acc = 0; |
|
358 TInt oldSize = -1; |
|
359 TUint32 writeMask = 0; |
|
360 switch (args->iWorkload) |
|
361 { |
|
362 case EWorkloadUniformRandom: |
|
363 case EWorkloadNormalRandom1: |
|
364 writeMask = 0x80000000; break; |
|
365 case EWorkloadNormalRandom2: |
|
366 writeMask = 0xc0000000; break; |
|
367 default: test(EFalse); break; |
|
368 } |
128 while (gRunThrashTest) |
369 while (gRunThrashTest) |
129 { |
370 { |
130 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); |
371 TInt size = args->iPageCount; |
131 for (TInt i = 0 ; i < size && gRunThrashTest ; ++i) |
372 if (size != oldSize) |
132 { |
373 { |
133 TUint32 rand = random.Next(); |
374 switch (args->iWorkload) |
134 TInt action = rand >> 31; |
375 { |
135 TInt r = rand % size; |
376 case EWorkloadUniformRandom: |
136 if (action == 0) |
377 uniformRand.SetParams(size); break; |
137 acc += ptr[r]; |
378 case EWorkloadNormalRandom1: |
138 else |
379 case EWorkloadNormalRandom2: |
139 ptr[r] = acc; |
380 normalRand.SetParams(size, size / 8); break; |
140 __e32_atomic_add_ord64(&args->iAccesses, 1); |
381 default: test(EFalse); break; |
|
382 } |
|
383 oldSize = size; |
141 } |
384 } |
|
385 |
|
386 TInt page = args->iWorkload == EWorkloadUniformRandom ? |
|
387 uniformRand.Next() : normalRand.Next(); |
|
388 TInt index = page * (gPageSize / sizeof(TInt)); |
|
389 TBool write = (random.IntRand() & writeMask) == 0; |
|
390 if (write) |
|
391 ptr[index] = acc; |
|
392 else |
|
393 acc += ptr[index]; |
|
394 __e32_atomic_add_ord64(&args->iAccesses, 1); |
142 } |
395 } |
143 } |
396 } |
144 break; |
397 break; |
145 |
398 |
146 case EWorkloadShuffle: |
399 case EWorkloadShuffle: |
147 { |
400 { |
148 TInt i; |
401 TInt i = 0; |
149 while (gRunThrashTest) |
402 while (gRunThrashTest) |
150 { |
403 { |
151 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); |
404 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt); |
152 for (i = 0 ; gRunThrashTest && i < (size - 1) ; ++i) |
405 Mem::Swap(&ptr[i], &ptr[i + random.IntRand() % (size - i - 1) + 1], sizeof(TInt)); |
153 { |
406 __e32_atomic_add_ord64(&args->iAccesses, 2); |
154 Mem::Swap(&ptr[i], &ptr[i + random.Next() % (size - i - 1) + 1], sizeof(TInt)); |
407 ++i; |
155 __e32_atomic_add_ord64(&args->iAccesses, 2); |
408 if (i >= size - 1) |
156 } |
409 i = 0; |
157 } |
410 } |
158 } |
411 } |
159 break; |
412 break; |
160 |
413 |
161 default: |
414 default: |
170 RThread iThread; |
423 RThread iThread; |
171 TRequestStatus iStatus; |
424 TRequestStatus iStatus; |
172 SThrashTestArgs iArgs; |
425 SThrashTestArgs iArgs; |
173 }; |
426 }; |
174 |
427 |
175 void ThrashTest(TInt aThreads, // number of threads to run |
428 void ThrashTest(const TDesC& aTestName, // name and description |
|
429 TInt aThreads, // number of threads to run |
176 TBool aSharedData, // whether all threads share the same data |
430 TBool aSharedData, // whether all threads share the same data |
177 TWorkload aWorkload, |
431 TWorkload aWorkload, |
178 TInt aBeginPages, // number of pages to start with for last/all threads |
432 TInt aBeginPages, // number of pages to start with for last/all threads |
179 TInt aEndPages, // number of pages to end with for last/all threads |
433 TInt aEndPages, // number of pages to end with for last/all threads |
180 TInt aOtherPages) // num of pages for other threads, or zero to use same value for all |
434 TInt aOtherPages) // num of pages for other threads, or zero to use same value for all |
181 { |
435 { |
182 RDebug::Printf("\nPages Accesses ThL"); |
436 const TInt KTestLengthInSeconds = 2; |
183 |
437 |
|
438 test.Next(_L("Thrash test")); |
|
439 |
184 DPTest::FlushCache(); |
440 DPTest::FlushCache(); |
185 User::After(1000000); |
441 EnsureSystemIdle(); |
|
442 |
|
443 TInt i; |
|
444 test.Printf(_L("Table: %S\n"), &aTestName); |
|
445 test.Printf(_L("totalPages, totalAccesses, thrashLevel")); |
|
446 if (BenchmarksSupported) |
|
447 test.Printf(_L(", rejuveCount, rejuveTime, codePageInCount, codePageInTime, initCount, initTime, readCount, readTime, writePages, writeCount, writeTime")); |
|
448 if (aThreads > 1) |
|
449 { |
|
450 for (TInt i = 0 ; i < aThreads ; ++i) |
|
451 test.Printf(_L(", Thread%dPages, Thread%dAccesses"), i, i); |
|
452 } |
|
453 test.Printf(_L("\n")); |
186 |
454 |
187 TInt pagesNeeded; |
455 TInt pagesNeeded; |
188 TInt maxPages = Max(aBeginPages, aEndPages); |
456 TInt maxPages = Max(aBeginPages, aEndPages); |
189 TInt groupSize = 0; |
457 TInt groupSize = 0; |
190 if (aSharedData) |
458 if (aSharedData) |
255 if (aSharedData) |
524 if (aSharedData) |
256 totalPages = Max(totalPages, threads[i].iArgs.iPageCount); |
525 totalPages = Max(totalPages, threads[i].iArgs.iPageCount); |
257 else |
526 else |
258 totalPages += threads[i].iArgs.iPageCount; |
527 totalPages += threads[i].iArgs.iPageCount; |
259 } |
528 } |
260 |
529 TInt accessesPerSecond = (TInt)(totalAccesses / KTestLengthInSeconds); |
261 test.Printf(_L("%5d %12ld %3d"), totalPages, totalAccesses, thrashLevel); |
530 |
262 for (i = 0 ; i < aThreads ; ++i) |
531 TBool warmingUp = (step > 0) ? pageCount < aBeginPages : pageCount > aBeginPages; |
|
532 if (!warmingUp) |
263 { |
533 { |
264 test.Printf(_L(" %5d %12ld"), |
534 test.Printf(_L("%10d, %13d, %11.2f"), totalPages, accessesPerSecond, (TReal)thrashLevel / 255); |
265 threads[i].iArgs.iPageCount, |
535 |
266 __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses)); |
536 if (BenchmarksSupported) |
267 test_Equal(KRequestPending, threads[i].iStatus.Int()); |
537 { |
|
538 TInt benchmarkCount[EMaxPagingBm]; |
|
539 TInt benchmarkTime[EMaxPagingBm]; |
|
540 test_KErrNone(GetAllBenchmarks(KTestLengthInSeconds, benchmarkCount, benchmarkTime)); |
|
541 |
|
542 TInt otherPageInCount = benchmarkCount[EPagingBmReadRomPage] + benchmarkCount[EPagingBmReadCodePage]; |
|
543 TInt otherPageInTime = benchmarkTime[EPagingBmReadRomPage] + benchmarkTime[EPagingBmReadCodePage]; |
|
544 |
|
545 TInt initCount = benchmarkCount[EPagingBmReadDataPage] - benchmarkCount[EPagingBmReadDataMedia]; |
|
546 TInt initTime = benchmarkTime[EPagingBmReadDataPage] - benchmarkTime[EPagingBmReadDataMedia]; |
|
547 |
|
548 test.Printf(_L(", %11d, %10d, %15d, %14d, %9d, %8d, %9d, %8d, %10d, %10d, %9d"), |
|
549 benchmarkCount[EPagingBmRejuvenate], benchmarkTime[EPagingBmRejuvenate], |
|
550 otherPageInCount, otherPageInTime, |
|
551 initCount, initTime, |
|
552 benchmarkCount[EPagingBmReadDataMedia], benchmarkTime[EPagingBmReadDataMedia], |
|
553 benchmarkCount[EPagingBmWriteDataPage], |
|
554 benchmarkCount[EPagingBmWriteDataMedia], benchmarkTime[EPagingBmWriteDataMedia]); |
|
555 } |
|
556 |
|
557 if (aThreads > 1) |
|
558 { |
|
559 for (i = 0 ; i < aThreads ; ++i) |
|
560 { |
|
561 test.Printf(_L(", %12d, %15ld"), |
|
562 threads[i].iArgs.iPageCount, |
|
563 __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses)); |
|
564 test_Equal(KRequestPending, threads[i].iStatus.Int()); |
|
565 } |
|
566 } |
|
567 test.Printf(_L("\n")); |
268 } |
568 } |
269 test.Printf(_L("\n")); |
569 |
270 |
570 pageCount += step; |
271 if (aEndPages >= aBeginPages ? pageCount >= aEndPages : pageCount < aEndPages) |
571 if (aEndPages >= aBeginPages ? pageCount >= aEndPages : pageCount < aEndPages) |
272 break; |
572 break; |
273 pageCount += step; |
|
274 } |
573 } |
275 |
574 |
276 gRunThrashTest = EFalse; |
575 gRunThrashTest = EFalse; |
277 |
576 |
278 for (i = 0 ; i < aThreads ; ++i) |
577 for (i = 0 ; i < aThreads ; ++i) |
296 TInt maxPages2 = (5 * gMaxCacheSize) / 8; |
595 TInt maxPages2 = (5 * gMaxCacheSize) / 8; |
297 TInt minPages4 = (3 * gMaxCacheSize) / 16 - 4; |
596 TInt minPages4 = (3 * gMaxCacheSize) / 16 - 4; |
298 TInt maxPages4 = (5 * gMaxCacheSize) / 16; |
597 TInt maxPages4 = (5 * gMaxCacheSize) / 16; |
299 |
598 |
300 // Single thread increasing in size |
599 // Single thread increasing in size |
301 test.Next(_L("Thrash test: single thread, sequential workload")); |
600 ThrashTest(_L("single thread, sequential workload"), |
302 ThrashTest(1, ETrue, EWorkloadSequential, minPages, maxPages, 0); |
601 1, ETrue, EWorkloadSequential, minPages, maxPages, 0); |
303 |
602 |
304 test.Next(_L("Thrash test: single thread, random workload")); |
603 ThrashTest(_L("single thread, random workload"), |
305 ThrashTest(1, ETrue, EWorkloadRandom, minPages, maxPages, 0); |
604 1, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); |
306 |
605 |
307 test.Next(_L("Thrash test: single thread, shuffle workload")); |
606 ThrashTest(_L("single thread, shuffle workload"), |
308 ThrashTest(1, ETrue, EWorkloadShuffle, minPages, maxPages, 0); |
607 1, ETrue, EWorkloadShuffle, minPages, maxPages, 0); |
309 |
608 |
310 // Multiple threads with shared data, one thread incresing in size |
609 // Multiple threads with shared data, one thread incresing in size |
311 test.Next(_L("Thrash test: two threads with shared data, one thread increasing, random workload")); |
610 ThrashTest(_L("two threads with shared data, one thread increasing, random workload"), |
312 ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, minPages); |
611 2, ETrue, EWorkloadUniformRandom, minPages, maxPages, minPages); |
313 |
612 |
314 test.Next(_L("Thrash test: four threads with shared data, one thread increasing, random workload")); |
613 ThrashTest(_L("four threads with shared data, one thread increasing, random workload"), |
315 ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, minPages); |
614 4, ETrue, EWorkloadUniformRandom, minPages, maxPages, minPages); |
316 |
615 |
317 // Multiple threads with shared data, all threads incresing in size |
616 // Multiple threads with shared data, all threads incresing in size |
318 test.Next(_L("Thrash test: two threads with shared data, all threads increasing, random workload")); |
617 ThrashTest(_L("two threads with shared data, all threads increasing, random workload"), |
319 ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, 0); |
618 2, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); |
320 |
619 |
321 test.Next(_L("Thrash test: four threads with shared data, all threads increasing, random workload")); |
620 ThrashTest(_L("four threads with shared data, all threads increasing, random workload"), |
322 ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, 0); |
621 4, ETrue, EWorkloadUniformRandom, minPages, maxPages, 0); |
323 |
622 |
324 // Multiple threads with independent data, one thread incresing in size |
623 // Multiple threads with independent data, one thread incresing in size |
325 test.Next(_L("Thrash test: two threads with independent data, one thread increasing, random workload")); |
624 ThrashTest(_L("two threads with independent data, one thread increasing, random workload"), |
326 ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, gMaxCacheSize / 2); |
625 2, EFalse, EWorkloadUniformRandom, minPages2, maxPages2, gMaxCacheSize / 2); |
327 |
626 |
328 test.Next(_L("Thrash test: four threads with independent data, one thread increasing, random workload")); |
627 ThrashTest(_L("four threads with independent data, one thread increasing, random workload"), |
329 ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, gMaxCacheSize / 4); |
628 4, EFalse, EWorkloadUniformRandom, minPages4, maxPages4, gMaxCacheSize / 4); |
330 |
629 |
331 // Multiple threads with independant data, all threads incresing in size |
630 // Multiple threads with independant data, all threads incresing in size |
332 test.Next(_L("Thrash test: two threads with independent data, all threads increasing, random workload")); |
631 ThrashTest(_L("two threads with independent data, all threads increasing, random workload"), |
333 ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, 0); |
632 2, EFalse, EWorkloadUniformRandom, minPages2, maxPages2, 0); |
334 |
633 |
335 test.Next(_L("Thrash test: four threads with independent data, all threads increasing, random workload")); |
634 ThrashTest(_L("four threads with independent data, all threads increasing, random workload"), |
336 ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, 0); |
635 4, EFalse, EWorkloadUniformRandom, minPages4, maxPages4, 0); |
337 |
636 |
338 // Attempt to create thrash state where there is sufficient cache |
637 // Attempt to create thrash state where there is sufficient cache |
339 test.Next(_L("Thrash test: two threads with independent data, one threads decreasing, random workload")); |
|
340 TInt halfCacheSize = gMaxCacheSize / 2; |
638 TInt halfCacheSize = gMaxCacheSize / 2; |
341 ThrashTest(2, EFalse, EWorkloadRandom, halfCacheSize + 10, halfCacheSize - 30, halfCacheSize); |
639 ThrashTest(_L("two threads with independent data, one threads decreasing, random workload"), |
|
640 2, EFalse, EWorkloadUniformRandom, halfCacheSize + 10, halfCacheSize - 30, halfCacheSize); |
|
641 } |
|
642 |
|
643 void TestDistribution(TRandom& aRandom, TInt aSamples) |
|
644 { |
|
645 TUint32* data = new TUint32[aSamples]; |
|
646 test_NotNull(data); |
|
647 |
|
648 TInt i; |
|
649 TReal mean = 0.0; |
|
650 for (i = 0 ; i < aSamples ; ++i) |
|
651 { |
|
652 data[i] = aRandom.Next(); |
|
653 mean += (TReal)data[i] / aSamples; |
|
654 } |
|
655 |
|
656 TReal sum2 = 0.0; |
|
657 for (i = 0 ; i < aSamples ; ++i) |
|
658 { |
|
659 TReal d = (TReal)data[i] - mean; |
|
660 sum2 += d * d; |
|
661 } |
|
662 TReal variance = sum2 / (aSamples - 1); |
|
663 |
|
664 test.Printf(_L(" mean == %f\n"), mean); |
|
665 test.Printf(_L(" variance == %f\n"), variance); |
|
666 |
|
667 delete [] data; |
|
668 } |
|
669 |
|
670 void BenchmarkReplacement() |
|
671 { |
|
672 test.Next(_L("Test uniform distribution")); |
|
673 TUniformRandom rand1; |
|
674 rand1.SetParams(100); |
|
675 TestDistribution(rand1, 10000); |
|
676 |
|
677 test.Next(_L("Test normal distribution")); |
|
678 TNormalRandom rand2; |
|
679 rand2.SetParams(100, 25); |
|
680 TestDistribution(rand2, 10000); |
|
681 |
|
682 ThrashTest(_L("Thrash test: single thread, normal random workload 1"), |
|
683 1, ETrue, EWorkloadNormalRandom1, (2 * gMaxCacheSize) / 3, 2 * gMaxCacheSize, 0); |
|
684 |
|
685 ThrashTest(_L("Thrash test: single thread, normal random workload 2"), |
|
686 1, ETrue, EWorkloadNormalRandom2, (2 * gMaxCacheSize) / 3, 2 * gMaxCacheSize, 0); |
|
687 |
|
688 ThrashTest(_L("Thrash test: single thread, uniform random workload"), |
|
689 1, ETrue, EWorkloadUniformRandom, (2 * gMinCacheSize) / 3, (3 * gMaxCacheSize) / 2, 0); |
342 } |
690 } |
343 |
691 |
344 void TestThrashHal() |
692 void TestThrashHal() |
345 { |
693 { |
346 test.Next(_L("Test EVMHalSetThrashThresholds")); |
694 test.Next(_L("Test EVMHalSetThrashThresholds")); |
367 test_KErrNone(notifier.Logon(status)); |
715 test_KErrNone(notifier.Logon(status)); |
368 test_KErrNone(notifier.Logon(status)); // first logon completes immediately |
716 test_KErrNone(notifier.Logon(status)); // first logon completes immediately |
369 test_Equal(KRequestPending, status.Int()); |
717 test_Equal(KRequestPending, status.Int()); |
370 |
718 |
371 // stress system and check thrash level and notification |
719 // stress system and check thrash level and notification |
372 ThrashTest(1, ETrue, EWorkloadRandom, gMaxCacheSize * 2, gMaxCacheSize * 2 + 5, 0); |
720 ThrashTest(_L("stress system"), |
|
721 1, ETrue, EWorkloadUniformRandom, gMaxCacheSize * 2, gMaxCacheSize * 2 + 5, 0); |
373 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); |
722 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); |
374 test(r >= 0 && r <= 255); |
723 test(r >= 0 && r <= 255); |
375 test.Printf(_L("Thrash level == %d\n"), r); |
724 test.Printf(_L("Thrash level == %d\n"), r); |
376 test(r > 200); // should indicate thrashing |
725 test(r > 200); // should indicate thrashing |
377 test_Equal(EChangesThrashLevel, status.Int()); |
726 |
378 User::WaitForAnyRequest(); |
727 TBool gotThrashNotification = EFalse; |
379 |
728 |
380 // wait for system to calm down and check notification again |
729 // wait for EChangesThrashLevel notification |
381 test_KErrNone(notifier.Logon(status)); |
730 while(status.Int() != KRequestPending) |
382 User::WaitForAnyRequest(); |
731 { |
383 test_Equal(EChangesThreadDeath, status.Int()); |
732 gotThrashNotification = (status.Int() & EChangesThrashLevel) != 0; |
384 |
733 User::WaitForAnyRequest(); |
385 test_KErrNone(notifier.Logon(status)); |
734 test_KErrNone(notifier.Logon(status)); |
|
735 User::After(1); |
|
736 } |
|
737 test(gotThrashNotification); |
|
738 |
386 User::After(2000000); |
739 User::After(2000000); |
387 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); |
740 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0); |
388 test(r >= 0 && r <= 255); |
741 test(r >= 0 && r <= 255); |
389 test.Printf(_L("Thrash level == %d\n"), r); |
742 test.Printf(_L("Thrash level == %d\n"), r); |
390 test(r <= 10); // should indicate lightly loaded system |
743 test(r <= 10); // should indicate lightly loaded system |
391 test_Equal(EChangesThrashLevel, status.Int()); |
744 |
|
745 // wait for EChangesThrashLevel notification |
|
746 gotThrashNotification = EFalse; |
|
747 while(status.Int() != KRequestPending) |
|
748 { |
|
749 gotThrashNotification = (status.Int() & EChangesThrashLevel) != 0; |
|
750 User::WaitForAnyRequest(); |
|
751 test_KErrNone(notifier.Logon(status)); |
|
752 User::After(1); |
|
753 } |
|
754 test(gotThrashNotification); |
|
755 test_KErrNone(notifier.LogonCancel()); |
392 User::WaitForAnyRequest(); |
756 User::WaitForAnyRequest(); |
|
757 notifier.Close(); |
393 } |
758 } |
394 |
759 |
395 void TestThrashHalNotSupported() |
760 void TestThrashHalNotSupported() |
396 { |
761 { |
397 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0)); |
762 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0)); |
398 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, 0, 0)); |
763 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, 0, 0)); |
399 } |
764 } |
400 |
765 |
|
766 _LIT(KUsageMessage, "usage: t_thrash [ test ] [ thrashing ] [ benchmarks ]\n"); |
|
767 |
|
768 enum TTestAction |
|
769 { |
|
770 EActionTest = 1 << 0, |
|
771 EActionThrashing = 1 << 1, |
|
772 EActionBenchmarks = 1 << 2 |
|
773 }; |
|
774 |
|
775 void BadUsage() |
|
776 { |
|
777 test.Printf(KUsageMessage); |
|
778 test(EFalse); |
|
779 } |
|
780 |
|
781 TInt ParseCommandLine() |
|
782 { |
|
783 const TInt KMaxLineLength = 64; |
|
784 |
|
785 if (User::CommandLineLength() > KMaxLineLength) |
|
786 BadUsage(); |
|
787 TBuf<KMaxLineLength> buffer; |
|
788 User::CommandLine(buffer); |
|
789 |
|
790 if (buffer == KNullDesC) |
|
791 return EActionTest; |
|
792 |
|
793 TLex lex(buffer); |
|
794 TInt result = 0; |
|
795 while (!lex.Eos()) |
|
796 { |
|
797 TPtrC word = lex.NextToken(); |
|
798 if (word == _L("test")) |
|
799 result |= EActionTest; |
|
800 else if (word == _L("thrashing")) |
|
801 result |= EActionThrashing; |
|
802 else if (word == _L("benchmarks")) |
|
803 result |= EActionBenchmarks; |
|
804 else |
|
805 { |
|
806 test.Printf(_L("bad token '%S'\n"), &word); |
|
807 BadUsage(); |
|
808 } |
|
809 } |
|
810 |
|
811 return result; |
|
812 } |
|
813 |
401 TInt E32Main() |
814 TInt E32Main() |
402 { |
815 { |
403 test.Title(); |
816 test.Title(); |
404 test.Start(_L("Test thrashing monitor")); |
817 test.Start(_L("Test thrashing monitor")); |
405 |
818 |
|
819 test_KErrNone(InitBenchmarks()); |
|
820 |
|
821 TInt actions = ParseCommandLine(); |
|
822 |
406 test_KErrNone(GetGlobalPolicies()); |
823 test_KErrNone(GetGlobalPolicies()); |
407 |
824 |
408 TUint cacheOriginalMin = 0; |
825 TUint cacheOriginalMin = 0; |
409 TUint cacheOriginalMax = 0; |
826 TUint cacheOriginalMax = 0; |
410 TUint cacheCurrentSize = 0; |
|
411 |
827 |
412 if (gDataPagingSupported) |
828 if (gDataPagingSupported) |
413 { |
829 { |
414 test.Next(_L("Thrash test: change maximum cache size to minimal")); |
830 test.Next(_L("Thrash test: change cache size to maximum 2Mb")); |
415 //store original values |
831 TUint cacheCurrentSize = 0; |
416 DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize); |
832 DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize); |
417 gMaxCacheSize = 256; |
833 gMinCacheSize = 512; |
418 gMinCacheSize = 64; |
834 gMaxCacheSize = 520; |
419 test_KErrNone(DPTest::SetCacheSize(gMinCacheSize * gPageSize, gMaxCacheSize * gPageSize)); |
835 test_KErrNone(DPTest::SetCacheSize(gMinCacheSize * gPageSize, gMaxCacheSize * gPageSize)); |
420 } |
836 } |
421 |
837 |
422 TBool flexibleMemoryModel = (MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible; |
838 if (actions & EActionTest) |
423 if (flexibleMemoryModel) |
839 { |
424 TestThrashHal(); |
840 TBool flexibleMemoryModel = (MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible; |
425 else |
841 if (flexibleMemoryModel) |
426 TestThrashHalNotSupported(); |
842 TestThrashHal(); |
427 |
843 else |
428 if (gDataPagingSupported && User::CommandLineLength() > 0) |
844 TestThrashHalNotSupported(); |
429 { |
845 } |
|
846 |
|
847 if (actions & EActionThrashing) |
|
848 { |
430 test.Next(_L("Extended thrashing tests")); |
849 test.Next(_L("Extended thrashing tests")); |
431 TestThrashing(); |
850 TestThrashing(); |
432 } |
851 } |
|
852 |
|
853 if (actions & EActionBenchmarks) |
|
854 { |
|
855 test.Next(_L("Benchmarking page replacement")); |
|
856 BenchmarkReplacement(); |
|
857 } |
|
858 |
433 if (gDataPagingSupported) |
859 if (gDataPagingSupported) |
434 { |
860 { |
435 //Reset the cache size to normal |
|
436 test.Next(_L("Thrash test: Reset cache size to normal")); |
861 test.Next(_L("Thrash test: Reset cache size to normal")); |
437 test_KErrNone(DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax)); |
862 test_KErrNone(DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax)); |
438 } |
863 } |
439 |
864 |
440 test.End(); |
865 test.End(); |
441 return 0; |
866 return 0; |
442 } |
867 } |