43 TBool FragThreadStop; |
45 TBool FragThreadStop; |
44 TBool ManualTest; |
46 TBool ManualTest; |
45 TBool CacheSizeAdjustable; |
47 TBool CacheSizeAdjustable; |
46 TUint OrigMinCacheSize; |
48 TUint OrigMinCacheSize; |
47 TUint OrigMaxCacheSize; |
49 TUint OrigMaxCacheSize; |
|
50 |
|
51 // |
|
52 // Random number generation |
|
53 // |
|
54 |
|
55 TUint32 RandomSeed; |
|
56 |
|
57 TUint32 Random() |
|
58 { |
|
59 RandomSeed = RandomSeed*69069+1; |
|
60 return RandomSeed; |
|
61 } |
|
62 |
|
63 TUint32 Random(TUint32 aRange) |
|
64 { |
|
65 return (TUint32)((TUint64(Random())*TUint64(aRange))>>32); |
|
66 } |
|
67 |
|
68 void RandomInit(TUint32 aSeed) |
|
69 { |
|
70 RandomSeed = aSeed+(aSeed<<8)+(aSeed<<16)+(aSeed<<24); |
|
71 Random(); |
|
72 Random(); |
|
73 } |
48 |
74 |
49 TInt AllocPhysicalRam(TUint32& aAddr, TInt aSize, TInt aAlign) |
75 TInt AllocPhysicalRam(TUint32& aAddr, TInt aSize, TInt aAlign) |
50 { |
76 { |
51 return Shadow.AllocPhysicalRam(aAddr,aSize,aAlign); |
77 return Shadow.AllocPhysicalRam(aAddr,aSize,aAlign); |
52 } |
78 } |
163 { |
189 { |
164 r = KErrGeneral; |
190 r = KErrGeneral; |
165 RDebug::Printf("Error alignment phys addr 0x%08x", *(pa - 1)); |
191 RDebug::Printf("Error alignment phys addr 0x%08x", *(pa - 1)); |
166 break; |
192 break; |
167 } |
193 } |
168 if (allocData.iCheckFreeRam && freeRam - allocData.iSize != (TUint)FreeRam()) |
194 TUint newFreeRam = FreeRam(); |
|
195 if (allocData.iCheckFreeRam && freeRam - allocData.iSize != newFreeRam) |
169 { |
196 { |
170 r = KErrGeneral; |
197 r = KErrGeneral; |
171 RDebug::Printf("Error in free ram 0x%08x orig 0x%08x", FreeRam(), freeRam); |
198 RDebug::Printf("Error in free ram 0x%08x orig 0x%08x", newFreeRam, freeRam); |
172 break; |
199 break; |
173 } |
200 } |
174 } |
201 } |
175 |
202 |
176 TUint32* physEnd = pa; |
203 TUint32* physEnd = pa; |
185 if (allocData.iCheckMaxAllocs && allocations > maxAllocs) |
212 if (allocData.iCheckMaxAllocs && allocations > maxAllocs) |
186 { |
213 { |
187 r = KErrOverflow; |
214 r = KErrOverflow; |
188 RDebug::Printf("Error able to allocate too many pages"); |
215 RDebug::Printf("Error able to allocate too many pages"); |
189 } |
216 } |
190 if (allocData.iCheckFreeRam && initialFreeRam != (TUint)FreeRam()) |
217 TUint finalFreeRam = FreeRam(); |
|
218 if (allocData.iCheckFreeRam && initialFreeRam != finalFreeRam) |
191 { |
219 { |
192 r = KErrGeneral; |
220 r = KErrGeneral; |
193 RDebug::Printf("Error in free ram 0x%08x initial 0x%08x", FreeRam(), initialFreeRam); |
221 RDebug::Printf("Error in free ram 0x%08x initial 0x%08x", finalFreeRam, initialFreeRam); |
194 } |
222 } |
195 delete[] physAddrs; |
223 delete[] physAddrs; |
196 if (r != KErrNone && r != KErrNoMemory) |
224 if (r != KErrNone && r != KErrNoMemory) |
197 return r; |
225 return r; |
198 TUint possibleAllocs = initialFreeRam / allocData.iSize; |
226 TUint possibleAllocs = initialFreeRam / allocData.iSize; |
217 RThread* threads = new RThread[aNumThreads]; |
245 RThread* threads = new RThread[aNumThreads]; |
218 TRequestStatus* status = new TRequestStatus[aNumThreads]; |
246 TRequestStatus* status = new TRequestStatus[aNumThreads]; |
219 TUint i = 0; |
247 TUint i = 0; |
220 for (; i < aNumThreads; i++) |
248 for (; i < aNumThreads; i++) |
221 {// Need enough heap to store addr of every possible allocation + 1. |
249 {// Need enough heap to store addr of every possible allocation + 1. |
222 TUint requiredHeapMax = Max(PageSize, ((InitFreeRam / aSize) / sizeof(TUint32)) + sizeof(TUint32)); |
250 TUint requiredHeapMax = Max(PageSize, ((TotalRam / aSize) * sizeof(TUint32)) + sizeof(TUint32)); |
223 TInt r = threads[i].Create(KNullDesC, FillPhysicalRam, KDefaultStackSize, PageSize, requiredHeapMax, (TAny*)&allocData); |
251 TInt r = threads[i].Create(KNullDesC, FillPhysicalRam, KDefaultStackSize, PageSize, requiredHeapMax, (TAny*)&allocData); |
224 test_KErrNone(r); |
252 if (r != KErrNone) |
|
253 break; |
225 threads[i].Logon(status[i]); |
254 threads[i].Logon(status[i]); |
226 } |
255 } |
227 for (i = 0; i < aNumThreads; i++) |
256 TUint totalThreads = i; |
|
257 for (i = 0; i < totalThreads; i++) |
228 { |
258 { |
229 threads[i].Resume(); |
259 threads[i].Resume(); |
230 } |
260 } |
231 for (i = 0; i < aNumThreads; i++) |
261 for (i = 0; i < totalThreads; i++) |
232 { |
262 { |
233 User::WaitForRequest(status[i]); |
263 User::WaitForRequest(status[i]); |
234 test_Equal(EExitKill, threads[i].ExitType()); |
264 test_Equal(EExitKill, threads[i].ExitType()); |
235 TInt exitReason = threads[i].ExitReason(); |
265 TInt exitReason = threads[i].ExitReason(); |
236 test_Value(exitReason, exitReason >= 0 || exitReason == KErrNoMemory); |
266 test_Value(exitReason, exitReason >= 0 || exitReason == KErrNoMemory); |
247 }TouchData; |
277 }TouchData; |
248 |
278 |
249 |
279 |
250 TInt TouchMemory(TAny*) |
280 TInt TouchMemory(TAny*) |
251 { |
281 { |
|
282 RThread::Rendezvous(KErrNone); // Signal that this thread has started running. |
|
283 RandomInit(TouchData.iSize); |
252 while (!TouchDataStop) |
284 while (!TouchDataStop) |
253 { |
285 { |
254 TUint8* p = Chunk.Base(); |
286 TUint8* p = Chunk.Base(); |
255 TUint8* pEnd = p + ChunkCommitEnd; |
287 TUint8* pEnd = p + ChunkCommitEnd; |
256 TUint8* fragPEnd = p + TouchData.iFrequency; |
288 TUint8* fragPEnd = p + TouchData.iFrequency; |
257 for (TUint8* fragP = p + TouchData.iSize; fragPEnd < pEnd;) |
289 for (TUint8* fragP = p + TouchData.iSize; fragPEnd < pEnd && !TouchDataStop;) |
258 { |
290 { |
259 TUint8* data = fragP; |
291 TUint8* data = fragP; |
260 for (; data < fragPEnd; data += PageSize) |
292 for (; data < fragPEnd && !TouchDataStop; data += PageSize) |
261 { |
293 { |
262 *data = (TUint8)(data - fragP); |
294 *data = (TUint8)(data - fragP); |
|
295 TUint random = Random(); |
|
296 if (random & 0x8484) |
|
297 User::After(random & 0xFFFF); |
263 } |
298 } |
264 for (data = fragP; data < fragPEnd; data += PageSize) |
299 for (data = fragP; data < fragPEnd && !TouchDataStop; data += PageSize) |
265 { |
300 { |
266 if (*data != (TUint8)(data - fragP)) |
301 if (*data != (TUint8)(data - fragP)) |
267 { |
302 { |
268 RDebug::Printf("Error unexpected data 0x%x read from 0x%08x", *data, data); |
303 RDebug::Printf("Error unexpected data 0x%x read from 0x%08x", *data, data); |
269 return KErrGeneral; |
304 return KErrGeneral; |
270 } |
305 } |
|
306 TUint random = Random(); |
|
307 if (random & 0x8484) |
|
308 User::After(random & 0xFFFF); |
271 } |
309 } |
272 fragP = fragPEnd + TouchData.iSize; |
310 fragP = fragPEnd + TouchData.iSize; |
273 fragPEnd += TouchData.iFrequency; |
311 fragPEnd += TouchData.iFrequency; |
274 } |
312 } |
275 } |
313 } |
300 (offset + FragData.iSize) < ChunkCommitEnd; |
338 (offset + FragData.iSize) < ChunkCommitEnd; |
301 offset += FragData.iFrequency, freeBlocks++) |
339 offset += FragData.iFrequency, freeBlocks++) |
302 { |
340 { |
303 test_KErrNone(Chunk.Decommit(offset, FragData.iSize)); |
341 test_KErrNone(Chunk.Decommit(offset, FragData.iSize)); |
304 } |
342 } |
305 if (!FragData.iFragThread) |
|
306 test_Equal(FreeRam(), freeBlocks * FragData.iSize); |
|
307 |
343 |
308 if (FragData.iDiscard && CacheSizeAdjustable && !FragThreadStop) |
344 if (FragData.iDiscard && CacheSizeAdjustable && !FragThreadStop) |
309 { |
345 { |
310 TUint minCacheSize = FreeRam(); |
346 TUint minCacheSize = FreeRam(); |
311 TUint maxCacheSize = minCacheSize; |
347 TUint maxCacheSize = minCacheSize; |
312 TUint currentCacheSize; |
348 DPTest::SetCacheSize(minCacheSize, maxCacheSize); |
313 test_KErrNone(DPTest::CacheSize(OrigMinCacheSize, OrigMaxCacheSize, currentCacheSize)); |
349 if (OrigMinCacheSize <= maxCacheSize) |
314 test_KErrNone(DPTest::SetCacheSize(minCacheSize, maxCacheSize)); |
350 DPTest::SetCacheSize(OrigMinCacheSize, maxCacheSize); |
315 test_KErrNone(DPTest::SetCacheSize(OrigMinCacheSize, maxCacheSize)); |
|
316 } |
351 } |
317 } |
352 } |
318 |
353 |
319 |
354 |
320 void UnfragmentMemoryFunc() |
355 void UnfragmentMemoryFunc() |
321 { |
356 { |
322 if (FragData.iDiscard && CacheSizeAdjustable) |
357 if (FragData.iDiscard && CacheSizeAdjustable) |
323 test_KErrNone(DPTest::SetCacheSize(OrigMinCacheSize, OrigMaxCacheSize)); |
358 DPTest::SetCacheSize(OrigMinCacheSize, OrigMaxCacheSize); |
324 Chunk.Decommit(0, Chunk.MaxSize()); |
359 Chunk.Decommit(0, Chunk.MaxSize()); |
325 } |
360 } |
326 |
361 |
327 |
362 |
328 TInt FragmentMemoryThreadFunc(TAny*) |
363 TInt FragmentMemoryThreadFunc(TAny*) |
329 { |
364 { |
|
365 RThread::Rendezvous(KErrNone); // Signal that this thread has started running. |
330 while (!FragThreadStop) |
366 while (!FragThreadStop) |
331 { |
367 { |
332 FragmentMemoryFunc(); |
368 FragmentMemoryFunc(); |
333 UnfragmentMemoryFunc(); |
369 UnfragmentMemoryFunc(); |
334 } |
370 } |
344 FragData.iFrequency = aFrequency; |
380 FragData.iFrequency = aFrequency; |
345 FragData.iDiscard = aDiscard; |
381 FragData.iDiscard = aDiscard; |
346 FragData.iFragThread = aFragThread; |
382 FragData.iFragThread = aFragThread; |
347 |
383 |
348 TChunkCreateInfo chunkInfo; |
384 TChunkCreateInfo chunkInfo; |
349 chunkInfo.SetDisconnected(0, 0, FreeRam()); |
385 chunkInfo.SetDisconnected(0, 0, TotalRam); |
350 chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); |
386 chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); |
|
387 chunkInfo.SetClearByte(0x19); |
351 test_KErrNone(Chunk.Create(chunkInfo)); |
388 test_KErrNone(Chunk.Create(chunkInfo)); |
352 |
389 |
353 if (aFragThread) |
390 if (aFragThread) |
354 { |
391 { |
355 TInt r = FragThread.Create(KNullDesC, FragmentMemoryThreadFunc, KDefaultStackSize, PageSize, PageSize, NULL); |
392 TInt r = FragThread.Create(_L("FragThread"), FragmentMemoryThreadFunc, KDefaultStackSize, PageSize, PageSize, NULL); |
356 test_KErrNone(r); |
393 test_KErrNone(r); |
357 FragThread.Logon(FragStatus); |
394 FragThread.Logon(FragStatus); |
358 FragThreadStop = EFalse; |
395 FragThreadStop = EFalse; |
|
396 TRequestStatus threadInitialised; |
|
397 FragThread.Rendezvous(threadInitialised); |
359 FragThread.Resume(); |
398 FragThread.Resume(); |
|
399 User::WaitForRequest(threadInitialised); |
|
400 test_KErrNone(threadInitialised.Int()); |
360 } |
401 } |
361 else |
402 else |
362 { |
403 { |
363 FragmentMemoryFunc(); |
404 FragmentMemoryFunc(); |
364 } |
405 } |
365 if (aTouchMemory && !ManualTest) |
406 if (aTouchMemory && !ManualTest) |
366 { |
407 { |
367 TouchData.iSize = aSize; |
408 TouchData.iSize = aSize; |
368 TouchData.iFrequency = aFrequency; |
409 TouchData.iFrequency = aFrequency; |
369 TInt r = TouchThread.Create(KNullDesC, TouchMemory, KDefaultStackSize, PageSize, PageSize, NULL); |
410 TInt r = TouchThread.Create(_L("TouchThread"), TouchMemory, KDefaultStackSize, PageSize, PageSize, NULL); |
370 test_KErrNone(r); |
411 test_KErrNone(r); |
371 TouchThread.Logon(TouchStatus); |
412 TouchThread.Logon(TouchStatus); |
372 TouchDataStop = EFalse; |
413 TouchDataStop = EFalse; |
|
414 TRequestStatus threadInitialised; |
|
415 TouchThread.Rendezvous(threadInitialised); |
373 TouchThread.Resume(); |
416 TouchThread.Resume(); |
|
417 User::WaitForRequest(threadInitialised); |
|
418 test_KErrNone(threadInitialised.Int()); |
374 } |
419 } |
375 } |
420 } |
376 |
421 |
377 |
422 |
378 void UnfragmentMemory(TBool aDiscard, TBool aTouchMemory, TBool aFragThread) |
423 void UnfragmentMemory(TBool aDiscard, TBool aTouchMemory, TBool aFragThread) |
394 test_KErrNone(FragThread.ExitReason()); |
439 test_KErrNone(FragThread.ExitReason()); |
395 CLOSE_AND_WAIT(FragThread); |
440 CLOSE_AND_WAIT(FragThread); |
396 } |
441 } |
397 else |
442 else |
398 UnfragmentMemoryFunc(); |
443 UnfragmentMemoryFunc(); |
|
444 if (CacheSizeAdjustable) |
|
445 test_KErrNone(DPTest::SetCacheSize(OrigMinCacheSize, OrigMaxCacheSize)); |
399 CLOSE_AND_WAIT(Chunk); |
446 CLOSE_AND_WAIT(Chunk); |
400 } |
447 } |
401 |
448 |
402 |
449 |
403 void TestFillPhysicalRam(TUint aFragSize, TUint aFragFreq, TUint aAllocSize, TUint aAllocAlign, TBool aDiscard, TBool aTouchMemory) |
450 void TestFillPhysicalRam(TUint aFragSize, TUint aFragFreq, TUint aAllocSize, TUint aAllocAlign, TBool aDiscard, TBool aTouchMemory) |
405 test.Printf(_L("TestFillPhysicalRam aFragSize 0x%x aFragFreq 0x%x aAllocSize 0x%x aAllocAlign %d dis %d touch %d\n"), |
452 test.Printf(_L("TestFillPhysicalRam aFragSize 0x%x aFragFreq 0x%x aAllocSize 0x%x aAllocAlign %d dis %d touch %d\n"), |
406 aFragSize, aFragFreq, aAllocSize, aAllocAlign, aDiscard, aTouchMemory); |
453 aFragSize, aFragFreq, aAllocSize, aAllocAlign, aDiscard, aTouchMemory); |
407 FragmentMemory(aFragSize, aFragFreq, aDiscard, aTouchMemory, EFalse); |
454 FragmentMemory(aFragSize, aFragFreq, aDiscard, aTouchMemory, EFalse); |
408 SPhysAllocData allocData; |
455 SPhysAllocData allocData; |
409 // Only check free all ram could be allocated in manual tests as fixed pages may be fragmented. |
456 // Only check free all ram could be allocated in manual tests as fixed pages may be fragmented. |
410 allocData.iCheckMaxAllocs = (ManualTest && !aTouchMemory && !aAllocAlign)? ETrue : EFalse; |
457 allocData.iCheckMaxAllocs = (ManualTest && !aTouchMemory && !aAllocAlign); |
411 allocData.iCheckFreeRam = ETrue; |
458 allocData.iCheckFreeRam = ETrue; |
412 allocData.iSize = aAllocSize; |
459 allocData.iSize = aAllocSize; |
413 allocData.iAlign = aAllocAlign; |
460 allocData.iAlign = aAllocAlign; |
414 FillPhysicalRam(&allocData); |
461 TInt r = FillPhysicalRam(&allocData); |
|
462 test_Value(r, r >= 0); |
415 UnfragmentMemory(aDiscard, aTouchMemory, EFalse); |
463 UnfragmentMemory(aDiscard, aTouchMemory, EFalse); |
416 } |
464 } |
417 |
465 |
418 |
466 |
419 void TestFragmentedAllocation() |
467 void TestFragmentedAllocation() |
490 User::CommandLine(cmdLine); |
538 User::CommandLine(cmdLine); |
491 cmdLine.LowerCase(); |
539 cmdLine.LowerCase(); |
492 ManualTest = cmdLine.Find(KManual) != KErrNotFound; |
540 ManualTest = cmdLine.Find(KManual) != KErrNotFound; |
493 } |
541 } |
494 |
542 |
495 // Turn off lazy dll unloading so the free ram checking isn't affected. |
543 // Turn off lazy dll unloading and ensure any supervisor clean up has completed |
|
544 // so the free ram checking isn't affected. |
496 RLoader l; |
545 RLoader l; |
497 test(l.Connect()==KErrNone); |
546 test(l.Connect()==KErrNone); |
498 test(l.CancelLazyDllUnload()==KErrNone); |
547 test(l.CancelLazyDllUnload()==KErrNone); |
499 l.Close(); |
548 l.Close(); |
500 |
549 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); |
501 InitFreeRam=FreeRam(); |
550 |
502 test.Printf(_L("Free RAM=%08x, Page size=%x, Page shift=%d\n"),InitFreeRam,PageSize,PageShift); |
551 test_KErrNone(HAL::Get(HAL::EMemoryRAM, TotalRam)); |
|
552 |
|
553 test.Printf(_L("Free RAM=%08x, Page size=%x, Page shift=%d\n"),FreeRam(),PageSize,PageShift); |
503 |
554 |
504 test.Next(_L("Open test LDD")); |
555 test.Next(_L("Open test LDD")); |
505 r=Shadow.Open(); |
556 r=Shadow.Open(); |
506 test(r==KErrNone); |
557 test(r==KErrNone); |
507 |
558 |
511 test.Next(_L("TestClaimPhys")); |
562 test.Next(_L("TestClaimPhys")); |
512 TestClaimPhys(); |
563 TestClaimPhys(); |
513 |
564 |
514 if (memodel >= EMemModelTypeFlexible) |
565 if (memodel >= EMemModelTypeFlexible) |
515 { |
566 { |
|
567 // To stop these tests taking too long leave only 8MB of RAM free. |
|
568 const TUint KFreePages = 2048; |
|
569 test.Next(_L("Load gobbler LDD")); |
|
570 TInt r = User::LoadLogicalDevice(KGobblerLddFileName); |
|
571 test_Value(r, r == KErrNone || r == KErrAlreadyExists); |
|
572 RGobbler gobbler; |
|
573 r = gobbler.Open(); |
|
574 test_KErrNone(r); |
|
575 TUint32 taken = gobbler.GobbleRAM(KFreePages * PageSize); |
|
576 test.Printf(_L("Gobbled: %dK\n"), taken/1024); |
|
577 test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam()); |
|
578 |
516 test.Next(_L("TestFragmentedAllocation")); |
579 test.Next(_L("TestFragmentedAllocation")); |
517 TestFragmentedAllocation(); |
580 TestFragmentedAllocation(); |
518 |
581 |
519 test.Next(_L("TestMultipleContiguousAllocations")); |
582 test.Next(_L("TestMultipleContiguousAllocations")); |
520 TestMultipleContiguousAllocations(20, PageSize * 16, 0); |
583 TestMultipleContiguousAllocations(20, PageSize * 16, 0); |
553 TestMultipleContiguousAllocations(20, PageSize * 512, PageShift + 8); |
616 TestMultipleContiguousAllocations(20, PageSize * 512, PageShift + 8); |
554 UnfragmentMemory(ETrue, EFalse, ETrue); |
617 UnfragmentMemory(ETrue, EFalse, ETrue); |
555 FragmentMemory(PageSize * 32, PageSize * 64, ETrue, EFalse, ETrue); |
618 FragmentMemory(PageSize * 32, PageSize * 64, ETrue, EFalse, ETrue); |
556 TestMultipleContiguousAllocations(20, PageSize * 1024, PageShift + 10); |
619 TestMultipleContiguousAllocations(20, PageSize * 1024, PageShift + 10); |
557 UnfragmentMemory(ETrue, EFalse, ETrue); |
620 UnfragmentMemory(ETrue, EFalse, ETrue); |
|
621 |
|
622 gobbler.Close(); |
|
623 r = User::FreeLogicalDevice(KGobblerLddFileName); |
|
624 test_KErrNone(r); |
558 } |
625 } |
559 |
626 |
560 Shadow.Close(); |
627 Shadow.Close(); |
|
628 r = User::FreeLogicalDevice(KLddFileName); |
|
629 test_KErrNone(r); |
561 test.Printf(_L("Free RAM=%08x at end of test\n"),FreeRam()); |
630 test.Printf(_L("Free RAM=%08x at end of test\n"),FreeRam()); |
562 test.End(); |
631 test.End(); |
563 return(KErrNone); |
632 return(KErrNone); |
564 } |
633 } |