|
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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\heap\t_page_alloc.cpp |
|
15 // Overview: |
|
16 // Tests RHeap class. |
|
17 // API Information: |
|
18 // RHeap |
|
19 // Details: |
|
20 // - Tests that the page bitmap is consistent (i.e. encoded sizes are sensible and |
|
21 // encoded in the correct fashion. |
|
22 // - Tests that pages which appear in the page bitmap are present in memory by |
|
23 // reading them. |
|
24 // -Tests that other pages are not readable |
|
25 // - Tests page bitmap by creating an allocator where all allocations >= 4kB use |
|
26 // paged allocator, allocating a large number of regions of various sizes (from |
|
27 // 4 kB to b MB), checking that the walk function finds them all correctly, freeing |
|
28 // some of them, checking the walk function again, and so on. |
|
29 // Platforms/Drives/Compatibility: |
|
30 // All |
|
31 // Assumptions/Requirement/Pre-requisites: |
|
32 // Failures and causes: |
|
33 // Base Port information: |
|
34 // |
|
35 // |
|
36 |
|
37 #include <e32test.h> |
|
38 #include <e32hal.h> |
|
39 #include <e32def.h> |
|
40 #include <e32math.h> |
|
41 #include <e32def_private.h> |
|
42 #include "dla.h" |
|
43 #include "slab.h" |
|
44 #include "page_alloc.h" |
|
45 #include "heap_hybrid.h" |
|
46 |
|
47 |
|
48 struct TMetaData |
|
49 { |
|
50 TBool iDLOnly; |
|
51 RFastLock* iLock; |
|
52 TInt iChunkSize; |
|
53 TInt iSlabThreshold; |
|
54 unsigned iSlabInitThreshold; |
|
55 unsigned iSlabConfigBits; |
|
56 slab* iPartialPage; |
|
57 slab* iFullSlab; |
|
58 page* iSparePage; |
|
59 TUint8* iMemBase; |
|
60 unsigned char iSizeMap[(MAXSLABSIZE>>2)+1]; |
|
61 slabset iSlabAlloc[MAXSLABSIZE>>2]; |
|
62 slab** iSlabAllocRealRootAddress[MAXSLABSIZE>>2]; |
|
63 }; |
|
64 |
|
65 LOCAL_D RTest test(_L("T_HEAPPAGEALLOC")); |
|
66 |
|
67 class TestHybridHeap |
|
68 { |
|
69 public: |
|
70 static TUint8* MemBase(const RHybridHeap * aHybridHeap); |
|
71 static void GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta); |
|
72 }; |
|
73 |
|
74 TUint8* TestHybridHeap::MemBase(const RHybridHeap * aHybridHeap) |
|
75 { |
|
76 return aHybridHeap->iMemBase; |
|
77 } |
|
78 |
|
79 void TestHybridHeap::GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta) |
|
80 { |
|
81 RHybridHeap::STestCommand cmd; |
|
82 cmd.iCommand = RHybridHeap::EHeapMetaData; |
|
83 TInt ret = aHeap.DebugFunction(RHeap::EHybridHeap, &cmd, 0); |
|
84 test(ret == KErrNone); |
|
85 |
|
86 RHybridHeap* hybridHeap = (RHybridHeap*) cmd.iData; |
|
87 |
|
88 aMeta.iDLOnly = hybridHeap->iDLOnly; |
|
89 aMeta.iLock = &hybridHeap->iLock; |
|
90 aMeta.iChunkSize = hybridHeap->iChunkSize; |
|
91 aMeta.iSlabThreshold = hybridHeap->iSlabThreshold; |
|
92 aMeta.iSlabInitThreshold = hybridHeap->iSlabInitThreshold; |
|
93 aMeta.iSlabConfigBits = hybridHeap->iSlabConfigBits; |
|
94 aMeta.iPartialPage = hybridHeap->iPartialPage; |
|
95 aMeta.iFullSlab = hybridHeap->iFullSlab; |
|
96 aMeta.iSparePage = hybridHeap->iSparePage; |
|
97 aMeta.iMemBase = hybridHeap->iMemBase; |
|
98 |
|
99 TInt i; |
|
100 TInt count; |
|
101 count = sizeof(aMeta.iSizeMap)/sizeof(unsigned char); |
|
102 for (i=0; i<count; ++i) |
|
103 { |
|
104 aMeta.iSizeMap[i] = hybridHeap->iSizeMap[i]; |
|
105 } |
|
106 count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset); |
|
107 for (i=0; i<count; ++i) |
|
108 { |
|
109 aMeta.iSlabAlloc[i].iPartial = hybridHeap->iSlabAlloc[i].iPartial; |
|
110 aMeta.iSlabAllocRealRootAddress[i] = &hybridHeap->iSlabAlloc[i].iPartial; |
|
111 } |
|
112 } |
|
113 |
|
114 LOCAL_C void GetMeta(RHeap& aHeap, TMetaData& aMeta) |
|
115 { |
|
116 TestHybridHeap::GetHeapMetaData(aHeap, aMeta); |
|
117 } |
|
118 |
|
119 class TestRHeap : public RHeap |
|
120 { |
|
121 public: |
|
122 void InitTests(); |
|
123 void Test1(void); |
|
124 void Test2(void); |
|
125 void Test3(void); |
|
126 void CloseTests(); |
|
127 TUint GetRandomSize(TUint aMaxSize); |
|
128 TUint GetRandomIndex(TUint aMaxIndex); |
|
129 static void WalkCallback(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen); |
|
130 TBool CheckWalkArrayEmpty(); |
|
131 |
|
132 private: |
|
133 RHybridHeap* iHybridHeap; |
|
134 RHeap *iHeap; |
|
135 TUint8* iMemBase; // bottom of Paged/Slab memory (chunk base) |
|
136 static TUint iWalkArraySize; |
|
137 static TUint iWalkArrayIndex; |
|
138 static TAny** iWalkArrayOfCells; |
|
139 TUint iAllocatedArrayIndex; |
|
140 TAny** iAllocatedArrayOfCells; |
|
141 }; |
|
142 |
|
143 TUint TestRHeap::iWalkArraySize = 100; |
|
144 TUint TestRHeap::iWalkArrayIndex = 0; |
|
145 TAny** TestRHeap::iWalkArrayOfCells = new TAny*[iWalkArraySize]; |
|
146 |
|
147 void TestRHeap::InitTests() |
|
148 { |
|
149 // Allocate a chunk heap |
|
150 TPtrC testHeap=_L("TESTHEAP"); |
|
151 iHeap=User::ChunkHeap(&testHeap,0x1800,0x800000); |
|
152 RHybridHeap::STestCommand cmd; |
|
153 cmd.iCommand = RHybridHeap::EHeapMetaData; |
|
154 iHeap->DebugFunction(RHeap::EHybridHeap, &cmd, 0); |
|
155 iHybridHeap = (RHybridHeap*) cmd.iData; |
|
156 iMemBase = TestHybridHeap::MemBase(iHybridHeap); |
|
157 |
|
158 // configure paged heap threshold 16 kB |
|
159 cmd.iCommand = RHybridHeap::ESetConfig; |
|
160 cmd.iConfig.iSlabBits = 0x0; //0xabe |
|
161 cmd.iConfig.iDelayedSlabThreshold = 0x40000000; |
|
162 cmd.iConfig.iPagePower = 14; |
|
163 test(iHeap->DebugFunction(RHeap::EHybridHeap, &cmd, 0) == KErrNone); |
|
164 } |
|
165 |
|
166 |
|
167 TUint TestRHeap::GetRandomSize(TUint aMaxSize) |
|
168 { |
|
169 TUint size = 0; |
|
170 do |
|
171 { |
|
172 size = Math::Random() & aMaxSize; |
|
173 } |
|
174 while(size < 16384 || size > aMaxSize ); |
|
175 // subtract debug header size |
|
176 return size - 8; |
|
177 } |
|
178 |
|
179 |
|
180 TUint TestRHeap::GetRandomIndex(TUint aMaxIndex) |
|
181 { |
|
182 TUint index = 0; |
|
183 do |
|
184 { |
|
185 index = Math::Random() & 0x7F; |
|
186 } |
|
187 while(index >= aMaxIndex || iWalkArrayOfCells[index] == 0); |
|
188 |
|
189 return index; |
|
190 } |
|
191 |
|
192 |
|
193 void TestRHeap::WalkCallback(TAny* aPtr, TCellType aCellType, TAny* aBuffer, TInt aLen) |
|
194 { |
|
195 if (aLen>16375 && aPtr>0) // Don't test DL allocator |
|
196 test(aCellType == EGoodAllocatedCell); |
|
197 |
|
198 TUint i = 0; |
|
199 for(i=0; i<iWalkArrayIndex; i++) |
|
200 { |
|
201 if(iWalkArrayOfCells[i] == aBuffer) |
|
202 { |
|
203 iWalkArrayOfCells[i] = NULL; |
|
204 break; |
|
205 } |
|
206 } |
|
207 } |
|
208 |
|
209 TBool TestRHeap::CheckWalkArrayEmpty() |
|
210 { |
|
211 TUint i = 0; |
|
212 for(i=0; i<iWalkArrayIndex; i++) |
|
213 { |
|
214 if(iWalkArrayOfCells[i]) |
|
215 { |
|
216 return EFalse; |
|
217 } |
|
218 } |
|
219 return ETrue; |
|
220 } |
|
221 |
|
222 |
|
223 /////////////////////////////////////////////////////////// |
|
224 // Test page allocation with various sizes, 16 kB - 8 MB // |
|
225 // Simple test with fixed sizes. // |
|
226 /////////////////////////////////////////////////////////// |
|
227 void TestRHeap::Test1(void) |
|
228 { |
|
229 // Allocate and free single paged buffers of different size |
|
230 // Small buffer |
|
231 TAny* p1 = NULL; |
|
232 p1=iHeap->Alloc(0x4000); |
|
233 test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap); |
|
234 test(iHeap->Count() == 1); |
|
235 iHeap->Free(p1); |
|
236 p1 = NULL; |
|
237 test(iHeap->Count() == 0); |
|
238 |
|
239 // Medium buffer |
|
240 p1=iHeap->Alloc(0x20000); |
|
241 test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap); |
|
242 test(iHeap->Count() == 1); |
|
243 iHeap->Free(p1); |
|
244 p1 = NULL; |
|
245 test(iHeap->Count() == 0); |
|
246 |
|
247 // Large buffer |
|
248 p1=iHeap->Alloc(0x700000); |
|
249 test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap); |
|
250 test(iHeap->Count() == 1); |
|
251 iHeap->Free(p1); |
|
252 p1 = NULL; |
|
253 test(iHeap->Count() == 0); |
|
254 |
|
255 // Oversized buffer, not allocated |
|
256 p1=iHeap->Alloc(0x900000); |
|
257 test(p1 == NULL); |
|
258 test(iHeap->Count() == 0); |
|
259 } |
|
260 |
|
261 |
|
262 /////////////////////////////////////////////////////////////////////////// |
|
263 // Allocate and free multiple random sized buffers, sizes under 65 kB. // |
|
264 // Check that all are allocated succesfully with Count. Free every other // |
|
265 // of them, check the Count. Allocate more buffers sized under 655 kB // |
|
266 // and free all buffers in reverse order. Check all are freed. // |
|
267 /////////////////////////////////////////////////////////////////////////// |
|
268 void TestRHeap::Test2(void) |
|
269 { |
|
270 TInt ArraySize=10; |
|
271 TInt ArrayIndex; |
|
272 TAny** ArrayOfCells; |
|
273 ArrayOfCells = new TAny*[ArraySize]; |
|
274 |
|
275 // Allocate set of buffers |
|
276 for(ArrayIndex=0; ArrayIndex<ArraySize; ArrayIndex++) |
|
277 { |
|
278 ArrayOfCells[ArrayIndex] = 0; |
|
279 ArrayOfCells[ArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF)); |
|
280 test(ArrayOfCells[ArrayIndex] != NULL); |
|
281 } |
|
282 test(iHeap->Count() == 10); |
|
283 |
|
284 // Free every other |
|
285 for(ArrayIndex=0; ArrayIndex<ArraySize; ArrayIndex=ArrayIndex+2 ) |
|
286 { |
|
287 iHeap->Free(ArrayOfCells[ArrayIndex]); |
|
288 ArrayOfCells[ArrayIndex] = 0; |
|
289 } |
|
290 test(iHeap->Count() == 5); |
|
291 |
|
292 TInt ArraySize2=10; |
|
293 TInt ArrayIndex2; |
|
294 TAny** ArrayOfCells2; |
|
295 ArrayOfCells2 = new TAny*[ArraySize2]; |
|
296 |
|
297 // Allocate larger buffers |
|
298 for(ArrayIndex2=0; ArrayIndex2<ArraySize; ArrayIndex2++) |
|
299 { |
|
300 ArrayOfCells2[ArrayIndex2] = 0; |
|
301 ArrayOfCells2[ArrayIndex2] = iHeap->Alloc(GetRandomSize(0x7FFFF)); |
|
302 test(ArrayOfCells2[ArrayIndex2] != NULL); |
|
303 } |
|
304 test(iHeap->Count() == 15); |
|
305 |
|
306 // Free all buffers in reverse order |
|
307 for(ArrayIndex=9; ArrayIndex>=0; ArrayIndex-- ) |
|
308 { |
|
309 if(ArrayOfCells[ArrayIndex] != 0) |
|
310 { |
|
311 iHeap->Free(ArrayOfCells[ArrayIndex]); |
|
312 ArrayOfCells[ArrayIndex] = 0; |
|
313 } |
|
314 } |
|
315 for(ArrayIndex2=9; ArrayIndex2>=0; ArrayIndex2-- ) |
|
316 { |
|
317 if(ArrayOfCells2[ArrayIndex2] != 0) |
|
318 { |
|
319 iHeap->Free(ArrayOfCells2[ArrayIndex2]); |
|
320 ArrayOfCells2[ArrayIndex2] = 0; |
|
321 } |
|
322 } |
|
323 test(iHeap->Count() == 0); |
|
324 } |
|
325 |
|
326 |
|
327 /////////////////////////////////////////////////////////////////////// |
|
328 // Allocate and free multiple random sized buffers. Use // |
|
329 // DebugFunction(EWalk) to check that all allocated cells are found. // |
|
330 /////////////////////////////////////////////////////////////////////// |
|
331 void TestRHeap::Test3(void) |
|
332 { |
|
333 TUint iAllocatedArraySize = 100; |
|
334 iAllocatedArrayOfCells = new TAny*[iAllocatedArraySize]; |
|
335 |
|
336 // allocate 100 random cells and save them in iAllocatedArrayOfCells |
|
337 for(iAllocatedArrayIndex=0; iAllocatedArrayIndex<iAllocatedArraySize; iAllocatedArrayIndex++) |
|
338 { |
|
339 iAllocatedArrayOfCells[iAllocatedArrayIndex] = 0; |
|
340 iAllocatedArrayOfCells[iAllocatedArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF)); |
|
341 test(iAllocatedArrayOfCells[iAllocatedArrayIndex] != NULL); |
|
342 } |
|
343 test(iHeap->Count() == 100); //check that all 100 allocations have succeedeed |
|
344 |
|
345 // copy iAllocatedArrayOfCells => iWalkArrayOfCells |
|
346 iWalkArrayOfCells = new TAny*[iWalkArrayIndex]; |
|
347 for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++) |
|
348 { |
|
349 iWalkArrayOfCells[iWalkArrayIndex] = 0; |
|
350 iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex]; |
|
351 test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]); |
|
352 } |
|
353 |
|
354 //check that walk finds all allocated cells... |
|
355 iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this); |
|
356 TBool ret = CheckWalkArrayEmpty(); |
|
357 test(ret); // ...and iWalkArrayOfCells is emptied |
|
358 |
|
359 // copy iAllocatedArrayOfCells => iWalkArrayOfCells |
|
360 iWalkArrayOfCells = new TAny*[iWalkArrayIndex]; |
|
361 for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++) |
|
362 { |
|
363 iWalkArrayOfCells[iWalkArrayIndex] = 0; |
|
364 iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex]; |
|
365 test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]); |
|
366 } |
|
367 |
|
368 // free 40 random cells from iWalkArrayOfCells |
|
369 TUint i; |
|
370 for (i=0; i<40; i++) |
|
371 { |
|
372 TUint RandomIndex = GetRandomIndex(99); |
|
373 iHeap->Free(iWalkArrayOfCells[RandomIndex]); |
|
374 iWalkArrayOfCells[RandomIndex] = 0; |
|
375 iAllocatedArrayOfCells[RandomIndex] = 0; |
|
376 } |
|
377 test(iHeap->Count() == 60); |
|
378 |
|
379 //check that walk finds all the remaining allocated cells... |
|
380 iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this); |
|
381 ret = CheckWalkArrayEmpty(); |
|
382 test(ret); // ...and iWalkArrayOfCells is emptied |
|
383 |
|
384 // allocate 20 more random cells starting on the first available free cell |
|
385 iAllocatedArrayIndex = 0; |
|
386 for (i=0; i<20; i++) |
|
387 { |
|
388 while (iAllocatedArrayOfCells[iAllocatedArrayIndex] != 0) |
|
389 { |
|
390 iAllocatedArrayIndex++; |
|
391 } |
|
392 iAllocatedArrayOfCells[iAllocatedArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF)); |
|
393 } |
|
394 test(iHeap->Count() == 80); |
|
395 |
|
396 // copy iAllocatedArrayOfCells => iWalkArrayOfCells |
|
397 iWalkArrayOfCells = new TAny*[iWalkArrayIndex]; |
|
398 for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++) |
|
399 { |
|
400 iWalkArrayOfCells[iWalkArrayIndex] = 0; |
|
401 iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex]; |
|
402 test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]); |
|
403 } |
|
404 |
|
405 //check that walk finds all the earlier and newly allocated cells... |
|
406 iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this); |
|
407 ret = CheckWalkArrayEmpty(); |
|
408 test(ret); // ...and iWalkArrayOfCells is emptied |
|
409 } |
|
410 |
|
411 |
|
412 void TestRHeap::CloseTests() |
|
413 { |
|
414 // close heap so we don't exceed chunk limit |
|
415 iHeap->Close(); |
|
416 } |
|
417 |
|
418 |
|
419 GLDEF_C TInt E32Main(void) |
|
420 { |
|
421 test.Title(); |
|
422 __KHEAP_MARK; |
|
423 |
|
424 TestRHeap T; |
|
425 |
|
426 test.Start(_L("Page Allocator Test")); |
|
427 |
|
428 TPtrC testHeapM=_L("TESTHEAP-MAIN"); |
|
429 RHeap* iHeapM; |
|
430 |
|
431 iHeapM=User::ChunkHeap(&testHeapM,0x1800,0x800000); |
|
432 |
|
433 TMetaData metaData; |
|
434 GetMeta(*iHeapM, metaData); |
|
435 |
|
436 iHeapM->Close(); |
|
437 |
|
438 if (metaData.iDLOnly) |
|
439 { |
|
440 test.Printf(_L("Page allocator is not used, no tests to run.\n")); |
|
441 __KHEAP_MARKEND; |
|
442 test.End(); |
|
443 return(0); |
|
444 } |
|
445 |
|
446 test.Next(_L("Init Paged allocator tests")); |
|
447 T.InitTests(); |
|
448 test.Next(_L("Test Paged allocator 1")); |
|
449 T.Test1(); |
|
450 test.Next(_L("Test Paged allocator 2")); |
|
451 T.Test2(); |
|
452 test.Next(_L("Test Paged allocator 3")); |
|
453 T.Test3(); |
|
454 T.CloseTests(); |
|
455 |
|
456 __KHEAP_CHECK(0); |
|
457 __KHEAP_MARKEND; |
|
458 |
|
459 test.End(); |
|
460 |
|
461 return (0); |
|
462 } |