Update contrib.
1 // Copyright (c) 2008-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\demandpaging\t_thrash.cpp
15 // todo: test combinations of rom / code / data paging
18 #define __E32TEST_EXTENSION__
27 #include <e32msgqueue.h>
28 #include <e32atomics.h>
32 #include "../mmu/mmudetect.h"
33 #include "../mmu/d_memorytest.h"
34 #include "../mmu/t_codepaging_dll.h"
36 RTest test(_L("T_THRASH"));
38 volatile TBool gRunThrashTest = EFalse;
40 _LIT(KChunkName, "t_thrash chunk");
59 iV = (TUint32)this + RThread().Id() + User::FastCounter() + 23;
62 TUint32 TRandom::Next()
68 void CreatePagedChunk(TInt aSizeInPages)
70 test_Equal(0,gChunk.Handle());
72 TChunkCreateInfo createInfo;
73 TInt size = aSizeInPages * gPageSize;
74 createInfo.SetNormal(size, size);
75 createInfo.SetPaging(TChunkCreateInfo::EPaged);
76 createInfo.SetOwner(EOwnerProcess);
77 createInfo.SetGlobal(KChunkName);
78 test_KErrNone(gChunk.Create(createInfo));
79 test(gChunk.IsPaged()); // this is only ever called if data paging is supported
82 TUint32* PageBasePtr(TInt aPage)
84 return (TUint32*)(gChunk.Base() + (gPageSize * aPage));
94 struct SThrashTestArgs
100 volatile TInt iPageCount;
101 volatile TInt64 iAccesses;
104 TInt ThrashTestFunc(TAny* aArg)
106 SThrashTestArgs* args = (SThrashTestArgs*)aArg;
109 TInt startPage = args->iThreadGroup * args->iGroupSize;
110 TInt* ptr = (TInt*)(args->iBasePtr + startPage * gPageSize);
111 switch (args->iWorkload)
113 case EWorkloadSequential:
114 while (gRunThrashTest)
116 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt);
117 for (TInt i = 0 ; i < size && gRunThrashTest ; ++i)
119 ptr[i] = random.Next();
120 __e32_atomic_add_ord64(&args->iAccesses, 1);
125 case EWorkloadRandom:
128 while (gRunThrashTest)
130 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt);
131 for (TInt i = 0 ; i < size && gRunThrashTest ; ++i)
133 TUint32 rand = random.Next();
134 TInt action = rand >> 31;
135 TInt r = rand % size;
140 __e32_atomic_add_ord64(&args->iAccesses, 1);
146 case EWorkloadShuffle:
149 while (gRunThrashTest)
151 TInt size = (args->iPageCount * gPageSize) / sizeof(TInt);
152 for (i = 0 ; gRunThrashTest && i < (size - 1) ; ++i)
154 Mem::Swap(&ptr[i], &ptr[i + random.Next() % (size - i - 1) + 1], sizeof(TInt));
155 __e32_atomic_add_ord64(&args->iAccesses, 2);
168 struct SThrashThreadData
171 TRequestStatus iStatus;
172 SThrashTestArgs iArgs;
175 void ThrashTest(TInt aThreads, // number of threads to run
176 TBool aSharedData, // whether all threads share the same data
178 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
180 TInt aOtherPages) // num of pages for other threads, or zero to use same value for all
182 RDebug::Printf("\nPages Accesses ThL");
184 DPTest::FlushCache();
185 User::After(1000000);
188 TInt maxPages = Max(aBeginPages, aEndPages);
191 pagesNeeded = Max(maxPages, aOtherPages);
196 groupSize = aOtherPages;
197 pagesNeeded = (aThreads - 1) * aOtherPages + maxPages;
201 groupSize = maxPages;
202 pagesNeeded = aThreads * maxPages;
205 CreatePagedChunk(pagesNeeded);
207 SThrashThreadData* threads = new SThrashThreadData[aThreads];
208 test_NotNull(threads);
210 gRunThrashTest = ETrue;
211 TInt pageCount = aBeginPages;
212 const TInt maxSteps = 30;
213 TInt step = aEndPages >= aBeginPages ? Max((aEndPages - aBeginPages) / maxSteps, 1) : Min((aEndPages - aBeginPages) / maxSteps, -1);
216 for (i = 0 ; i < aThreads ; ++i)
218 SThrashThreadData& thread = threads[i];
219 thread.iArgs.iThreadGroup = aSharedData ? 0 : i;
220 thread.iArgs.iGroupSize = groupSize;
221 thread.iArgs.iWorkload = aWorkload;
222 thread.iArgs.iBasePtr = gChunk.Base();
224 thread.iArgs.iPageCount = (i == aThreads - 1) ? pageCount : aOtherPages;
226 thread.iArgs.iPageCount = pageCount;
227 test_KErrNone(thread.iThread.Create(KNullDesC, ThrashTestFunc, gPageSize, NULL, &thread.iArgs));
228 thread.iThread.Logon(thread.iStatus);
229 thread.iThread.SetPriority(EPriorityLess);
230 threads[i].iThread.Resume();
236 threads[aThreads - 1].iArgs.iPageCount = pageCount;
239 for (i = 0 ; i < aThreads ; ++i)
240 threads[i].iArgs.iPageCount = pageCount;
243 for (i = 0 ; i < aThreads ; ++i)
244 __e32_atomic_store_ord64(&threads[i].iArgs.iAccesses, 0);
246 User::After(2000000);
247 TInt thrashLevel = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0);
248 test(thrashLevel >= 0 && thrashLevel <= 255);
250 TInt64 totalAccesses = 0;
252 for (i = 0 ; i < aThreads ; ++i)
254 totalAccesses += __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses);
256 totalPages = Max(totalPages, threads[i].iArgs.iPageCount);
258 totalPages += threads[i].iArgs.iPageCount;
261 test.Printf(_L("%5d %12ld %3d"), totalPages, totalAccesses, thrashLevel);
262 for (i = 0 ; i < aThreads ; ++i)
264 test.Printf(_L(" %5d %12ld"),
265 threads[i].iArgs.iPageCount,
266 __e32_atomic_load_acq64(&threads[i].iArgs.iAccesses));
267 test_Equal(KRequestPending, threads[i].iStatus.Int());
269 test.Printf(_L("\n"));
271 if (aEndPages >= aBeginPages ? pageCount >= aEndPages : pageCount < aEndPages)
276 gRunThrashTest = EFalse;
278 for (i = 0 ; i < aThreads ; ++i)
280 SThrashThreadData& thread = threads[i];
281 User::WaitForRequest(thread.iStatus);
282 test_Equal(EExitKill, thread.iThread.ExitType());
283 test_KErrNone(thread.iStatus.Int());
284 thread.iThread.Close();
288 RDebug::Printf("\n");
293 TInt minPages = (3 * gMaxCacheSize) / 4 - 4;
294 TInt maxPages = (5 * gMaxCacheSize) / 4;
295 TInt minPages2 = (3 * gMaxCacheSize) / 8 - 4;
296 TInt maxPages2 = (5 * gMaxCacheSize) / 8;
297 TInt minPages4 = (3 * gMaxCacheSize) / 16 - 4;
298 TInt maxPages4 = (5 * gMaxCacheSize) / 16;
300 // Single thread increasing in size
301 test.Next(_L("Thrash test: single thread, sequential workload"));
302 ThrashTest(1, ETrue, EWorkloadSequential, minPages, maxPages, 0);
304 test.Next(_L("Thrash test: single thread, random workload"));
305 ThrashTest(1, ETrue, EWorkloadRandom, minPages, maxPages, 0);
307 test.Next(_L("Thrash test: single thread, shuffle workload"));
308 ThrashTest(1, ETrue, EWorkloadShuffle, minPages, maxPages, 0);
310 // 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"));
312 ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, minPages);
314 test.Next(_L("Thrash test: four threads with shared data, one thread increasing, random workload"));
315 ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, minPages);
317 // 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"));
319 ThrashTest(2, ETrue, EWorkloadRandom, minPages, maxPages, 0);
321 test.Next(_L("Thrash test: four threads with shared data, all threads increasing, random workload"));
322 ThrashTest(4, ETrue, EWorkloadRandom, minPages, maxPages, 0);
324 // 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"));
326 ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, gMaxCacheSize / 2);
328 test.Next(_L("Thrash test: four threads with independent data, one thread increasing, random workload"));
329 ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, gMaxCacheSize / 4);
331 // 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"));
333 ThrashTest(2, EFalse, EWorkloadRandom, minPages2, maxPages2, 0);
335 test.Next(_L("Thrash test: four threads with independent data, all threads increasing, random workload"));
336 ThrashTest(4, EFalse, EWorkloadRandom, minPages4, maxPages4, 0);
338 // 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;
341 ThrashTest(2, EFalse, EWorkloadRandom, halfCacheSize + 10, halfCacheSize - 30, halfCacheSize);
346 test.Next(_L("Test EVMHalSetThrashThresholds"));
347 test_Equal(KErrArgument, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, (TAny*)256, 0));
348 test_Equal(KErrArgument, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, (TAny*)0, (TAny*)1));
349 test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, 0, 0));
350 test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, (TAny*)255, 0));
351 test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, (TAny*)200, (TAny*)150));
353 test.Next(_L("Test EVMHalGetThrashLevel"));
354 User::After(2000000);
355 TInt r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0);
356 test(r >= 0 && r <= 255);
357 test.Printf(_L("Thrash level == %d\n"), r);
358 test(r <= 10); // should indicate lightly loaded system
360 if (!gDataPagingSupported)
361 return; // rest of this test relies on data paging
363 // set up thrashing notification
364 RChangeNotifier notifier;
365 test_KErrNone(notifier.Create());
366 TRequestStatus status;
367 test_KErrNone(notifier.Logon(status));
368 test_KErrNone(notifier.Logon(status)); // first logon completes immediately
369 test_Equal(KRequestPending, status.Int());
371 // stress system and check thrash level and notification
372 ThrashTest(1, ETrue, EWorkloadRandom, gMaxCacheSize * 2, gMaxCacheSize * 2 + 5, 0);
373 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0);
374 test(r >= 0 && r <= 255);
375 test.Printf(_L("Thrash level == %d\n"), r);
376 test(r > 200); // should indicate thrashing
377 test_Equal(EChangesThrashLevel, status.Int());
378 User::WaitForAnyRequest();
380 // wait for system to calm down and check notification again
381 test_KErrNone(notifier.Logon(status));
382 User::WaitForAnyRequest();
383 test_Equal(EChangesThreadDeath, status.Int());
385 test_KErrNone(notifier.Logon(status));
386 User::After(2000000);
387 r = UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0);
388 test(r >= 0 && r <= 255);
389 test.Printf(_L("Thrash level == %d\n"), r);
390 test(r <= 10); // should indicate lightly loaded system
391 test_Equal(EChangesThrashLevel, status.Int());
392 User::WaitForAnyRequest();
395 void TestThrashHalNotSupported()
397 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalGetThrashLevel, 0, 0));
398 test_Equal(KErrNotSupported, UserSvr::HalFunction(EHalGroupVM, EVMHalSetThrashThresholds, 0, 0));
404 test.Start(_L("Test thrashing monitor"));
406 test_KErrNone(GetGlobalPolicies());
408 TUint cacheOriginalMin = 0;
409 TUint cacheOriginalMax = 0;
410 TUint cacheCurrentSize = 0;
412 if (gDataPagingSupported)
414 test.Next(_L("Thrash test: change maximum cache size to minimal"));
415 //store original values
416 DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize);
419 test_KErrNone(DPTest::SetCacheSize(gMinCacheSize * gPageSize, gMaxCacheSize * gPageSize));
422 TBool flexibleMemoryModel = (MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible;
423 if (flexibleMemoryModel)
426 TestThrashHalNotSupported();
428 if (gDataPagingSupported && User::CommandLineLength() > 0)
430 test.Next(_L("Extended thrashing tests"));
433 if (gDataPagingSupported)
435 //Reset the cache size to normal
436 test.Next(_L("Thrash test: Reset cache size to normal"));
437 test_KErrNone(DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax));