--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/heap/t_heappagealloc.cpp Thu Jun 10 11:48:01 2010 +0100
@@ -0,0 +1,462 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\heap\t_page_alloc.cpp
+// Overview:
+// Tests RHeap class.
+// API Information:
+// RHeap
+// Details:
+// - Tests that the page bitmap is consistent (i.e. encoded sizes are sensible and
+// encoded in the correct fashion.
+// - Tests that pages which appear in the page bitmap are present in memory by
+// reading them.
+// -Tests that other pages are not readable
+// - Tests page bitmap by creating an allocator where all allocations >= 4kB use
+// paged allocator, allocating a large number of regions of various sizes (from
+// 4 kB to b MB), checking that the walk function finds them all correctly, freeing
+// some of them, checking the walk function again, and so on.
+// Platforms/Drives/Compatibility:
+// All
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+//
+//
+
+#include <e32test.h>
+#include <e32hal.h>
+#include <e32def.h>
+#include <e32math.h>
+#include <e32def_private.h>
+#include "dla.h"
+#include "slab.h"
+#include "page_alloc.h"
+#include "heap_hybrid.h"
+
+
+struct TMetaData
+ {
+ TBool iDLOnly;
+ RFastLock* iLock;
+ TInt iChunkSize;
+ TInt iSlabThreshold;
+ unsigned iSlabInitThreshold;
+ unsigned iSlabConfigBits;
+ slab* iPartialPage;
+ slab* iFullSlab;
+ page* iSparePage;
+ TUint8* iMemBase;
+ unsigned char iSizeMap[(MAXSLABSIZE>>2)+1];
+ slabset iSlabAlloc[MAXSLABSIZE>>2];
+ slab** iSlabAllocRealRootAddress[MAXSLABSIZE>>2];
+ };
+
+LOCAL_D RTest test(_L("T_HEAPPAGEALLOC"));
+
+class TestHybridHeap
+ {
+public:
+ static TUint8* MemBase(const RHybridHeap * aHybridHeap);
+ static void GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta);
+ };
+
+TUint8* TestHybridHeap::MemBase(const RHybridHeap * aHybridHeap)
+ {
+ return aHybridHeap->iMemBase;
+ }
+
+void TestHybridHeap::GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta)
+{
+ RHybridHeap::STestCommand cmd;
+ cmd.iCommand = RHybridHeap::EHeapMetaData;
+ TInt ret = aHeap.DebugFunction(RHeap::EHybridHeap, &cmd, 0);
+ test(ret == KErrNone);
+
+ RHybridHeap* hybridHeap = (RHybridHeap*) cmd.iData;
+
+ aMeta.iDLOnly = hybridHeap->iDLOnly;
+ aMeta.iLock = &hybridHeap->iLock;
+ aMeta.iChunkSize = hybridHeap->iChunkSize;
+ aMeta.iSlabThreshold = hybridHeap->iSlabThreshold;
+ aMeta.iSlabInitThreshold = hybridHeap->iSlabInitThreshold;
+ aMeta.iSlabConfigBits = hybridHeap->iSlabConfigBits;
+ aMeta.iPartialPage = hybridHeap->iPartialPage;
+ aMeta.iFullSlab = hybridHeap->iFullSlab;
+ aMeta.iSparePage = hybridHeap->iSparePage;
+ aMeta.iMemBase = hybridHeap->iMemBase;
+
+ TInt i;
+ TInt count;
+ count = sizeof(aMeta.iSizeMap)/sizeof(unsigned char);
+ for (i=0; i<count; ++i)
+ {
+ aMeta.iSizeMap[i] = hybridHeap->iSizeMap[i];
+ }
+ count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset);
+ for (i=0; i<count; ++i)
+ {
+ aMeta.iSlabAlloc[i].iPartial = hybridHeap->iSlabAlloc[i].iPartial;
+ aMeta.iSlabAllocRealRootAddress[i] = &hybridHeap->iSlabAlloc[i].iPartial;
+ }
+}
+
+LOCAL_C void GetMeta(RHeap& aHeap, TMetaData& aMeta)
+{
+ TestHybridHeap::GetHeapMetaData(aHeap, aMeta);
+}
+
+class TestRHeap : public RHeap
+ {
+public:
+ void InitTests();
+ void Test1(void);
+ void Test2(void);
+ void Test3(void);
+ void CloseTests();
+ TUint GetRandomSize(TUint aMaxSize);
+ TUint GetRandomIndex(TUint aMaxIndex);
+ static void WalkCallback(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen);
+ TBool CheckWalkArrayEmpty();
+
+private:
+ RHybridHeap* iHybridHeap;
+ RHeap *iHeap;
+ TUint8* iMemBase; // bottom of Paged/Slab memory (chunk base)
+ static TUint iWalkArraySize;
+ static TUint iWalkArrayIndex;
+ static TAny** iWalkArrayOfCells;
+ TUint iAllocatedArrayIndex;
+ TAny** iAllocatedArrayOfCells;
+ };
+
+TUint TestRHeap::iWalkArraySize = 100;
+TUint TestRHeap::iWalkArrayIndex = 0;
+TAny** TestRHeap::iWalkArrayOfCells = new TAny*[iWalkArraySize];
+
+void TestRHeap::InitTests()
+{
+ // Allocate a chunk heap
+ TPtrC testHeap=_L("TESTHEAP");
+ iHeap=User::ChunkHeap(&testHeap,0x1800,0x800000);
+ RHybridHeap::STestCommand cmd;
+ cmd.iCommand = RHybridHeap::EHeapMetaData;
+ iHeap->DebugFunction(RHeap::EHybridHeap, &cmd, 0);
+ iHybridHeap = (RHybridHeap*) cmd.iData;
+ iMemBase = TestHybridHeap::MemBase(iHybridHeap);
+
+ // configure paged heap threshold 16 kB
+ cmd.iCommand = RHybridHeap::ESetConfig;
+ cmd.iConfig.iSlabBits = 0x0; //0xabe
+ cmd.iConfig.iDelayedSlabThreshold = 0x40000000;
+ cmd.iConfig.iPagePower = 14;
+ test(iHeap->DebugFunction(RHeap::EHybridHeap, &cmd, 0) == KErrNone);
+}
+
+
+TUint TestRHeap::GetRandomSize(TUint aMaxSize)
+{
+ TUint size = 0;
+ do
+ {
+ size = Math::Random() & aMaxSize;
+ }
+ while(size < 16384 || size > aMaxSize );
+ // subtract debug header size
+ return size - 8;
+}
+
+
+TUint TestRHeap::GetRandomIndex(TUint aMaxIndex)
+{
+ TUint index = 0;
+ do
+ {
+ index = Math::Random() & 0x7F;
+ }
+ while(index >= aMaxIndex || iWalkArrayOfCells[index] == 0);
+
+ return index;
+}
+
+
+void TestRHeap::WalkCallback(TAny* aPtr, TCellType aCellType, TAny* aBuffer, TInt aLen)
+{
+ if (aLen>16375 && aPtr>0) // Don't test DL allocator
+ test(aCellType == EGoodAllocatedCell);
+
+ TUint i = 0;
+ for(i=0; i<iWalkArrayIndex; i++)
+ {
+ if(iWalkArrayOfCells[i] == aBuffer)
+ {
+ iWalkArrayOfCells[i] = NULL;
+ break;
+ }
+ }
+}
+
+TBool TestRHeap::CheckWalkArrayEmpty()
+{
+ TUint i = 0;
+ for(i=0; i<iWalkArrayIndex; i++)
+ {
+ if(iWalkArrayOfCells[i])
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+}
+
+
+///////////////////////////////////////////////////////////
+// Test page allocation with various sizes, 16 kB - 8 MB //
+// Simple test with fixed sizes. //
+///////////////////////////////////////////////////////////
+void TestRHeap::Test1(void)
+{
+ // Allocate and free single paged buffers of different size
+ // Small buffer
+ TAny* p1 = NULL;
+ p1=iHeap->Alloc(0x4000);
+ test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap);
+ test(iHeap->Count() == 1);
+ iHeap->Free(p1);
+ p1 = NULL;
+ test(iHeap->Count() == 0);
+
+ // Medium buffer
+ p1=iHeap->Alloc(0x20000);
+ test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap);
+ test(iHeap->Count() == 1);
+ iHeap->Free(p1);
+ p1 = NULL;
+ test(iHeap->Count() == 0);
+
+ // Large buffer
+ p1=iHeap->Alloc(0x700000);
+ test(p1 != NULL && p1 >= iMemBase && p1 < iHybridHeap);
+ test(iHeap->Count() == 1);
+ iHeap->Free(p1);
+ p1 = NULL;
+ test(iHeap->Count() == 0);
+
+ // Oversized buffer, not allocated
+ p1=iHeap->Alloc(0x900000);
+ test(p1 == NULL);
+ test(iHeap->Count() == 0);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// Allocate and free multiple random sized buffers, sizes under 65 kB. //
+// Check that all are allocated succesfully with Count. Free every other //
+// of them, check the Count. Allocate more buffers sized under 655 kB //
+// and free all buffers in reverse order. Check all are freed. //
+///////////////////////////////////////////////////////////////////////////
+void TestRHeap::Test2(void)
+{
+ TInt ArraySize=10;
+ TInt ArrayIndex;
+ TAny** ArrayOfCells;
+ ArrayOfCells = new TAny*[ArraySize];
+
+ // Allocate set of buffers
+ for(ArrayIndex=0; ArrayIndex<ArraySize; ArrayIndex++)
+ {
+ ArrayOfCells[ArrayIndex] = 0;
+ ArrayOfCells[ArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF));
+ test(ArrayOfCells[ArrayIndex] != NULL);
+ }
+ test(iHeap->Count() == 10);
+
+ // Free every other
+ for(ArrayIndex=0; ArrayIndex<ArraySize; ArrayIndex=ArrayIndex+2 )
+ {
+ iHeap->Free(ArrayOfCells[ArrayIndex]);
+ ArrayOfCells[ArrayIndex] = 0;
+ }
+ test(iHeap->Count() == 5);
+
+ TInt ArraySize2=10;
+ TInt ArrayIndex2;
+ TAny** ArrayOfCells2;
+ ArrayOfCells2 = new TAny*[ArraySize2];
+
+ // Allocate larger buffers
+ for(ArrayIndex2=0; ArrayIndex2<ArraySize; ArrayIndex2++)
+ {
+ ArrayOfCells2[ArrayIndex2] = 0;
+ ArrayOfCells2[ArrayIndex2] = iHeap->Alloc(GetRandomSize(0x7FFFF));
+ test(ArrayOfCells2[ArrayIndex2] != NULL);
+ }
+ test(iHeap->Count() == 15);
+
+ // Free all buffers in reverse order
+ for(ArrayIndex=9; ArrayIndex>=0; ArrayIndex-- )
+ {
+ if(ArrayOfCells[ArrayIndex] != 0)
+ {
+ iHeap->Free(ArrayOfCells[ArrayIndex]);
+ ArrayOfCells[ArrayIndex] = 0;
+ }
+ }
+ for(ArrayIndex2=9; ArrayIndex2>=0; ArrayIndex2-- )
+ {
+ if(ArrayOfCells2[ArrayIndex2] != 0)
+ {
+ iHeap->Free(ArrayOfCells2[ArrayIndex2]);
+ ArrayOfCells2[ArrayIndex2] = 0;
+ }
+ }
+ test(iHeap->Count() == 0);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// Allocate and free multiple random sized buffers. Use //
+// DebugFunction(EWalk) to check that all allocated cells are found. //
+///////////////////////////////////////////////////////////////////////
+void TestRHeap::Test3(void)
+{
+ TUint iAllocatedArraySize = 100;
+ iAllocatedArrayOfCells = new TAny*[iAllocatedArraySize];
+
+ // allocate 100 random cells and save them in iAllocatedArrayOfCells
+ for(iAllocatedArrayIndex=0; iAllocatedArrayIndex<iAllocatedArraySize; iAllocatedArrayIndex++)
+ {
+ iAllocatedArrayOfCells[iAllocatedArrayIndex] = 0;
+ iAllocatedArrayOfCells[iAllocatedArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF));
+ test(iAllocatedArrayOfCells[iAllocatedArrayIndex] != NULL);
+ }
+ test(iHeap->Count() == 100); //check that all 100 allocations have succeedeed
+
+ // copy iAllocatedArrayOfCells => iWalkArrayOfCells
+ iWalkArrayOfCells = new TAny*[iWalkArrayIndex];
+ for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++)
+ {
+ iWalkArrayOfCells[iWalkArrayIndex] = 0;
+ iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex];
+ test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]);
+ }
+
+ //check that walk finds all allocated cells...
+ iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this);
+ TBool ret = CheckWalkArrayEmpty();
+ test(ret); // ...and iWalkArrayOfCells is emptied
+
+ // copy iAllocatedArrayOfCells => iWalkArrayOfCells
+ iWalkArrayOfCells = new TAny*[iWalkArrayIndex];
+ for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++)
+ {
+ iWalkArrayOfCells[iWalkArrayIndex] = 0;
+ iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex];
+ test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]);
+ }
+
+ // free 40 random cells from iWalkArrayOfCells
+ TUint i;
+ for (i=0; i<40; i++)
+ {
+ TUint RandomIndex = GetRandomIndex(99);
+ iHeap->Free(iWalkArrayOfCells[RandomIndex]);
+ iWalkArrayOfCells[RandomIndex] = 0;
+ iAllocatedArrayOfCells[RandomIndex] = 0;
+ }
+ test(iHeap->Count() == 60);
+
+ //check that walk finds all the remaining allocated cells...
+ iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this);
+ ret = CheckWalkArrayEmpty();
+ test(ret); // ...and iWalkArrayOfCells is emptied
+
+ // allocate 20 more random cells starting on the first available free cell
+ iAllocatedArrayIndex = 0;
+ for (i=0; i<20; i++)
+ {
+ while (iAllocatedArrayOfCells[iAllocatedArrayIndex] != 0)
+ {
+ iAllocatedArrayIndex++;
+ }
+ iAllocatedArrayOfCells[iAllocatedArrayIndex] = iHeap->Alloc(GetRandomSize(0xFFFF));
+ }
+ test(iHeap->Count() == 80);
+
+ // copy iAllocatedArrayOfCells => iWalkArrayOfCells
+ iWalkArrayOfCells = new TAny*[iWalkArrayIndex];
+ for(iWalkArrayIndex=0; iWalkArrayIndex<iWalkArraySize; iWalkArrayIndex++)
+ {
+ iWalkArrayOfCells[iWalkArrayIndex] = 0;
+ iWalkArrayOfCells[iWalkArrayIndex] = iAllocatedArrayOfCells[iWalkArrayIndex];
+ test(iWalkArrayOfCells[iWalkArrayIndex] == iAllocatedArrayOfCells[iWalkArrayIndex]);
+ }
+
+ //check that walk finds all the earlier and newly allocated cells...
+ iHeap->DebugFunction(EWalk, (TAny*)&WalkCallback, (TAny*)this);
+ ret = CheckWalkArrayEmpty();
+ test(ret); // ...and iWalkArrayOfCells is emptied
+}
+
+
+void TestRHeap::CloseTests()
+ {
+ // close heap so we don't exceed chunk limit
+ iHeap->Close();
+ }
+
+
+GLDEF_C TInt E32Main(void)
+ {
+ test.Title();
+ __KHEAP_MARK;
+
+ TestRHeap T;
+
+ test.Start(_L("Page Allocator Test"));
+
+ TPtrC testHeapM=_L("TESTHEAP-MAIN");
+ RHeap* iHeapM;
+
+ iHeapM=User::ChunkHeap(&testHeapM,0x1800,0x800000);
+
+ TMetaData metaData;
+ GetMeta(*iHeapM, metaData);
+
+ iHeapM->Close();
+
+ if (metaData.iDLOnly)
+ {
+ test.Printf(_L("Page allocator is not used, no tests to run.\n"));
+ __KHEAP_MARKEND;
+ test.End();
+ return(0);
+ }
+
+ test.Next(_L("Init Paged allocator tests"));
+ T.InitTests();
+ test.Next(_L("Test Paged allocator 1"));
+ T.Test1();
+ test.Next(_L("Test Paged allocator 2"));
+ T.Test2();
+ test.Next(_L("Test Paged allocator 3"));
+ T.Test3();
+ T.CloseTests();
+
+ __KHEAP_CHECK(0);
+ __KHEAP_MARKEND;
+
+ test.End();
+
+ return (0);
+ }