kerneltest/e32test/heap/t_heapslab.cpp
changeset 109 b3a1d9898418
equal deleted inserted replaced
102:ef2a444a7410 109:b3a1d9898418
       
     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_heapslab.cpp
       
    15 // Overview:
       
    16 // Tests RHybridHeap class: slab allocator
       
    17 // API Information:
       
    18 // RHybridHeap/RHeap
       
    19 // Details:
       
    20 //- Starts with empty allocator configured to use slab allocation
       
    21 //  on all cell sizes less than slab threshold (49).
       
    22 //- Allocate enough cells of the same size to fill 128 slabs.
       
    23 //- Check the number of pages used corresponds to the number of slabs.
       
    24 //- Check that a new slab is taken from a partially filled page if available.
       
    25 //- Check that a partially filled slab is used if available.
       
    26 //- Check that if all four slabs in a page are free, the page is freed.
       
    27 //- Free cells to give empty slab.
       
    28 //- Free cells to give partial slab.
       
    29 //- Reallocate cells.
       
    30 //- RAllocator::Check() is used to check internal consistency.
       
    31 // Platforms/Drives/Compatibility:
       
    32 // All
       
    33 // Assumptions/Requirement/Pre-requisites:
       
    34 // Failures and causes:
       
    35 // Base Port information:
       
    36 // 
       
    37 //
       
    38 
       
    39 #include <e32test.h>
       
    40 #include <e32hal.h>
       
    41 #include <e32def.h>
       
    42 #include <e32def_private.h>
       
    43 #include "dla.h"
       
    44 #include "slab.h"
       
    45 #include "page_alloc.h"
       
    46 #include "heap_hybrid.h"
       
    47 
       
    48 #define MAX_THREADS 4
       
    49 #define MAX_ALLOCS 20000 // 16128, if slab count is 128 and alloc size is 8
       
    50 
       
    51 //#define TSTSLAB_DBG(a) a
       
    52 #define TSTSLAB_DBG(a)
       
    53 
       
    54 struct TSlabTestThreadParm
       
    55     {
       
    56     RHeap*  iHeap;
       
    57     TInt    iAllocSize;
       
    58     TInt    iInitSlabCount;
       
    59     TBool   iUseRandomSize;
       
    60     TInt    iThreadCount;
       
    61     TInt    iThreadIndex;
       
    62     };
       
    63 
       
    64 struct TMetaData
       
    65     {
       
    66     TBool           iDLOnly;
       
    67     RFastLock*      iLock;
       
    68     TInt            iChunkSize;
       
    69     TInt            iSlabThreshold;
       
    70     unsigned        iSlabInitThreshold;
       
    71     unsigned        iSlabConfigBits;
       
    72     slab*           iPartialPage;
       
    73     slab*           iFullSlab;
       
    74     page*           iSparePage;
       
    75     TUint8*         iMemBase;
       
    76     unsigned char   iSizeMap[(MAXSLABSIZE>>2)+1];
       
    77     slabset         iSlabAlloc[MAXSLABSIZE>>2];
       
    78     slab**          iSlabAllocRealRootAddress[MAXSLABSIZE>>2];
       
    79     };
       
    80 
       
    81 class TestHybridHeap
       
    82     {
       
    83 public:
       
    84     static void GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta);
       
    85     };
       
    86 
       
    87 LOCAL_D RTest test(_L("T_HEAPSLAB"));
       
    88 
       
    89 LOCAL_D TInt PageSize;
       
    90 
       
    91 LOCAL_D TAny* PtrBuf[MAX_THREADS][MAX_ALLOCS];
       
    92 LOCAL_D TSlabTestThreadParm ThreadParm[MAX_THREADS];
       
    93 
       
    94 enum TTestWalkFunc {ETestWalk, ETestFindSlab};
       
    95 
       
    96 
       
    97 static unsigned SlabHeaderPagemap(unsigned h) {return (h&0x00000f00)>>8;}
       
    98 
       
    99 void TestHybridHeap::GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta)
       
   100 {
       
   101     RHybridHeap::STestCommand cmd;
       
   102     cmd.iCommand = RHybridHeap::EHeapMetaData;
       
   103     TInt ret = aHeap.DebugFunction(RHeap::EHybridHeap, &cmd, 0);
       
   104     test(ret == KErrNone);
       
   105     
       
   106     RHybridHeap* hybridHeap = (RHybridHeap*) cmd.iData;
       
   107     
       
   108     aMeta.iDLOnly              = hybridHeap->iDLOnly;
       
   109     aMeta.iLock                = &hybridHeap->iLock;
       
   110     aMeta.iChunkSize           = hybridHeap->iChunkSize;
       
   111     aMeta.iSlabThreshold       = hybridHeap->iSlabThreshold;
       
   112     aMeta.iSlabInitThreshold   = hybridHeap->iSlabInitThreshold;
       
   113     aMeta.iSlabConfigBits      = hybridHeap->iSlabConfigBits;
       
   114     aMeta.iPartialPage         = hybridHeap->iPartialPage;
       
   115     aMeta.iFullSlab            = hybridHeap->iFullSlab;
       
   116     aMeta.iSparePage           = hybridHeap->iSparePage;
       
   117     aMeta.iMemBase             = hybridHeap->iMemBase;
       
   118 
       
   119     TInt i;
       
   120     TInt count;
       
   121     count = sizeof(aMeta.iSizeMap)/sizeof(unsigned char);
       
   122     for (i=0; i<count; ++i)
       
   123         {
       
   124         aMeta.iSizeMap[i] = hybridHeap->iSizeMap[i];
       
   125         }
       
   126     count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset);
       
   127     for (i=0; i<count; ++i)
       
   128         {
       
   129         aMeta.iSlabAlloc[i].iPartial = hybridHeap->iSlabAlloc[i].iPartial;
       
   130         aMeta.iSlabAllocRealRootAddress[i] = &hybridHeap->iSlabAlloc[i].iPartial;
       
   131         }
       
   132 }
       
   133 
       
   134 LOCAL_C void GetMeta(RHeap& aHeap, TMetaData& aMeta)
       
   135 {
       
   136     TestHybridHeap::GetHeapMetaData(aHeap, aMeta);
       
   137 }
       
   138 
       
   139 /*LOCAL_C void PrintMeta(const char* aText, TMetaData& aMeta)
       
   140 {
       
   141     RDebug::Printf("=========== HeapMetaData (local) - begin: %s", aText);
       
   142 
       
   143     RDebug::Printf("iDLOnly: 0x%08x", aMeta.iDLOnly);
       
   144     RDebug::Printf("iChunkSize: 0x%08x", aMeta.iChunkSize);
       
   145     RDebug::Printf("iSlabThreshold: 0x%08x / %d", aMeta.iSlabThreshold, aMeta.iSlabThreshold);
       
   146     RDebug::Printf("iSlabInitThreshold: 0x%08x / %d", aMeta.iSlabInitThreshold, aMeta.iSlabInitThreshold);
       
   147     RDebug::Printf("iSlabConfigBits: 0x%08x", aMeta.iSlabConfigBits);
       
   148     RDebug::Printf("iPartialPage: 0x%08x", aMeta.iPartialPage);
       
   149     RDebug::Printf("iFullSlab: 0x%08x", aMeta.iFullSlab);
       
   150     RDebug::Printf("iSparePage: 0x%08x", aMeta.iSparePage);
       
   151     RDebug::Printf("iMemBase: 0x%08x", aMeta.iMemBase);
       
   152 
       
   153     TInt i;
       
   154     TInt count;
       
   155     count = sizeof(aMeta.iSizeMap)/sizeof(unsigned char);
       
   156     for (i=0; i<count; ++i)
       
   157         {
       
   158         RDebug::Printf("iSizeMap[%d]: %d", i, aMeta.iSizeMap[i]);
       
   159         }
       
   160     count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset);
       
   161     for (i=0; i<count; ++i)
       
   162         {
       
   163         RDebug::Printf("iSlabAlloc[%d].iPartial: 0x%08x", i, aMeta.iSlabAlloc[i].iPartial);
       
   164         }
       
   165     for (i=0; i<count; ++i)
       
   166         {
       
   167         RDebug::Printf("iSlabAllocRealRootAddress[%d]: 0x%08x", i, aMeta.iSlabAllocRealRootAddress[i]);
       
   168         }
       
   169     RDebug::Printf("=========== HeapMetaData (local) - end");
       
   170 }
       
   171 
       
   172 LOCAL_C void GetAndPrintMeta(RHeap& aHeap, const char* aText, TMetaData& aMeta)
       
   173 {
       
   174     (void)aText;
       
   175     GetMeta(aHeap, aMeta);
       
   176     TSTSLAB_DBG(PrintMeta(aText, aMeta));
       
   177 }
       
   178 
       
   179 #ifndef __KERNEL_MODE__
       
   180 LOCAL_C void Lock(TMetaData& aMeta)
       
   181    {((RFastLock&)*aMeta.iLock).Wait();}
       
   182 
       
   183 LOCAL_C void Unlock(TMetaData& aMeta)
       
   184    {((RFastLock&)*aMeta.iLock).Signal();}
       
   185 #else
       
   186 LOCAL_C void Lock(TMetaData& aMeta)
       
   187    {;}
       
   188 
       
   189 LOCAL_C void Unlock(TMetaData& aMeta)
       
   190    {;}
       
   191 #endif
       
   192 */
       
   193 
       
   194 LOCAL_C  page* PageFor(slab* s)
       
   195     {
       
   196         return reinterpret_cast<page*>(Floor(s, PAGESIZE));
       
   197     }
       
   198 
       
   199    
       
   200 LOCAL_C slab* SlabFor(const void* p)
       
   201 {
       
   202     return (slab*)(Floor(p, SLABSIZE));
       
   203 }
       
   204 
       
   205 LOCAL_C TInt TreeWalk(slab** aRealRootAddress, slab* const* aRoot, TTestWalkFunc aFunc, TAny* aParm, TInt& aOutParm)
       
   206 {
       
   207     TInt count = 0;
       
   208     aOutParm = 0;
       
   209     
       
   210     slab* s = *aRoot;
       
   211     if (!s)
       
   212         return count;
       
   213     
       
   214     for (;;)
       
   215         {
       
   216         slab* c;
       
   217         while ((c = s->iChild1) != 0)
       
   218             s = c;      // walk down left side to end
       
   219         for (;;)
       
   220             {
       
   221             count++;
       
   222             TSTSLAB_DBG(RDebug::Printf("TreeWalk - slab: 0x%08x", s));
       
   223             (void)aParm;
       
   224             if (aFunc == ETestWalk)
       
   225                 {
       
   226                 ;
       
   227                 }
       
   228             else if (aFunc == ETestFindSlab)
       
   229                 {
       
   230                 if ((slab*)aParm == s)
       
   231                     {
       
   232                     aOutParm = 1;
       
   233                     return 0;
       
   234                     }
       
   235                 }
       
   236             
       
   237             c = s->iChild2;
       
   238             if (c)
       
   239                 {   // one step down right side, now try and walk down left
       
   240                 s = c;
       
   241                 break;
       
   242                 }
       
   243             for (;;)
       
   244                 {   // loop to walk up right side
       
   245                 slab** pp = s->iParent;
       
   246                 if (pp == aRealRootAddress)
       
   247                     return count;
       
   248                 s = SlabFor(pp);
       
   249                 if (pp == &s->iChild1)
       
   250                     break;
       
   251                 }
       
   252             }
       
   253         }
       
   254 }
       
   255 
       
   256 LOCAL_C TInt WalkSlabSet(TInt aSlabsetIndex, TMetaData& aMeta, TTestWalkFunc aFunc, TAny* aParm, TInt& aOutParm)
       
   257 {
       
   258     if (aSlabsetIndex >= (MAXSLABSIZE>>2))
       
   259         {
       
   260         return 0;
       
   261         }
       
   262     return TreeWalk(aMeta.iSlabAllocRealRootAddress[aSlabsetIndex], &aMeta.iSlabAlloc[aSlabsetIndex].iPartial, aFunc, aParm, aOutParm);
       
   263 }
       
   264 
       
   265 /*LOCAL_C void DebugPrintSlabs(TInt aSlabsetIndex, TMetaData& aMeta)
       
   266     {
       
   267     //RDebug::Printf("=========== DebugPrintSlabs: %s", aText);
       
   268     RDebug::Printf("=========== DebugPrintSlabs");
       
   269 
       
   270     RDebug::Printf("iSparePage: 0x%08x", aMeta.iSparePage);
       
   271     
       
   272     slab* fullSlab = aMeta.iFullSlab;
       
   273     TInt fullSlabCount = 0;
       
   274     while (fullSlab)
       
   275         {
       
   276         RDebug::Printf("fullSlab: 0x%08x", fullSlab);
       
   277         fullSlabCount++;
       
   278         fullSlab = fullSlab->iChild1;
       
   279         }
       
   280 
       
   281     TInt outParm;
       
   282     TInt partialTreeSlabCount = 0;
       
   283     partialTreeSlabCount += WalkSlabSet(aSlabsetIndex, aMeta, ETestWalk, 0, outParm);
       
   284 
       
   285     slab* partialPageSlab = aMeta.iPartialPage;
       
   286     TInt partialPageSlabCount = 0;
       
   287     while (partialPageSlab)
       
   288         {
       
   289         RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab);
       
   290         partialPageSlabCount++;
       
   291         partialPageSlab = partialPageSlab->iChild1;
       
   292         }
       
   293     }*/
       
   294 
       
   295 LOCAL_C void TestSlabFixedSizeManyThreads(TSlabTestThreadParm& aParm)
       
   296     {
       
   297     RHeap* heap = aParm.iHeap;
       
   298     TInt allocSize = aParm.iAllocSize;
       
   299     TInt initSlabCount = aParm.iInitSlabCount;
       
   300     //TBool useRandomSize = aParm.iUseRandomSize;
       
   301     //TInt threadCount = aParm.iThreadCount;
       
   302     TInt threadIndex = aParm.iThreadIndex;
       
   303 
       
   304     TInt slabsPerPage = PageSize/SLABSIZE;
       
   305 
       
   306     test(initSlabCount % slabsPerPage == 0); // for this test
       
   307     
       
   308 #ifdef _DEBUG
       
   309     TInt allocRealCellSize = allocSize + RHeap::EDebugHdrSize;
       
   310 #else
       
   311     TInt allocRealCellSize = allocSize;
       
   312 #endif
       
   313 
       
   314     TMetaData metaData;
       
   315     GetMeta(*heap, metaData);
       
   316     
       
   317     if (allocRealCellSize >= metaData.iSlabThreshold)
       
   318         {
       
   319         allocRealCellSize = metaData.iSlabThreshold - 1;
       
   320 #ifdef _DEBUG
       
   321         allocSize = allocRealCellSize - RHeap::EDebugHdrSize;
       
   322 #else
       
   323         allocSize = allocRealCellSize;
       
   324 #endif
       
   325         }
       
   326     
       
   327     TAny** pBuf = &PtrBuf[threadIndex][0];
       
   328     TInt i;
       
   329     for (i=0; i<MAX_ALLOCS; ++i)
       
   330         {
       
   331         pBuf[i] = 0;
       
   332         }
       
   333 
       
   334     //Allocate enough cells of the same size to fill initSlabCount (128) slabs
       
   335     TInt slabsetIndex = metaData.iSizeMap[(allocRealCellSize+3)>>2];
       
   336     test(slabsetIndex != 0xff);
       
   337     TInt slabCellSize = 4 + (slabsetIndex * 4);
       
   338     
       
   339     TInt slabPayloadSize = SLABSIZE - sizeof(slabhdr);
       
   340     TInt cellCountPerSlab = slabPayloadSize / slabCellSize;
       
   341     TInt initCellCount = initSlabCount * cellCountPerSlab;
       
   342 
       
   343     TSTSLAB_DBG(RDebug::Printf("=========== Allocate enough cells of the same size to fill %d slabs", initSlabCount));
       
   344     TSTSLAB_DBG(RDebug::Printf("=========== counts: %d %d %d", cellCountPerSlab, initCellCount, slabCellSize));
       
   345 
       
   346     for (i=0; i<initCellCount; ++i)
       
   347         {
       
   348         pBuf[i] = heap->Alloc(allocSize);
       
   349         test(pBuf[i] != 0);
       
   350         }
       
   351 
       
   352     heap->Check();
       
   353 
       
   354     TInt maxI5 = initCellCount + (cellCountPerSlab*(slabsPerPage+1));
       
   355     for (i=initCellCount; i<maxI5; ++i)
       
   356         {
       
   357         pBuf[i] = heap->Alloc(allocSize);
       
   358         test(pBuf[i] != 0);
       
   359         }
       
   360 
       
   361     heap->Check();
       
   362     
       
   363     TAny* p2 = heap->Alloc(allocSize);
       
   364     test(p2 != 0);
       
   365 
       
   366     heap->Check();
       
   367     heap->Free(p2);
       
   368 
       
   369     heap->Check();
       
   370     
       
   371 
       
   372     TInt page2pBufIndexFirst = cellCountPerSlab * slabsPerPage;
       
   373     //TInt page2pBufIndexLast = page2pBufIndexFirst + (cellCountPerSlab * slabsPerPage);
       
   374     
       
   375     slab* partialTreeSlabX1 = SlabFor(pBuf[page2pBufIndexFirst]);
       
   376     page* partialTreeSlabPageX1 = PageFor(partialTreeSlabX1);
       
   377     
       
   378     heap->Free(pBuf[page2pBufIndexFirst]);
       
   379     pBuf[page2pBufIndexFirst] = 0;
       
   380 
       
   381     heap->Check();
       
   382     
       
   383     TAny* p3 = heap->Alloc(allocSize);
       
   384     test(p3 != 0);
       
   385     heap->Check();
       
   386     heap->Free(p3);
       
   387     heap->Check();
       
   388     
       
   389     TInt size2 = metaData.iChunkSize;
       
   390     TSTSLAB_DBG(RDebug::Printf("---- size2: 0x%08x", size2));
       
   391     if (metaData.iSparePage)
       
   392         {
       
   393         size2 -= PageSize;
       
   394         }
       
   395 
       
   396     for (i=0; i<MAX_ALLOCS; ++i)
       
   397         {
       
   398         if (pBuf[i]) {
       
   399             page* page1 = PageFor(SlabFor(pBuf[i]));
       
   400             if (partialTreeSlabPageX1 == page1)
       
   401                 {
       
   402                 heap->Free(pBuf[i]);
       
   403                 pBuf[i] = 0;
       
   404                 }
       
   405             }
       
   406         }
       
   407 
       
   408     heap->Check();
       
   409 
       
   410     TInt size3 = metaData.iChunkSize;
       
   411     if (metaData.iSparePage)
       
   412         {
       
   413         size3 -= PageSize;
       
   414         }
       
   415 
       
   416     TInt bufIndexFirst = cellCountPerSlab;
       
   417     TInt maxI = bufIndexFirst + cellCountPerSlab;
       
   418     for (i=bufIndexFirst; i<=maxI; ++i)
       
   419         {
       
   420         if (pBuf[i])
       
   421             {
       
   422             heap->Free(pBuf[i]);
       
   423             pBuf[i] = 0;
       
   424             }
       
   425         }
       
   426 
       
   427     heap->Check();
       
   428 
       
   429     TInt firstI = cellCountPerSlab * 3;
       
   430     maxI = firstI + cellCountPerSlab;
       
   431     for (i=firstI; i<=maxI; ++i)
       
   432         {
       
   433         if (i % 3 == 0)
       
   434             {
       
   435             if (pBuf[i])
       
   436                 {
       
   437                 heap->Free(pBuf[i]);
       
   438                 pBuf[i] = 0;
       
   439                 }
       
   440             }
       
   441         }
       
   442     
       
   443     heap->Check();
       
   444     
       
   445     //Reallocate cells.
       
   446     for (i=0; i<(MAX_ALLOCS); ++i)
       
   447         {
       
   448         if (pBuf[i] != 0)
       
   449             {
       
   450             pBuf[i] = heap->ReAlloc(pBuf[i], allocSize);
       
   451             test(pBuf[i] != 0);
       
   452             }
       
   453         }
       
   454     
       
   455     heap->Check();
       
   456     
       
   457     //Allocate cells.
       
   458     for (i=0; i<(MAX_ALLOCS/4); ++i)
       
   459         {
       
   460         if (pBuf[i] == 0)
       
   461             {
       
   462             pBuf[i] = heap->Alloc(allocSize);
       
   463             test(pBuf[i] != 0);
       
   464             }
       
   465         }
       
   466 
       
   467     heap->Check();
       
   468     
       
   469     for (i=0; i<MAX_ALLOCS; ++i)
       
   470         {
       
   471         if (pBuf[i])
       
   472             {
       
   473             heap->Free(pBuf[i]);
       
   474             pBuf[i] = 0;
       
   475             }
       
   476         }
       
   477     heap->Check();
       
   478 
       
   479     TSTSLAB_DBG(RDebug::Printf("=========== TestSlabFixedSizeManyThreads end"));
       
   480     }
       
   481     
       
   482     
       
   483 LOCAL_C void TestSlabFixedSizeOneThread(TSlabTestThreadParm& aParm)
       
   484     {
       
   485     RHeap* heap = aParm.iHeap;
       
   486     TInt allocSize = aParm.iAllocSize;
       
   487     TInt initSlabCount = aParm.iInitSlabCount;
       
   488     //TBool useRandomSize = aParm.iUseRandomSize;
       
   489     //TInt threadCount = aParm.iThreadCount;
       
   490     TInt threadIndex = aParm.iThreadIndex;
       
   491 
       
   492     TInt slabsPerPage = PageSize/SLABSIZE;
       
   493 
       
   494     test(initSlabCount % slabsPerPage == 0); // for this test
       
   495     
       
   496 #ifdef _DEBUG
       
   497     TInt allocRealCellSize = allocSize + RHeap::EDebugHdrSize;
       
   498 #else
       
   499     TInt allocRealCellSize = allocSize;
       
   500 #endif
       
   501 
       
   502     TMetaData metaData;
       
   503     GetMeta(*heap, metaData);
       
   504     
       
   505     TSTSLAB_DBG(PrintMeta(" --- TestSlabFixedSizeOneThread start", metaData));
       
   506 
       
   507     if (allocRealCellSize >= metaData.iSlabThreshold)
       
   508         {
       
   509         allocRealCellSize = metaData.iSlabThreshold - 1;
       
   510 #ifdef _DEBUG
       
   511         allocSize = allocRealCellSize - RHeap::EDebugHdrSize;
       
   512 #else
       
   513         allocSize = allocRealCellSize;
       
   514 #endif
       
   515         }
       
   516 
       
   517     TAny** pBuf = &PtrBuf[threadIndex][0];
       
   518     TInt i;
       
   519     for (i=0; i<MAX_ALLOCS; ++i)
       
   520         {
       
   521         pBuf[i] = 0;
       
   522         }
       
   523 
       
   524     //Allocate enough cells of the same size to fill initSlabCount (128) slabs
       
   525     TInt slabsetIndex = metaData.iSizeMap[(allocRealCellSize+3)>>2];
       
   526     test(slabsetIndex != 0xff);
       
   527     TInt slabCellSize = 4 + (slabsetIndex * 4);
       
   528     
       
   529     TInt slabPayloadSize = SLABSIZE - sizeof(slabhdr);
       
   530     TInt cellCountPerSlab = slabPayloadSize / slabCellSize;
       
   531     TInt initCellCount = initSlabCount * cellCountPerSlab;
       
   532 
       
   533     TSTSLAB_DBG(RDebug::Printf("=========== Allocate enough cells of the same size to fill %d slabs", initSlabCount));
       
   534     TSTSLAB_DBG(RDebug::Printf("=========== counts: %d %d %d", cellCountPerSlab, initCellCount, slabCellSize));
       
   535 
       
   536     for (i=0; i<initCellCount; ++i)
       
   537         {
       
   538         pBuf[i] = heap->Alloc(allocSize);
       
   539         test(pBuf[i] != 0);
       
   540         }
       
   541 
       
   542     heap->Check();
       
   543     GetMeta(*heap, metaData);
       
   544     
       
   545     TSTSLAB_DBG(PrintMeta("after init allocs", metaData));
       
   546     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   547 
       
   548     //Check the number of pages used corresponds to the number of slabs.
       
   549     TSTSLAB_DBG(RDebug::Printf("=========== Check the number of pages used corresponds to the number of slabs"));
       
   550     
       
   551     TInt pageCountForSlabs1 = (metaData.iChunkSize / PageSize) - 1;
       
   552     TInt pageCountForSlabs2 = (initSlabCount+(slabsPerPage-1)) / slabsPerPage;
       
   553     TSTSLAB_DBG(RDebug::Printf("=========== page counts: %d %d", pageCountForSlabs1, pageCountForSlabs2));
       
   554     test(pageCountForSlabs1 == pageCountForSlabs2);
       
   555 
       
   556     //-----------------------------------------
       
   557     TSTSLAB_DBG(RDebug::Printf("=========== check slab counts in the lists"));
       
   558     
       
   559     slab* fullSlab = metaData.iFullSlab;
       
   560     TInt fullSlabCount = 0;
       
   561     while (fullSlab)
       
   562         {
       
   563         TSTSLAB_DBG(RDebug::Printf("fullSlab: 0x%08x", fullSlab));
       
   564         fullSlabCount++;
       
   565         fullSlab = fullSlab->iChild1;
       
   566         }
       
   567 
       
   568     TInt outParm;
       
   569     TInt partialTreeSlabCount = 0;
       
   570     partialTreeSlabCount = WalkSlabSet(slabsetIndex, metaData, ETestWalk, 0, outParm);
       
   571 
       
   572     slab* partialPageSlab = metaData.iPartialPage;
       
   573     TInt partialPageSlabCount = 0;
       
   574     while (partialPageSlab)
       
   575         {
       
   576         TSTSLAB_DBG(RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab));
       
   577         partialPageSlabCount++;
       
   578         partialPageSlab = partialPageSlab->iChild1;
       
   579         }
       
   580 
       
   581     test(fullSlabCount == (initSlabCount-1));
       
   582     test(partialTreeSlabCount == 1);
       
   583     if (initSlabCount % slabsPerPage == 0)
       
   584         {
       
   585         test(partialPageSlabCount == 0);
       
   586         }
       
   587     else
       
   588         {
       
   589         test(partialPageSlabCount == 1);
       
   590         }
       
   591     //-----------------------------------------
       
   592     TSTSLAB_DBG(RDebug::Printf("=========== alloc one cell more -> one full slab more"));
       
   593 
       
   594     TAny* p = heap->Alloc(allocSize);
       
   595     test(p != 0);
       
   596     
       
   597     heap->Check();
       
   598     GetMeta(*heap, metaData);
       
   599     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   600     
       
   601     fullSlab = metaData.iFullSlab;
       
   602     fullSlabCount = 0;
       
   603     while (fullSlab)
       
   604         {
       
   605         TSTSLAB_DBG(RDebug::Printf("fullSlab: 0x%08x", fullSlab));
       
   606         fullSlabCount++;
       
   607         fullSlab = fullSlab->iChild1;
       
   608         }
       
   609     test(fullSlabCount == initSlabCount);
       
   610 
       
   611     heap->Free(p);
       
   612 
       
   613     heap->Check();
       
   614     GetMeta(*heap, metaData);
       
   615     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   616     
       
   617     //-----------------------------------------
       
   618     //Check that a new slab is taken from a partially filled page if available.
       
   619     TSTSLAB_DBG(RDebug::Printf("=========== Check that a new slab is taken from a partially filled page if available"));
       
   620 
       
   621     // fill the first slab in the page (after iSparePage)
       
   622     TInt maxI5 = initCellCount + (cellCountPerSlab*(slabsPerPage+1));
       
   623     for (i=initCellCount; i<maxI5; ++i)
       
   624         {
       
   625         pBuf[i] = heap->Alloc(allocSize);
       
   626         test(pBuf[i] != 0);
       
   627         }
       
   628 
       
   629     heap->Check();
       
   630     GetMeta(*heap, metaData);
       
   631     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   632     
       
   633     partialPageSlab = metaData.iPartialPage;
       
   634     partialPageSlabCount = 0;
       
   635     while (partialPageSlab)
       
   636         {
       
   637         TSTSLAB_DBG(RDebug::Printf("partialPageSlab (empty): 0x%08x", partialPageSlab));
       
   638         partialPageSlabCount++;
       
   639         partialPageSlab = partialPageSlab->iChild1;
       
   640         }
       
   641     test(partialPageSlabCount == 1);
       
   642 
       
   643     page* page1 = PageFor(metaData.iPartialPage);
       
   644     unsigned header = page1->iSlabs[0].iHeader;
       
   645     unsigned pagemap = SlabHeaderPagemap(header);
       
   646     unsigned slabix = LOWBIT(pagemap);
       
   647     slab* partialPageSlab2 = &page1->iSlabs[slabix];
       
   648     
       
   649     TAny* p2 = heap->Alloc(allocSize);
       
   650     test(p2 != 0);
       
   651 
       
   652     heap->Check();
       
   653     TSTSLAB_DBG(RDebug::Printf("p2: 0x%08x; partialPageSlab2: 0x%08x", p2, partialPageSlab2));
       
   654     test(partialPageSlab2 == SlabFor(p2));
       
   655     heap->Free(p2);
       
   656 
       
   657     heap->Check();
       
   658     
       
   659     //-----------------------------
       
   660     // use the second page for the next test
       
   661     TInt page2pBufIndexFirst = cellCountPerSlab * slabsPerPage;
       
   662     //TInt page2pBufIndexLast = page2pBufIndexFirst + (cellCountPerSlab * slabsPerPage);
       
   663     
       
   664     //-----------------------------------------
       
   665     //Check that a partially filled slab is used if available.
       
   666     TSTSLAB_DBG(RDebug::Printf("=========== Check that a partially filled slab is used if available"));
       
   667 
       
   668     slab* partialTreeSlabX1 = SlabFor(pBuf[page2pBufIndexFirst]);
       
   669     page* partialTreeSlabPageX1 = PageFor(partialTreeSlabX1);
       
   670     
       
   671     heap->Free(pBuf[page2pBufIndexFirst]);
       
   672     pBuf[page2pBufIndexFirst] = 0;
       
   673 
       
   674     heap->Check();
       
   675     
       
   676     TAny* p3 = heap->Alloc(allocSize);
       
   677     test(p3 != 0);
       
   678     heap->Check();
       
   679     test(partialTreeSlabX1 == SlabFor(p3));
       
   680     heap->Free(p3);
       
   681     heap->Check();
       
   682     
       
   683     //-----------------------------------------
       
   684     //Check that if all four slabs in a page are free the page is freed.
       
   685     TSTSLAB_DBG(RDebug::Printf("=========== Check that if all four slabs in a page are free, the page is freed"));
       
   686 
       
   687     GetMeta(*heap, metaData);
       
   688     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   689 
       
   690     TInt size2 = metaData.iChunkSize;
       
   691     TSTSLAB_DBG(RDebug::Printf("---- size2: 0x%08x", size2));
       
   692     if (metaData.iSparePage)
       
   693         {
       
   694         size2 -= PageSize;
       
   695         }
       
   696 
       
   697     for (i=0; i<MAX_ALLOCS; ++i)
       
   698         {
       
   699         if (pBuf[i]) {
       
   700             page* page1 = PageFor(SlabFor(pBuf[i]));
       
   701             if (partialTreeSlabPageX1 == page1)
       
   702                 {
       
   703                 heap->Free(pBuf[i]);
       
   704                 pBuf[i] = 0;
       
   705                 }
       
   706             }
       
   707         }
       
   708 
       
   709     heap->Check();
       
   710     GetMeta(*heap, metaData);
       
   711     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   712 
       
   713     TInt size3 = metaData.iChunkSize;
       
   714     if (metaData.iSparePage)
       
   715         {
       
   716         size3 -= PageSize;
       
   717         }
       
   718 
       
   719     test(size3 == (size2-PageSize));
       
   720 
       
   721     //-----------------------------------------
       
   722     //Free cells to give empty slab (The second slab in the first page)
       
   723     TSTSLAB_DBG(RDebug::Printf("=========== Free cells to give empty slab (The second slab in the first page)"));
       
   724     slab* emptySlabAddr = (slab*)(metaData.iMemBase + SLABSIZE);
       
   725 
       
   726     //Check that emptySlabAddr is not already in iPartialPage list
       
   727     partialPageSlab = metaData.iPartialPage;
       
   728     while (partialPageSlab)
       
   729         {
       
   730         if (partialPageSlab == emptySlabAddr)
       
   731             {
       
   732             test(0);
       
   733             }
       
   734         partialPageSlab = partialPageSlab->iChild1;
       
   735         }
       
   736 
       
   737     // free cells to give empty slab  - emptySlabAddr
       
   738     TInt bufIndexFirst = cellCountPerSlab;
       
   739     TInt maxI = bufIndexFirst + cellCountPerSlab;
       
   740     for (i=bufIndexFirst; i<=maxI; ++i)
       
   741         {
       
   742         if (pBuf[i])
       
   743             {
       
   744             heap->Free(pBuf[i]);
       
   745             pBuf[i] = 0;
       
   746             }
       
   747         }
       
   748 
       
   749     heap->Check();
       
   750     GetMeta(*heap, metaData);
       
   751     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   752 
       
   753     // Check that emptySlabAddr is not now in iPartialPage list
       
   754     partialPageSlab = metaData.iPartialPage;
       
   755     while (partialPageSlab)
       
   756         {
       
   757         if (partialPageSlab == emptySlabAddr)
       
   758             {
       
   759             break;
       
   760             }
       
   761         partialPageSlab = partialPageSlab->iChild1;
       
   762         }
       
   763     test(partialPageSlab != 0);
       
   764 
       
   765     //Free cells to give partial slab (The third slab in the first page)
       
   766     TSTSLAB_DBG(RDebug::Printf("=========== Free cells to give partial slab (The third slab in the first page)"));
       
   767     slab* partialSlabAddr = (slab*)(metaData.iMemBase + (3*SLABSIZE));
       
   768 
       
   769     // Check that partialSlabAddr is not now in iPartialSlab list
       
   770     WalkSlabSet(slabsetIndex, metaData, ETestFindSlab, partialSlabAddr, outParm);
       
   771     test(outParm == 0);
       
   772 
       
   773     TInt firstI = cellCountPerSlab * 3;
       
   774     maxI = firstI + cellCountPerSlab;
       
   775     for (i=firstI; i<=maxI; ++i)
       
   776         {
       
   777         if (i % 3 == 0)
       
   778             {
       
   779             if (pBuf[i])
       
   780                 {
       
   781                 heap->Free(pBuf[i]);
       
   782                 pBuf[i] = 0;
       
   783                 }
       
   784             }
       
   785         }
       
   786     
       
   787     heap->Check();
       
   788     GetMeta(*heap, metaData);
       
   789     TSTSLAB_DBG(DebugPrintSlabs(slabsetIndex, metaData));
       
   790     
       
   791     // Check that partialSlabAddr is now in iPartialSlab list
       
   792     WalkSlabSet(slabsetIndex, metaData, ETestFindSlab, partialSlabAddr, outParm);
       
   793     test(outParm == 1);
       
   794     
       
   795     //Reallocate cells.
       
   796     for (i=0; i<(MAX_ALLOCS); ++i)
       
   797         {
       
   798         if (pBuf[i] != 0)
       
   799             {
       
   800             pBuf[i] = heap->ReAlloc(pBuf[i], allocSize);
       
   801             test(pBuf[i] != 0);
       
   802             }
       
   803         }
       
   804 
       
   805     heap->Check();
       
   806     
       
   807     //Allocate cells.
       
   808     for (i=0; i<(MAX_ALLOCS/4); ++i)
       
   809         {
       
   810         if (pBuf[i] == 0)
       
   811             {
       
   812             pBuf[i] = heap->Alloc(allocSize);
       
   813             test(pBuf[i] != 0);
       
   814             }
       
   815         }
       
   816 
       
   817     heap->Check();
       
   818     
       
   819     for (i=0; i<MAX_ALLOCS; ++i)
       
   820         {
       
   821         if (pBuf[i])
       
   822             {
       
   823             heap->Free(pBuf[i]);
       
   824             pBuf[i] = 0;
       
   825             }
       
   826         }
       
   827     heap->Check();
       
   828 
       
   829     TSTSLAB_DBG(RDebug::Printf("=========== TestSlabFixedSizeOneThread end"));
       
   830     }
       
   831 
       
   832 LOCAL_C RHeap* CreateSlabHeap(TInt aThreadCount)
       
   833 {
       
   834     //TPtrC slabHeap=_L("SlabHeap");
       
   835     //RHeap* heap = User::ChunkHeap(&slabHeap, 0x1000, 0x10000);
       
   836     TInt maxLth = 0x60000 * aThreadCount;
       
   837     RHeap* heap = User::ChunkHeap(0, 0x1000, maxLth);
       
   838     test(heap!=NULL);
       
   839 
       
   840     // Configure heap for slab
       
   841     RHybridHeap::STestCommand cmd;
       
   842     cmd.iCommand = RHybridHeap::ESetConfig;
       
   843     cmd.iConfig.iSlabBits = 0xabe;
       
   844     cmd.iConfig.iDelayedSlabThreshold = 0;
       
   845     cmd.iConfig.iPagePower = 0;  // 16 // 0 -> no page allocator
       
   846     TInt ret = heap->DebugFunction(RHeap::EHybridHeap, &cmd, 0);
       
   847     test(ret == KErrNone);
       
   848     
       
   849     return heap;
       
   850 }
       
   851 
       
   852 LOCAL_C TInt SlabTestManyThreads(TAny* aThreadParm)
       
   853     {
       
   854     TSlabTestThreadParm* parm = (TSlabTestThreadParm*)aThreadParm;
       
   855 
       
   856     TInt i;
       
   857     TInt maxLoops = 30; //300;
       
   858     for (i=0; i<maxLoops; ++i)
       
   859         {
       
   860         TestSlabFixedSizeManyThreads(*parm);
       
   861         }
       
   862                                 
       
   863     return KErrNone;
       
   864     }
       
   865     
       
   866 LOCAL_C TInt SlabTestOneThread(TAny* aThreadParm)
       
   867     {
       
   868     TSlabTestThreadParm* parm = (TSlabTestThreadParm*)aThreadParm;
       
   869     TestSlabFixedSizeOneThread(*parm);
       
   870     return KErrNone;
       
   871     }
       
   872     
       
   873 TInt StartThreads(TInt aThreadCount, TSlabTestThreadParm& aThreadParm)
       
   874     {
       
   875     const TInt KSlabTestThreadStackSize=0x4000; //0x10000; //0x2000;
       
   876 
       
   877     TRequestStatus  theStatus[MAX_THREADS];
       
   878     RThread         theThreads[MAX_THREADS];
       
   879     TBool           threadInUse[MAX_THREADS];
       
   880 
       
   881     TInt index;
       
   882     TInt ret;
       
   883 
       
   884     if (aThreadCount <= 0)
       
   885         {
       
   886         return KErrNone;
       
   887         }
       
   888 
       
   889     RHeap* heap = CreateSlabHeap(aThreadCount);
       
   890     aThreadParm.iHeap = heap;
       
   891     
       
   892     for (index = 0; index < aThreadCount; index++)
       
   893         {
       
   894         ThreadParm[index].iHeap             = aThreadParm.iHeap;
       
   895         ThreadParm[index].iAllocSize        = aThreadParm.iAllocSize;
       
   896         ThreadParm[index].iInitSlabCount    = aThreadParm.iInitSlabCount;
       
   897         ThreadParm[index].iUseRandomSize    = aThreadParm.iUseRandomSize;
       
   898         ThreadParm[index].iThreadCount      = aThreadParm.iThreadCount;
       
   899         
       
   900         ThreadParm[index].iThreadIndex = index;
       
   901         
       
   902         TBuf<32> threadName;
       
   903         threadName.Format(_L("SlabTest%d"), index);
       
   904         if (aThreadCount == 1)
       
   905             {
       
   906             ret = theThreads[index].Create(threadName, SlabTestOneThread, KSlabTestThreadStackSize, NULL, (TAny*)&ThreadParm[index]);
       
   907             }
       
   908         else
       
   909             {
       
   910             ret = theThreads[index].Create(threadName, SlabTestManyThreads, KSlabTestThreadStackSize, NULL, (TAny*)&ThreadParm[index]);
       
   911             }
       
   912         test(ret == KErrNone);
       
   913         theThreads[index].Logon(theStatus[index]);
       
   914         test(theStatus[index] == KRequestPending);
       
   915         threadInUse[index] = ETrue;
       
   916         theThreads[index].Resume();
       
   917         }
       
   918 
       
   919     User::WaitForAnyRequest();
       
   920     
       
   921     TBool anyUsed = ETrue;
       
   922     while (anyUsed)
       
   923         {
       
   924         User::After(1001000);
       
   925         anyUsed = EFalse;
       
   926         for (index = 0; index < aThreadCount; index++)
       
   927             {
       
   928             if (threadInUse[index])
       
   929                 {
       
   930                 if (theThreads[index].ExitType() != EExitPending)
       
   931                     {
       
   932                     threadInUse[index] = EFalse;
       
   933                     }
       
   934                 else
       
   935                     {
       
   936                     anyUsed = ETrue;
       
   937                     }
       
   938                 }
       
   939             }
       
   940         }
       
   941     
       
   942     for (index = 0; index < aThreadCount; index++)
       
   943         {
       
   944         theThreads[index].Close();
       
   945         }
       
   946     TSTSLAB_DBG(RDebug::Printf("=========== StartThreads end"));
       
   947     heap->Close();
       
   948 
       
   949     return KErrNone;
       
   950     }
       
   951 
       
   952 GLDEF_C TInt E32Main(void)
       
   953     {
       
   954     TInt ret;
       
   955     
       
   956     test.Title();
       
   957 
       
   958     __KHEAP_MARK;
       
   959     
       
   960     test.Start(_L("TestSlab"));
       
   961     UserHal::PageSizeInBytes(PageSize);
       
   962 
       
   963     RHeap* heap = CreateSlabHeap(1);
       
   964     
       
   965     TMetaData metaData;
       
   966     GetMeta(*heap, metaData);
       
   967 
       
   968     heap->Close();
       
   969 
       
   970     if (metaData.iDLOnly)
       
   971         {
       
   972         test.Printf(_L("Slab allocator is not used, no tests to run\n"));
       
   973         __KHEAP_MARKEND;
       
   974         test.End();
       
   975         return(0);
       
   976         }
       
   977     
       
   978     TSlabTestThreadParm threadParm;
       
   979     threadParm.iHeap = heap;
       
   980     threadParm.iAllocSize = 17;
       
   981     threadParm.iInitSlabCount = 128; // 12
       
   982     threadParm.iUseRandomSize = EFalse;
       
   983 
       
   984     test.Next(_L("TestSlab - one thread"));
       
   985 
       
   986     TInt threadCount;
       
   987     threadCount = 1;
       
   988     if (threadCount > MAX_THREADS)
       
   989         {
       
   990         threadCount = MAX_THREADS;
       
   991         }
       
   992     threadParm.iThreadCount = threadCount;
       
   993     
       
   994 #if 0
       
   995     ret = StartThreads(threadCount, threadParm);
       
   996     test(ret==KErrNone);
       
   997     
       
   998 #else   
       
   999     
       
  1000     TInt i;
       
  1001     for (i=1; i<metaData.iSlabThreshold; ++i)
       
  1002         {
       
  1003 #ifdef _DEBUG
       
  1004         if ((i + RHeap::EDebugHdrSize) >= metaData.iSlabThreshold)
       
  1005             {
       
  1006             break;
       
  1007             }
       
  1008 #endif // _DEBUG
       
  1009         TSTSLAB_DBG(RDebug::Printf("=========== StartThreads size: %d", i));
       
  1010         threadParm.iAllocSize = i;
       
  1011         test.Printf(_L("AllocSize: %d\n"), i);
       
  1012         ret = StartThreads(threadCount, threadParm);
       
  1013         test(ret==KErrNone);
       
  1014         }
       
  1015 #endif
       
  1016 
       
  1017     
       
  1018     test.Next(_L("TestSlab - many threads"));
       
  1019 
       
  1020     threadParm.iAllocSize = 17;
       
  1021     
       
  1022     threadCount = 3;
       
  1023     if (threadCount > MAX_THREADS)
       
  1024         {
       
  1025         threadCount = MAX_THREADS;
       
  1026         }
       
  1027     threadParm.iThreadCount = threadCount;
       
  1028     
       
  1029 #if 1
       
  1030     ret = StartThreads(threadCount, threadParm);
       
  1031     test(ret==KErrNone);
       
  1032     
       
  1033 #else   
       
  1034     
       
  1035     TInt i;
       
  1036     for (i=1; i<metaData.iSlabThreshold; ++i)
       
  1037         {
       
  1038 #ifdef _DEBUG
       
  1039         if ((i + RHeap::EDebugHdrSize) >= metaData.iSlabThreshold)
       
  1040             {
       
  1041             break;
       
  1042             }
       
  1043 #endif // _DEBUG
       
  1044         TSTSLAB_DBG(RDebug::Printf("=========== StartThreads size: %d", i));
       
  1045         threadParm.iAllocSize = i;
       
  1046         test.Printf(_L("AllocSize: %d\n"), i);
       
  1047         ret = StartThreads(threadCount, threadParm);
       
  1048         test(ret==KErrNone);
       
  1049         }
       
  1050 #endif
       
  1051 
       
  1052     __KHEAP_MARKEND;
       
  1053     
       
  1054     test.End();
       
  1055     return(0);
       
  1056     }