First public contribution.
1 // Copyright (c) 1995-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\mmu\t_chunk.cpp
15 // Tests on RChunk objects in connection with demand paging.
16 // Tests exercise the locking, unlocking, commiting and decommiting of
17 // pages to chunk objects.
18 // 1 Check Unlocked page gets counted as free memory
19 // 2 Check Unlock/Lock preserves page contents
20 // 3 Tests at chunk offset '0'
21 // 4 Check Lock is idempotent
22 // 5 Check non page aligned Unlock/Lock
23 // 6 Check unlocked pages get reclaimed for new memory allocation
24 // 7 Check reclaimed memory is unmapped from original location
25 // 8 Check Lock fails when memory is reclaimed
26 // 9 Check Lock failure Decommits memory
27 // 10 Recommit memory to chunk
28 // 11 Check Commit on unlocked pages
29 // 12 Check Commit on unlocked and reclaimed pages
31 // 14 Tests at chunk offset 'PageSize'
32 // 15 Check Lock is idempotent
33 // 16 Check non page aligned Unlock/Lock
34 // 17 Check unlocked pages get reclaimed for new memory allocation
35 // 18 Check reclaimed memory is unmapped from original location
36 // 19 Check Lock fails when memory is reclaimed
37 // 20 Check Lock failure Decommits memory
38 // 21 Recommit memory to chunk
39 // 22 Check Commit on unlocked pages
40 // 23 Check Commit on unlocked and reclaimed pages
42 // 25 Tests at chunk offset '0x100000-PageSize'
43 // 26 Check Lock is idempotent
44 // 27 Check non page aligned Unlock/Lock
45 // 28 Check unlocked pages get reclaimed for new memory allocation
46 // 29 Check reclaimed memory is unmapped from original location
47 // 30 Check Lock fails when memory is reclaimed
48 // 31 Check Lock failure Decommits memory
49 // 32 Recommit memory to chunk
50 // 33 Check Commit on unlocked pages
51 // 34 Check Commit on unlocked and reclaimed pages
53 // 36 Tests at chunk offset '0x400000-PageSize'
54 // 37 Check Lock is idempotent
55 // 38 Check non page aligned Unlock/Lock
56 // 39 Check unlocked pages get reclaimed for new memory allocation
57 // 40 Check reclaimed memory is unmapped from original location
58 // 41 Check Lock fails when memory is reclaimed
59 // 42 Check Lock failure Decommits memory
60 // 43 Recommit memory to chunk
61 // 44 Check Commit on unlocked pages
62 // 45 Check Commit on unlocked and reclaimed pages
66 // 49 Close chunk with unlocked pages which have been flushed
70 //! @SYMTestCaseID KBASE-T_CACHECHUNK-0336
73 //! @SYMTestCaseDesc Demand Paging Loader Stress Tests
74 //! @SYMTestActions 0 Commit all of memory
75 //! @SYMTestExpectedResults All tests should pass.
76 //! @SYMTestPriority High
77 //! @SYMTestStatus Implemented
79 #define __E32TEST_EXTENSION__
85 #include "mmudetect.h"
86 #include "d_memorytest.h"
91 LOCAL_D RTest test(_L("T_CACHECHUNK"));
93 RMemoryTestLdd MemoryTest;
96 TUint8* TestChunkBase;
104 void FillPage(TUint aOffset)
106 TUint8* ptr = TestChunkBase+aOffset;
107 TUint8* ptrEnd = ptr+PageSize;
108 do *((TUint32*&)ptr)++ = aOffset+=4;
113 TBool CheckPage(TUint aOffset)
115 TUint8* ptr = TestChunkBase+aOffset;
116 TUint8* ptrEnd = ptr+PageSize;
117 do if(*((TUint32*&)ptr)++ != (aOffset+=4)) break;
123 TBool CheckPages(TUint aOffset, TInt aNumPages)
126 if(!CheckPage(aOffset+=PageSize))
132 TBool IsPageMapped(TUint aOffset)
135 TInt r=MemoryTest.ReadMemory(TestChunkBase+aOffset,value);
140 void Tests(TInt aOffset)
142 if(aOffset+5*PageSize>=CommitEnd)
144 test.Start(_L("TEST NOT RUN - Not enough system RAM"));
151 TUint origChunkSize = TestChunk.Size();
153 test.Start(_L("Check Unlock is idempotent"));
154 r = TestChunk.Unlock(aOffset+PageSize,PageSize);
157 test(freeRam==NoFreeRam+PageSize);
158 r = TestChunk.Unlock(aOffset+PageSize,PageSize);
160 test_Equal(FreeRam(), freeRam);
161 // Ensure unlock on reclaimed pages is idempotent
162 TInt flushSupported = UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
163 r = TestChunk.Unlock(aOffset+PageSize,PageSize);
165 test_Equal(FreeRam(), freeRam);
166 test_Equal(origChunkSize, TestChunk.Size());
168 if (flushSupported == KErrNotSupported)
169 {// Flush cache not supported so lock won't fail so no need to recommit the pages.
170 test_KErrNone(TestChunk.Lock(aOffset+PageSize,PageSize));
173 {// Recommit the reclaimed pages.
174 test_KErrNone(flushSupported);
175 test_Equal(KErrNotFound, TestChunk.Lock(aOffset+PageSize,PageSize));
176 test_KErrNone(TestChunk.Commit(aOffset+PageSize,PageSize));
179 test.Next(_L("Check Lock is idempotent"));
180 r = TestChunk.Lock(aOffset,3*PageSize);
183 test(freeRam==NoFreeRam);
184 CheckPages(aOffset,3);
185 r = TestChunk.Lock(aOffset,3*PageSize);
187 CheckPages(aOffset,3);
189 test(freeRam==NoFreeRam);
190 test_Equal(origChunkSize, TestChunk.Size());
192 test.Next(_L("Check non page aligned Unlock/Lock"));
193 r = TestChunk.Unlock(aOffset+PageSize-1,1);
196 test(freeRam==NoFreeRam+PageSize);
197 r = TestChunk.Lock(aOffset+PageSize-1,1);
200 test(freeRam==NoFreeRam);
201 r = TestChunk.Unlock(aOffset+PageSize-1,2);
204 test(freeRam==NoFreeRam+PageSize*2);
205 r = TestChunk.Lock(aOffset+PageSize-1,2);
208 test(freeRam==NoFreeRam);
209 test_Equal(origChunkSize, TestChunk.Size());
211 test.Next(_L("Check unlocked pages get reclaimed for new memory allocation"));
212 r=TestChunk.Commit(CommitEnd,PageSize);
213 test(r==KErrNoMemory);
214 r = TestChunk.Unlock(aOffset,4*PageSize);
217 test(freeRam==NoFreeRam+PageSize*4);
218 r=TestChunk.Commit(CommitEnd,PageSize);
221 test(freeRam<NoFreeRam+PageSize*4);
222 r=TestChunk.Decommit(CommitEnd,PageSize);
225 test(freeRam==NoFreeRam+PageSize*4);
226 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); // make sure unlocked page is gone
228 test(freeRam==NoFreeRam+PageSize*4);
230 #ifndef __WINS__ // wins fakery doesn't actually do this
231 test.Next(_L("Check reclaimed memory is unmapped and decommitted from original location"));
232 TInt mappedPages = IsPageMapped(aOffset+PageSize*0);
233 mappedPages += IsPageMapped(aOffset+PageSize*1);
234 mappedPages += IsPageMapped(aOffset+PageSize*2);
235 mappedPages += IsPageMapped(aOffset+PageSize*3);
240 test(CheckPage(aOffset+PageSize*-1)); // should be left mapped
242 test(CheckPage(aOffset+PageSize*4)); // should be left mapped
244 test.Next(_L("Check Lock fails when memory is reclaimed"));
245 r = TestChunk.Lock(aOffset,4*PageSize);
246 test(r==KErrNotFound);
248 test(freeRam==NoFreeRam+PageSize*4);
250 test.Next(_L("Check Lock failure Decommits memory"));
251 test(!IsPageMapped(aOffset+PageSize*0));
252 test(!IsPageMapped(aOffset+PageSize*1));
253 test(!IsPageMapped(aOffset+PageSize*2));
254 test(!IsPageMapped(aOffset+PageSize*3));
255 test_Equal(origChunkSize-PageSize*4, TestChunk.Size());
257 test.Next(_L("Recommit memory to chunk"));
259 for(offset=aOffset; offset<aOffset+PageSize*4; offset+=PageSize)
261 r=TestChunk.Commit(offset,PageSize);
266 test(freeRam==NoFreeRam);
267 test_Equal(origChunkSize, TestChunk.Size());
269 test.Next(_L("Check Commit on unlocked pages"));
270 r = TestChunk.Unlock(aOffset,4*PageSize);
273 test(freeRam>=NoFreeRam+PageSize*4);
274 r=TestChunk.Commit(aOffset,4*PageSize);
275 test(r==KErrAlreadyExists);
277 test(freeRam>=NoFreeRam+PageSize*4);
278 test_Equal(origChunkSize, TestChunk.Size());
280 test.Next(_L("Check Commit on unlocked and reclaimed pages"));
281 // unlock and force a page to be reclaimed...
282 r=TestChunk.Commit(CommitEnd,PageSize);
284 r=TestChunk.Decommit(CommitEnd,PageSize);
286 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); // make sure unlocked page is gone
288 test(freeRam>=NoFreeRam+PageSize*4);
289 // check can't commit any pages (because they are unlocked, not decommitted)...
290 r=TestChunk.Commit(aOffset+PageSize*0,PageSize);
291 test(r==KErrAlreadyExists);
292 r=TestChunk.Commit(aOffset+PageSize*1,PageSize);
293 test(r==KErrAlreadyExists);
294 r=TestChunk.Commit(aOffset+PageSize*2,PageSize);
295 test(r==KErrAlreadyExists);
296 r=TestChunk.Commit(aOffset+PageSize*3,PageSize);
297 test(r==KErrAlreadyExists);
299 test(freeRam>=NoFreeRam+PageSize*4);
300 test_Equal(origChunkSize, TestChunk.Size());
301 // Restore the chunk to original size.
302 r = TestChunk.Lock(aOffset,4*PageSize);
303 test_Equal(r, KErrNotFound);
305 test_Compare(freeRam, >=, NoFreeRam+PageSize*4);
306 test_Equal(origChunkSize - PageSize*4, TestChunk.Size());
307 r = TestChunk.Commit(aOffset, PageSize*4);
310 test.Next(_L("Check Decommit on unlocked pages"));
311 r = TestChunk.Unlock(aOffset,PageSize*4);
313 test(FreeRam() >= NoFreeRam+PageSize*4);
314 r=TestChunk.Decommit(aOffset, PageSize*4);
317 test_Compare(freeRam, >=, NoFreeRam+PageSize*4);
318 test_Equal(origChunkSize - PageSize*4, TestChunk.Size());
319 // Restore chunk back to original state
320 r = TestChunk.Commit(aOffset, PageSize*4);
322 test(FreeRam() == NoFreeRam);
324 test.Next(_L("Check Decommit on unlocked and reclaimed pages"));
325 r = TestChunk.Unlock(aOffset,PageSize*4);
328 test_Compare(freeRam, >=, NoFreeRam+PageSize*4);
329 r=TestChunk.Commit(CommitEnd,PageSize);
331 r=TestChunk.Decommit(CommitEnd,PageSize);
333 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0); // make sure unlocked page is gone
335 test_Compare(freeRam, >=, NoFreeRam+PageSize*4);
336 r=TestChunk.Decommit(aOffset, PageSize*4);
339 test_Compare(freeRam, >=, NoFreeRam+PageSize*4);
340 test_Equal(origChunkSize - PageSize*4, TestChunk.Size());
342 test.Next(_L("Restore chunk"));
343 test_Equal(origChunkSize-PageSize*4, TestChunk.Size());
344 for(offset=aOffset; offset<aOffset+PageSize*4; offset+=PageSize)
346 r=TestChunk.Commit(offset,PageSize);
351 test(freeRam==NoFreeRam);
352 test_Equal(origChunkSize, TestChunk.Size());
359 void TestBenchmarks()
361 TInt r = TestChunk.Unlock(0,CommitEnd); // start with everthing unlocked
363 TInt testSizes[] = { PageSize,1<<16,1<<20,0 };
364 TInt* sizes = testSizes;
366 while((size=*sizes++)!=0)
368 TRequestStatus status;
369 Timer.After(status,1);
370 User::WaitForRequest(status);
371 TInt KRunTime = 1*1000*1000;
372 Timer.After(status,KRunTime);
374 while(status==KRequestPending)
376 r = TestChunk.Lock(0,size);
378 r = TestChunk.Unlock(0,size);
382 User::WaitForRequest(status);
383 test.Printf(_L("Unlock/Lock of %d kB takes %d us\n"),size>>10,KRunTime/count);
391 // we start with TestChunk being locked and no or little free RAM
392 // (hence live list should be close to minimum size.)
398 TInt r = DPTest::CacheSize(min,max,cur);
400 // manipulate demand paging live list so we end up with zero old pages...
402 r = TestChunk.Unlock(0,min*2); // dump 2*min bytes at start of live list
404 // live list now cur+2*min bytes
406 r = TestChunk.Commit(CommitEnd,cur); // use up 'cur' bytes of RAM from end of live list
408 // live list now 2*min bytes of pages which were unlocked from our test chunk
410 // lock pages until free RAM is <= 2 pages.
411 // this should remove all of the 'old' pages
413 while(FreeRam()>2*PageSize)
415 TestChunk.Lock(i,PageSize);
419 // live list now min+2*PageSize bytes, with no old pages
421 // now commit memory, which forces allocation from the demand paging live list
422 // which doesn't have any old pages (the purpose of this test)...
426 r = TestChunk.Commit(CommitEnd+min+extra,PageSize);
433 // restore commit state...
434 r = TestChunk.Decommit(CommitEnd,min+extra);
436 r = TestChunk.Decommit(0,min*2);
438 r = TestChunk.Commit(0,min*2);
450 test.Printf(_L("This test requires an MMU\n"));
453 test.Start(_L("Initialise test"));
454 test.Next(_L("Load gobbler LDD"));
455 TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
456 test(r==KErrNone || r==KErrAlreadyExists);
460 TUint32 taken = gobbler.GobbleRAM(496*1024*1024);
461 test.Printf(_L("Gobbled: %dK\n"), taken/1024);
462 test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
464 test_KErrNone(HAL::Get(HAL::EMemoryPageSize,PageSize));
466 test_KErrNone(HAL::Get(HAL::EMemoryRAM, totalRAM));
468 test.Printf(_L("totalRAM=%dK\n"), totalRAM/1024);
470 test(KErrNone==MemoryTest.Open());
471 // Create the test chunk. It must not be paged otherwise
472 // unlocking its pages will have no effect.
473 TChunkCreateInfo createInfo;
474 createInfo.SetCache(totalRAM);
475 test_KErrNone(TestChunk.Create(createInfo));
476 TestChunkBase = TestChunk.Base();
478 test(KErrNone==Timer.CreateLocal());
479 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
481 test.Next(_L("Commit all of memory"));
483 while(KErrNone==(r=TestChunk.Commit(CommitEnd,PageSize)))
486 CommitEnd += PageSize;
488 test(r==KErrNoMemory);
489 NoFreeRam = FreeRam();
490 test(NoFreeRam<=PageSize);
492 test.Next(_L("Check Unlocked page gets counted as free memory"));
493 r = TestChunk.Unlock(0,PageSize);
495 TInt freeRam = FreeRam();
496 test(freeRam==NoFreeRam+PageSize);
497 r = TestChunk.Lock(0,PageSize);
500 test(freeRam==NoFreeRam);
502 test.Next(_L("Check Unlock/Lock preserves page contents"));
504 for(offset=0; offset<CommitEnd; offset+=PageSize)
506 test(CheckPage(offset));
507 r = TestChunk.Unlock(offset,PageSize);
509 r = TestChunk.Lock(offset,PageSize);
511 test(CheckPage(offset));
513 test(freeRam==NoFreeRam);
516 test.Next(_L("Tests at chunk offset '0'"));
518 test.Next(_L("Tests at chunk offset 'PageSize'"));
520 test.Next(_L("Tests at chunk offset '0x100000-PageSize'"));
521 Tests(0x100000-PageSize);
522 test.Next(_L("Tests at chunk offset '0x400000-PageSize'"));
523 Tests(0x400000-PageSize);
525 // Remove limit on max size of live list
526 TUint originalMin = 0;
527 TUint originalMax = 0;
528 TUint currentSize = 0;
529 r = DPTest::CacheSize(originalMin, originalMax, currentSize);
530 test(r == KErrNone || r == KErrNotSupported);
531 TBool resizeCache = r == KErrNone;
533 test_KErrNone(DPTest::SetCacheSize(originalMin, KMaxTUint));
535 test.Next(_L("Big Unlock/Lock"));
536 r = TestChunk.Unlock(0,CommitEnd);
539 test(freeRam>=NoFreeRam+CommitEnd);
540 r = TestChunk.Lock(0,CommitEnd);
543 test_Equal(NoFreeRam, freeRam);
547 test.Next(_L("Check Unlock of old pages doesn't cause problems"));
551 test.Next(_L("Benchmarks..."));
554 test.Next(_L("Close chunk with unlocked pages which have been flushed"));
555 r = TestChunk.Unlock(0,CommitEnd);
557 UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
560 test.Next(_L("Check can't lock/unlock non-cache chunks"));
562 test_KErrNone(chunk.CreateDisconnectedLocal(0,PageSize,2*PageSize));
563 test_Equal(KErrGeneral,chunk.Lock(PageSize,PageSize));
564 test_Equal(KErrGeneral,chunk.Unlock(0,PageSize));
567 // Restore original settings for live list size
569 test_KErrNone(DPTest::SetCacheSize(originalMin, originalMax));