diff -r 5e441a173c63 -r d9f1e5bfe28c kerneltest/e32test/heap/t_heapslab.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/heap/t_heapslab.cpp Thu Jun 10 11:48:01 2010 +0100 @@ -0,0 +1,1056 @@ +// 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_heapslab.cpp +// Overview: +// Tests RHybridHeap class: slab allocator +// API Information: +// RHybridHeap/RHeap +// Details: +//- Starts with empty allocator configured to use slab allocation +// on all cell sizes less than slab threshold (49). +//- Allocate enough cells of the same size to fill 128 slabs. +//- Check the number of pages used corresponds to the number of slabs. +//- Check that a new slab is taken from a partially filled page if available. +//- Check that a partially filled slab is used if available. +//- Check that if all four slabs in a page are free, the page is freed. +//- Free cells to give empty slab. +//- Free cells to give partial slab. +//- Reallocate cells. +//- RAllocator::Check() is used to check internal consistency. +// Platforms/Drives/Compatibility: +// All +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#include +#include +#include +#include +#include "dla.h" +#include "slab.h" +#include "page_alloc.h" +#include "heap_hybrid.h" + +#define MAX_THREADS 4 +#define MAX_ALLOCS 20000 // 16128, if slab count is 128 and alloc size is 8 + +//#define TSTSLAB_DBG(a) a +#define TSTSLAB_DBG(a) + +struct TSlabTestThreadParm + { + RHeap* iHeap; + TInt iAllocSize; + TInt iInitSlabCount; + TBool iUseRandomSize; + TInt iThreadCount; + TInt iThreadIndex; + }; + +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]; + }; + +class TestHybridHeap + { +public: + static void GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta); + }; + +LOCAL_D RTest test(_L("T_HEAPSLAB")); + +LOCAL_D TInt PageSize; + +LOCAL_D TAny* PtrBuf[MAX_THREADS][MAX_ALLOCS]; +LOCAL_D TSlabTestThreadParm ThreadParm[MAX_THREADS]; + +enum TTestWalkFunc {ETestWalk, ETestFindSlab}; + + +static unsigned SlabHeaderPagemap(unsigned h) {return (h&0x00000f00)>>8;} + +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; iiSizeMap[i]; + } + count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset); + for (i=0; iiSlabAlloc[i].iPartial; + aMeta.iSlabAllocRealRootAddress[i] = &hybridHeap->iSlabAlloc[i].iPartial; + } +} + +LOCAL_C void GetMeta(RHeap& aHeap, TMetaData& aMeta) +{ + TestHybridHeap::GetHeapMetaData(aHeap, aMeta); +} + +/*LOCAL_C void PrintMeta(const char* aText, TMetaData& aMeta) +{ + RDebug::Printf("=========== HeapMetaData (local) - begin: %s", aText); + + RDebug::Printf("iDLOnly: 0x%08x", aMeta.iDLOnly); + RDebug::Printf("iChunkSize: 0x%08x", aMeta.iChunkSize); + RDebug::Printf("iSlabThreshold: 0x%08x / %d", aMeta.iSlabThreshold, aMeta.iSlabThreshold); + RDebug::Printf("iSlabInitThreshold: 0x%08x / %d", aMeta.iSlabInitThreshold, aMeta.iSlabInitThreshold); + RDebug::Printf("iSlabConfigBits: 0x%08x", aMeta.iSlabConfigBits); + RDebug::Printf("iPartialPage: 0x%08x", aMeta.iPartialPage); + RDebug::Printf("iFullSlab: 0x%08x", aMeta.iFullSlab); + RDebug::Printf("iSparePage: 0x%08x", aMeta.iSparePage); + RDebug::Printf("iMemBase: 0x%08x", aMeta.iMemBase); + + TInt i; + TInt count; + count = sizeof(aMeta.iSizeMap)/sizeof(unsigned char); + for (i=0; i(Floor(s, PAGESIZE)); + } + + +LOCAL_C slab* SlabFor(const void* p) +{ + return (slab*)(Floor(p, SLABSIZE)); +} + +LOCAL_C TInt TreeWalk(slab** aRealRootAddress, slab* const* aRoot, TTestWalkFunc aFunc, TAny* aParm, TInt& aOutParm) +{ + TInt count = 0; + aOutParm = 0; + + slab* s = *aRoot; + if (!s) + return count; + + for (;;) + { + slab* c; + while ((c = s->iChild1) != 0) + s = c; // walk down left side to end + for (;;) + { + count++; + TSTSLAB_DBG(RDebug::Printf("TreeWalk - slab: 0x%08x", s)); + (void)aParm; + if (aFunc == ETestWalk) + { + ; + } + else if (aFunc == ETestFindSlab) + { + if ((slab*)aParm == s) + { + aOutParm = 1; + return 0; + } + } + + c = s->iChild2; + if (c) + { // one step down right side, now try and walk down left + s = c; + break; + } + for (;;) + { // loop to walk up right side + slab** pp = s->iParent; + if (pp == aRealRootAddress) + return count; + s = SlabFor(pp); + if (pp == &s->iChild1) + break; + } + } + } +} + +LOCAL_C TInt WalkSlabSet(TInt aSlabsetIndex, TMetaData& aMeta, TTestWalkFunc aFunc, TAny* aParm, TInt& aOutParm) +{ + if (aSlabsetIndex >= (MAXSLABSIZE>>2)) + { + return 0; + } + return TreeWalk(aMeta.iSlabAllocRealRootAddress[aSlabsetIndex], &aMeta.iSlabAlloc[aSlabsetIndex].iPartial, aFunc, aParm, aOutParm); +} + +/*LOCAL_C void DebugPrintSlabs(TInt aSlabsetIndex, TMetaData& aMeta) + { + //RDebug::Printf("=========== DebugPrintSlabs: %s", aText); + RDebug::Printf("=========== DebugPrintSlabs"); + + RDebug::Printf("iSparePage: 0x%08x", aMeta.iSparePage); + + slab* fullSlab = aMeta.iFullSlab; + TInt fullSlabCount = 0; + while (fullSlab) + { + RDebug::Printf("fullSlab: 0x%08x", fullSlab); + fullSlabCount++; + fullSlab = fullSlab->iChild1; + } + + TInt outParm; + TInt partialTreeSlabCount = 0; + partialTreeSlabCount += WalkSlabSet(aSlabsetIndex, aMeta, ETestWalk, 0, outParm); + + slab* partialPageSlab = aMeta.iPartialPage; + TInt partialPageSlabCount = 0; + while (partialPageSlab) + { + RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab); + partialPageSlabCount++; + partialPageSlab = partialPageSlab->iChild1; + } + }*/ + +LOCAL_C void TestSlabFixedSizeManyThreads(TSlabTestThreadParm& aParm) + { + RHeap* heap = aParm.iHeap; + TInt allocSize = aParm.iAllocSize; + TInt initSlabCount = aParm.iInitSlabCount; + //TBool useRandomSize = aParm.iUseRandomSize; + //TInt threadCount = aParm.iThreadCount; + TInt threadIndex = aParm.iThreadIndex; + + TInt slabsPerPage = PageSize/SLABSIZE; + + test(initSlabCount % slabsPerPage == 0); // for this test + +#ifdef _DEBUG + TInt allocRealCellSize = allocSize + RHeap::EDebugHdrSize; +#else + TInt allocRealCellSize = allocSize; +#endif + + TMetaData metaData; + GetMeta(*heap, metaData); + + if (allocRealCellSize >= metaData.iSlabThreshold) + { + allocRealCellSize = metaData.iSlabThreshold - 1; +#ifdef _DEBUG + allocSize = allocRealCellSize - RHeap::EDebugHdrSize; +#else + allocSize = allocRealCellSize; +#endif + } + + TAny** pBuf = &PtrBuf[threadIndex][0]; + TInt i; + for (i=0; i>2]; + test(slabsetIndex != 0xff); + TInt slabCellSize = 4 + (slabsetIndex * 4); + + TInt slabPayloadSize = SLABSIZE - sizeof(slabhdr); + TInt cellCountPerSlab = slabPayloadSize / slabCellSize; + TInt initCellCount = initSlabCount * cellCountPerSlab; + + TSTSLAB_DBG(RDebug::Printf("=========== Allocate enough cells of the same size to fill %d slabs", initSlabCount)); + TSTSLAB_DBG(RDebug::Printf("=========== counts: %d %d %d", cellCountPerSlab, initCellCount, slabCellSize)); + + for (i=0; iAlloc(allocSize); + test(pBuf[i] != 0); + } + + heap->Check(); + + TInt maxI5 = initCellCount + (cellCountPerSlab*(slabsPerPage+1)); + for (i=initCellCount; iAlloc(allocSize); + test(pBuf[i] != 0); + } + + heap->Check(); + + TAny* p2 = heap->Alloc(allocSize); + test(p2 != 0); + + heap->Check(); + heap->Free(p2); + + heap->Check(); + + + TInt page2pBufIndexFirst = cellCountPerSlab * slabsPerPage; + //TInt page2pBufIndexLast = page2pBufIndexFirst + (cellCountPerSlab * slabsPerPage); + + slab* partialTreeSlabX1 = SlabFor(pBuf[page2pBufIndexFirst]); + page* partialTreeSlabPageX1 = PageFor(partialTreeSlabX1); + + heap->Free(pBuf[page2pBufIndexFirst]); + pBuf[page2pBufIndexFirst] = 0; + + heap->Check(); + + TAny* p3 = heap->Alloc(allocSize); + test(p3 != 0); + heap->Check(); + heap->Free(p3); + heap->Check(); + + TInt size2 = metaData.iChunkSize; + TSTSLAB_DBG(RDebug::Printf("---- size2: 0x%08x", size2)); + if (metaData.iSparePage) + { + size2 -= PageSize; + } + + for (i=0; iFree(pBuf[i]); + pBuf[i] = 0; + } + } + } + + heap->Check(); + + TInt size3 = metaData.iChunkSize; + if (metaData.iSparePage) + { + size3 -= PageSize; + } + + TInt bufIndexFirst = cellCountPerSlab; + TInt maxI = bufIndexFirst + cellCountPerSlab; + for (i=bufIndexFirst; i<=maxI; ++i) + { + if (pBuf[i]) + { + heap->Free(pBuf[i]); + pBuf[i] = 0; + } + } + + heap->Check(); + + TInt firstI = cellCountPerSlab * 3; + maxI = firstI + cellCountPerSlab; + for (i=firstI; i<=maxI; ++i) + { + if (i % 3 == 0) + { + if (pBuf[i]) + { + heap->Free(pBuf[i]); + pBuf[i] = 0; + } + } + } + + heap->Check(); + + //Reallocate cells. + for (i=0; i<(MAX_ALLOCS); ++i) + { + if (pBuf[i] != 0) + { + pBuf[i] = heap->ReAlloc(pBuf[i], allocSize); + test(pBuf[i] != 0); + } + } + + heap->Check(); + + //Allocate cells. + for (i=0; i<(MAX_ALLOCS/4); ++i) + { + if (pBuf[i] == 0) + { + pBuf[i] = heap->Alloc(allocSize); + test(pBuf[i] != 0); + } + } + + heap->Check(); + + for (i=0; iFree(pBuf[i]); + pBuf[i] = 0; + } + } + heap->Check(); + + TSTSLAB_DBG(RDebug::Printf("=========== TestSlabFixedSizeManyThreads end")); + } + + +LOCAL_C void TestSlabFixedSizeOneThread(TSlabTestThreadParm& aParm) + { + RHeap* heap = aParm.iHeap; + TInt allocSize = aParm.iAllocSize; + TInt initSlabCount = aParm.iInitSlabCount; + //TBool useRandomSize = aParm.iUseRandomSize; + //TInt threadCount = aParm.iThreadCount; + TInt threadIndex = aParm.iThreadIndex; + + TInt slabsPerPage = PageSize/SLABSIZE; + + test(initSlabCount % slabsPerPage == 0); // for this test + +#ifdef _DEBUG + TInt allocRealCellSize = allocSize + RHeap::EDebugHdrSize; +#else + TInt allocRealCellSize = allocSize; +#endif + + TMetaData metaData; + GetMeta(*heap, metaData); + + TSTSLAB_DBG(PrintMeta(" --- TestSlabFixedSizeOneThread start", metaData)); + + if (allocRealCellSize >= metaData.iSlabThreshold) + { + allocRealCellSize = metaData.iSlabThreshold - 1; +#ifdef _DEBUG + allocSize = allocRealCellSize - RHeap::EDebugHdrSize; +#else + allocSize = allocRealCellSize; +#endif + } + + TAny** pBuf = &PtrBuf[threadIndex][0]; + TInt i; + for (i=0; i>2]; + test(slabsetIndex != 0xff); + TInt slabCellSize = 4 + (slabsetIndex * 4); + + TInt slabPayloadSize = SLABSIZE - sizeof(slabhdr); + TInt cellCountPerSlab = slabPayloadSize / slabCellSize; + TInt initCellCount = initSlabCount * cellCountPerSlab; + + TSTSLAB_DBG(RDebug::Printf("=========== Allocate enough cells of the same size to fill %d slabs", initSlabCount)); + TSTSLAB_DBG(RDebug::Printf("=========== counts: %d %d %d", cellCountPerSlab, initCellCount, slabCellSize)); + + for (i=0; iAlloc(allocSize); + test(pBuf[i] != 0); + } + + heap->Check(); + GetMeta(*heap, metaData); + + TSTSLAB_DBG(PrintMeta("after init allocs", metaData)); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + //Check the number of pages used corresponds to the number of slabs. + TSTSLAB_DBG(RDebug::Printf("=========== Check the number of pages used corresponds to the number of slabs")); + + TInt pageCountForSlabs1 = (metaData.iChunkSize / PageSize) - 1; + TInt pageCountForSlabs2 = (initSlabCount+(slabsPerPage-1)) / slabsPerPage; + TSTSLAB_DBG(RDebug::Printf("=========== page counts: %d %d", pageCountForSlabs1, pageCountForSlabs2)); + test(pageCountForSlabs1 == pageCountForSlabs2); + + //----------------------------------------- + TSTSLAB_DBG(RDebug::Printf("=========== check slab counts in the lists")); + + slab* fullSlab = metaData.iFullSlab; + TInt fullSlabCount = 0; + while (fullSlab) + { + TSTSLAB_DBG(RDebug::Printf("fullSlab: 0x%08x", fullSlab)); + fullSlabCount++; + fullSlab = fullSlab->iChild1; + } + + TInt outParm; + TInt partialTreeSlabCount = 0; + partialTreeSlabCount = WalkSlabSet(slabsetIndex, metaData, ETestWalk, 0, outParm); + + slab* partialPageSlab = metaData.iPartialPage; + TInt partialPageSlabCount = 0; + while (partialPageSlab) + { + TSTSLAB_DBG(RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab)); + partialPageSlabCount++; + partialPageSlab = partialPageSlab->iChild1; + } + + test(fullSlabCount == (initSlabCount-1)); + test(partialTreeSlabCount == 1); + if (initSlabCount % slabsPerPage == 0) + { + test(partialPageSlabCount == 0); + } + else + { + test(partialPageSlabCount == 1); + } + //----------------------------------------- + TSTSLAB_DBG(RDebug::Printf("=========== alloc one cell more -> one full slab more")); + + TAny* p = heap->Alloc(allocSize); + test(p != 0); + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + fullSlab = metaData.iFullSlab; + fullSlabCount = 0; + while (fullSlab) + { + TSTSLAB_DBG(RDebug::Printf("fullSlab: 0x%08x", fullSlab)); + fullSlabCount++; + fullSlab = fullSlab->iChild1; + } + test(fullSlabCount == initSlabCount); + + heap->Free(p); + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + //----------------------------------------- + //Check that a new slab is taken from a partially filled page if available. + TSTSLAB_DBG(RDebug::Printf("=========== Check that a new slab is taken from a partially filled page if available")); + + // fill the first slab in the page (after iSparePage) + TInt maxI5 = initCellCount + (cellCountPerSlab*(slabsPerPage+1)); + for (i=initCellCount; iAlloc(allocSize); + test(pBuf[i] != 0); + } + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + partialPageSlab = metaData.iPartialPage; + partialPageSlabCount = 0; + while (partialPageSlab) + { + TSTSLAB_DBG(RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab)); + partialPageSlabCount++; + partialPageSlab = partialPageSlab->iChild1; + } + test(partialPageSlabCount == 1); + + page* page1 = PageFor(metaData.iPartialPage); + unsigned header = page1->iSlabs[0].iHeader; + unsigned pagemap = SlabHeaderPagemap(header); + unsigned slabix = LOWBIT(pagemap); + slab* partialPageSlab2 = &page1->iSlabs[slabix]; + + TAny* p2 = heap->Alloc(allocSize); + test(p2 != 0); + + heap->Check(); + TSTSLAB_DBG(RDebug::Printf("p2: 0x%08x; partialPageSlab2: 0x%08x", p2, partialPageSlab2)); + test(partialPageSlab2 == SlabFor(p2)); + heap->Free(p2); + + heap->Check(); + + //----------------------------- + // use the second page for the next test + TInt page2pBufIndexFirst = cellCountPerSlab * slabsPerPage; + //TInt page2pBufIndexLast = page2pBufIndexFirst + (cellCountPerSlab * slabsPerPage); + + //----------------------------------------- + //Check that a partially filled slab is used if available. + TSTSLAB_DBG(RDebug::Printf("=========== Check that a partially filled slab is used if available")); + + slab* partialTreeSlabX1 = SlabFor(pBuf[page2pBufIndexFirst]); + page* partialTreeSlabPageX1 = PageFor(partialTreeSlabX1); + + heap->Free(pBuf[page2pBufIndexFirst]); + pBuf[page2pBufIndexFirst] = 0; + + heap->Check(); + + TAny* p3 = heap->Alloc(allocSize); + test(p3 != 0); + heap->Check(); + test(partialTreeSlabX1 == SlabFor(p3)); + heap->Free(p3); + heap->Check(); + + //----------------------------------------- + //Check that if all four slabs in a page are free the page is freed. + TSTSLAB_DBG(RDebug::Printf("=========== Check that if all four slabs in a page are free, the page is freed")); + + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + TInt size2 = metaData.iChunkSize; + TSTSLAB_DBG(RDebug::Printf("---- size2: 0x%08x", size2)); + if (metaData.iSparePage) + { + size2 -= PageSize; + } + + for (i=0; iFree(pBuf[i]); + pBuf[i] = 0; + } + } + } + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + TInt size3 = metaData.iChunkSize; + if (metaData.iSparePage) + { + size3 -= PageSize; + } + + test(size3 == (size2-PageSize)); + + //----------------------------------------- + //Free cells to give empty slab (The second slab in the first page) + TSTSLAB_DBG(RDebug::Printf("=========== Free cells to give empty slab (The second slab in the first page)")); + slab* emptySlabAddr = (slab*)(metaData.iMemBase + SLABSIZE); + + //Check that emptySlabAddr is not already in iPartialPage list + partialPageSlab = metaData.iPartialPage; + while (partialPageSlab) + { + if (partialPageSlab == emptySlabAddr) + { + test(0); + } + partialPageSlab = partialPageSlab->iChild1; + } + + // free cells to give empty slab - emptySlabAddr + TInt bufIndexFirst = cellCountPerSlab; + TInt maxI = bufIndexFirst + cellCountPerSlab; + for (i=bufIndexFirst; i<=maxI; ++i) + { + if (pBuf[i]) + { + heap->Free(pBuf[i]); + pBuf[i] = 0; + } + } + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + // Check that emptySlabAddr is not now in iPartialPage list + partialPageSlab = metaData.iPartialPage; + while (partialPageSlab) + { + if (partialPageSlab == emptySlabAddr) + { + break; + } + partialPageSlab = partialPageSlab->iChild1; + } + test(partialPageSlab != 0); + + //Free cells to give partial slab (The third slab in the first page) + TSTSLAB_DBG(RDebug::Printf("=========== Free cells to give partial slab (The third slab in the first page)")); + slab* partialSlabAddr = (slab*)(metaData.iMemBase + (3*SLABSIZE)); + + // Check that partialSlabAddr is not now in iPartialSlab list + WalkSlabSet(slabsetIndex, metaData, ETestFindSlab, partialSlabAddr, outParm); + test(outParm == 0); + + TInt firstI = cellCountPerSlab * 3; + maxI = firstI + cellCountPerSlab; + for (i=firstI; i<=maxI; ++i) + { + if (i % 3 == 0) + { + if (pBuf[i]) + { + heap->Free(pBuf[i]); + pBuf[i] = 0; + } + } + } + + heap->Check(); + GetMeta(*heap, metaData); + TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData)); + + // Check that partialSlabAddr is now in iPartialSlab list + WalkSlabSet(slabsetIndex, metaData, ETestFindSlab, partialSlabAddr, outParm); + test(outParm == 1); + + //Reallocate cells. + for (i=0; i<(MAX_ALLOCS); ++i) + { + if (pBuf[i] != 0) + { + pBuf[i] = heap->ReAlloc(pBuf[i], allocSize); + test(pBuf[i] != 0); + } + } + + heap->Check(); + + //Allocate cells. + for (i=0; i<(MAX_ALLOCS/4); ++i) + { + if (pBuf[i] == 0) + { + pBuf[i] = heap->Alloc(allocSize); + test(pBuf[i] != 0); + } + } + + heap->Check(); + + for (i=0; iFree(pBuf[i]); + pBuf[i] = 0; + } + } + heap->Check(); + + TSTSLAB_DBG(RDebug::Printf("=========== TestSlabFixedSizeOneThread end")); + } + +LOCAL_C RHeap* CreateSlabHeap(TInt aThreadCount) +{ + //TPtrC slabHeap=_L("SlabHeap"); + //RHeap* heap = User::ChunkHeap(&slabHeap, 0x1000, 0x10000); + TInt maxLth = 0x60000 * aThreadCount; + RHeap* heap = User::ChunkHeap(0, 0x1000, maxLth); + test(heap!=NULL); + + // Configure heap for slab + RHybridHeap::STestCommand cmd; + cmd.iCommand = RHybridHeap::ESetConfig; + cmd.iConfig.iSlabBits = 0xabe; + cmd.iConfig.iDelayedSlabThreshold = 0; + cmd.iConfig.iPagePower = 0; // 16 // 0 -> no page allocator + TInt ret = heap->DebugFunction(RHeap::EHybridHeap, &cmd, 0); + test(ret == KErrNone); + + return heap; +} + +LOCAL_C TInt SlabTestManyThreads(TAny* aThreadParm) + { + TSlabTestThreadParm* parm = (TSlabTestThreadParm*)aThreadParm; + + TInt i; + TInt maxLoops = 30; //300; + for (i=0; i threadName; + threadName.Format(_L("SlabTest%d"), index); + if (aThreadCount == 1) + { + ret = theThreads[index].Create(threadName, SlabTestOneThread, KSlabTestThreadStackSize, NULL, (TAny*)&ThreadParm[index]); + } + else + { + ret = theThreads[index].Create(threadName, SlabTestManyThreads, KSlabTestThreadStackSize, NULL, (TAny*)&ThreadParm[index]); + } + test(ret == KErrNone); + theThreads[index].Logon(theStatus[index]); + test(theStatus[index] == KRequestPending); + threadInUse[index] = ETrue; + theThreads[index].Resume(); + } + + User::WaitForAnyRequest(); + + TBool anyUsed = ETrue; + while (anyUsed) + { + User::After(1001000); + anyUsed = EFalse; + for (index = 0; index < aThreadCount; index++) + { + if (threadInUse[index]) + { + if (theThreads[index].ExitType() != EExitPending) + { + threadInUse[index] = EFalse; + } + else + { + anyUsed = ETrue; + } + } + } + } + + for (index = 0; index < aThreadCount; index++) + { + theThreads[index].Close(); + } + TSTSLAB_DBG(RDebug::Printf("=========== StartThreads end")); + heap->Close(); + + return KErrNone; + } + +GLDEF_C TInt E32Main(void) + { + TInt ret; + + test.Title(); + + __KHEAP_MARK; + + test.Start(_L("TestSlab")); + UserHal::PageSizeInBytes(PageSize); + + RHeap* heap = CreateSlabHeap(1); + + TMetaData metaData; + GetMeta(*heap, metaData); + + heap->Close(); + + if (metaData.iDLOnly) + { + test.Printf(_L("Slab allocator is not used, no tests to run\n")); + __KHEAP_MARKEND; + test.End(); + return(0); + } + + TSlabTestThreadParm threadParm; + threadParm.iHeap = heap; + threadParm.iAllocSize = 17; + threadParm.iInitSlabCount = 128; // 12 + threadParm.iUseRandomSize = EFalse; + + test.Next(_L("TestSlab - one thread")); + + TInt threadCount; + threadCount = 1; + if (threadCount > MAX_THREADS) + { + threadCount = MAX_THREADS; + } + threadParm.iThreadCount = threadCount; + +#if 0 + ret = StartThreads(threadCount, threadParm); + test(ret==KErrNone); + +#else + + TInt i; + for (i=1; i= metaData.iSlabThreshold) + { + break; + } +#endif // _DEBUG + TSTSLAB_DBG(RDebug::Printf("=========== StartThreads size: %d", i)); + threadParm.iAllocSize = i; + test.Printf(_L("AllocSize: %d\n"), i); + ret = StartThreads(threadCount, threadParm); + test(ret==KErrNone); + } +#endif + + + test.Next(_L("TestSlab - many threads")); + + threadParm.iAllocSize = 17; + + threadCount = 3; + if (threadCount > MAX_THREADS) + { + threadCount = MAX_THREADS; + } + threadParm.iThreadCount = threadCount; + +#if 1 + ret = StartThreads(threadCount, threadParm); + test(ret==KErrNone); + +#else + + TInt i; + for (i=1; i= metaData.iSlabThreshold) + { + break; + } +#endif // _DEBUG + TSTSLAB_DBG(RDebug::Printf("=========== StartThreads size: %d", i)); + threadParm.iAllocSize = i; + test.Printf(_L("AllocSize: %d\n"), i); + ret = StartThreads(threadCount, threadParm); + test(ret==KErrNone); + } +#endif + + __KHEAP_MARKEND; + + test.End(); + return(0); + }