kerneltest/e32test/heap/t_heapstress.cpp
changeset 109 b3a1d9898418
child 293 0659d0e1a03c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/heap/t_heapstress.cpp	Fri May 14 17:13:29 2010 +0300
@@ -0,0 +1,1233 @@
+// Copyright (c) 2002-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_heaphybridstress.cpp
+// Overview:
+// Tests RHybridHeap class: stress test
+// API Information:
+// RHybridHeap/RHeap
+// Details:
+// - Stress test heap implementation that allocates, frees
+//   and reallocates cells in random patterns, and checks the heap.
+// - Allocated/reallocated buffer content is verified, when buffer is freed/reallocated.
+// - Stress test with a single thread
+// - Stress test with two threads that run concurrently.
+// - Tests configured for slab, doug lea, paged and hybrid allocators
+// Platforms/Drives/Compatibility:
+// All
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+// 
+//
+
+#include <e32test.h>
+#include <e32hal.h>
+#include <e32def.h>
+#include <e32def_private.h>
+#include "dla.h"
+#include "slab.h"
+#include "page_alloc.h"
+#include "heap_hybrid.h"
+
+// Needed for KHeapShrinkHysRatio which is now ROM 'patchdata'
+#include "TestRHeapShrink.h"
+
+//-------------------------------------------
+
+//#define TSTDBG_PRINTMETA(a) a
+#define TSTDBG_PRINTMETA(a)
+
+//-------------------------------------------
+
+
+#ifdef __EABI__
+       IMPORT_D extern const TInt KHeapMinCellSize;
+#else
+       const TInt KHeapMinCellSize = 0;
+#endif
+
+RTest test(_L("T_HEAPSTRESS"));
+
+#define TEST_ALIGN(p,a)     test((TLinAddr(p)&((a)-1))==0)
+
+
+#define TST_HEAP_MAX_LTH 0x4000000 // 64M
+#define MAX_CELL_COUNT 0x100000 // 0x100 0x1000 0x10000 0x100000
+#define MAX_THREAD_COUNT 2
+LOCAL_D TUint8* HeapStressCell[MAX_THREAD_COUNT][MAX_CELL_COUNT];
+LOCAL_D TInt HeapStressLen[MAX_THREAD_COUNT][MAX_CELL_COUNT];
+
+enum TTestHybridHeapFunc {ETstOnlySlab, ETstOnlyDl, ETstOnlyPaged, ETstHybrid};
+enum TTestType {ETestE32Test, ETestForeverOne, ETestForeverAll};
+
+LOCAL_D TTimeIntervalMicroSeconds32 TickPeriod;
+
+//--------- config parameters - begin
+LOCAL_D TTestType TestType;
+LOCAL_D TInt TestTimeAsSeconds;
+LOCAL_D TBool TestForeverMultiThreadTest;
+LOCAL_D TTestHybridHeapFunc TestHybridHeapFunc;
+LOCAL_D TInt CurrMaxCellCount;
+LOCAL_D TInt HeapMaxLength;
+//--------- config parameters - end
+
+LOCAL_D TBool DlOnly;
+
+LOCAL_D TInt SlabThreshold;
+LOCAL_D TInt PageThreshold;
+
+
+struct TMetaData
+    {
+    TBool           iDLOnly;
+    RFastLock*      iLock;
+    TInt            iChunkSize;
+    TInt            iSlabThreshold;
+    TInt            iPageThreshold;
+    TInt            iSlabInitThreshold;
+    TUint32         iSlabConfigBits;
+    slab*           iPartialPage;
+    slab*           iFullSlab;
+    page*           iSparePage;
+    TUint8*         iMemBase;
+    TUint8          iSizeMap[(MAXSLABSIZE>>2)+1];
+    slabset         iSlabAlloc[MAXSLABSIZE>>2];
+    slab**          iSlabAllocRealRootAddress[MAXSLABSIZE>>2];
+    };
+
+class TestHybridHeap
+    {
+public:
+    static void GetHeapMetaData(RHeap& aHeap, TMetaData& aMeta);
+    };
+
+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.iPageThreshold       = hybridHeap->iPageThreshold;
+    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);
+}
+
+
+TSTDBG_PRINTMETA(
+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("iPageThreshold: 0x%08x / %d", aMeta.iPageThreshold, aMeta.iPageThreshold);
+    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<count; ++i)
+        {
+        RDebug::Printf("iSizeMap[%d]: %d", i, aMeta.iSizeMap[i]);
+        }
+    count = sizeof(aMeta.iSlabAlloc)/sizeof(slabset);
+    for (i=0; i<count; ++i)
+        {
+        RDebug::Printf("iSlabAlloc[%d].iPartial: 0x%08x", i, aMeta.iSlabAlloc[i].iPartial);
+        }
+    for (i=0; i<count; ++i)
+        {
+        RDebug::Printf("iSlabAllocRealRootAddress[%d]: 0x%08x", i, aMeta.iSlabAllocRealRootAddress[i]);
+        }
+    RDebug::Printf("=========== HeapMetaData (local) - end");
+}
+)
+
+LOCAL_C void ConfHeap(RHeap* aHeap)
+{
+    RHybridHeap::STestCommand cmd;
+
+    if (TestHybridHeapFunc == ETstOnlySlab)
+        {
+        cmd.iCommand = RHybridHeap::ESetConfig;
+        cmd.iConfig.iSlabBits = 0xabe;
+        cmd.iConfig.iDelayedSlabThreshold = 0;            // 0 -> use slab at once from the beginning
+        cmd.iConfig.iPagePower = 0;                       // 0 -> no page allocator
+        }
+    else if (TestHybridHeapFunc == ETstOnlyDl)
+        {
+        cmd.iCommand = RHybridHeap::ESetConfig;
+        cmd.iConfig.iSlabBits = 0xabe;
+        cmd.iConfig.iDelayedSlabThreshold = 0x40000000;   // 1G -> slab never used
+        cmd.iConfig.iPagePower = 0;                       // 0 -> no page allocator
+        }
+    else if (TestHybridHeapFunc == ETstOnlyPaged)
+        {
+        cmd.iCommand = RHybridHeap::ESetConfig;
+        cmd.iConfig.iSlabBits = 0xabe;
+        cmd.iConfig.iDelayedSlabThreshold = 0x40000000;   // 1G -> slab never used
+        cmd.iConfig.iPagePower = 14;                      // min page 14 -> 16K
+        }
+    else if (TestHybridHeapFunc == ETstHybrid)
+        {
+        cmd.iCommand = RHybridHeap::ESetConfig;
+        cmd.iConfig.iSlabBits = 0xabe;
+        cmd.iConfig.iDelayedSlabThreshold = 0;            // 0 -> use slab at once from the beginning
+        cmd.iConfig.iPagePower = 14;                      // min page 14 -> 16K
+        }
+    else
+        {
+        test(0);
+        }
+    
+    TInt ret = aHeap->DebugFunction(RHeap::EHybridHeap, &cmd, 0);
+    test(ret == KErrNone);
+}
+
+LOCAL_C TInt MinPagedAllocLength(void)
+{
+    return (1 << PageThreshold);
+}
+
+LOCAL_C TUint32 RandomPagedLength(TUint32 aRandom)
+{
+    TUint32 ret;
+    ret = aRandom;
+    ret <<= PageThreshold;
+    if (TestHybridHeapFunc == ETstOnlyPaged)
+        {
+        //ret &= 0xfffff; // below 1M
+        ret &= 0x7ffff; // below 512K
+        }
+    else
+        {
+        ret &= 0x1ffff; // below 128K
+        }
+    if (ret == 0)
+        {
+        ret = MinPagedAllocLength();
+        }
+    return ret;
+}
+
+#if 0            
+LOCAL_C TUint TicksAsMilliSeconds(TUint aTicks)
+{
+    TUint time = TUint((TUint64)aTicks*(TUint64)TickPeriod.Int()/(TUint64)1000);
+    return time;
+}
+#endif
+
+LOCAL_C TBool IsDlOnly(void)
+{
+    TestHybridHeapFunc = ETstHybrid;
+    
+    RHeap* heap;
+    heap = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x4000, 0x1000, 4);
+    test(heap != NULL);
+
+    ConfHeap(heap);
+    
+    TMetaData metaData;
+    GetMeta(*heap, metaData);
+    
+    heap->Close();
+    return metaData.iDLOnly;
+}
+
+LOCAL_C RHeap* CreateTestHeap(TInt aAlign)
+{
+    if (HeapMaxLength > TST_HEAP_MAX_LTH)
+        {
+        HeapMaxLength = TST_HEAP_MAX_LTH;
+        }
+    
+    if (CurrMaxCellCount > MAX_CELL_COUNT)
+        {
+        CurrMaxCellCount = MAX_CELL_COUNT;
+        }
+    
+    RHeap* heap;
+    heap = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, HeapMaxLength, 0x1000, aAlign);
+    test(heap != NULL);
+
+    ConfHeap(heap);
+    
+    TMetaData metaData;
+    GetMeta(*heap, metaData);
+    
+    if (TestHybridHeapFunc == ETstOnlySlab)
+        {
+        SlabThreshold = metaData.iSlabThreshold;
+        test(SlabThreshold != 0);
+        }
+    else if (TestHybridHeapFunc == ETstOnlyDl)
+        {
+        }
+    else if (TestHybridHeapFunc == ETstOnlyPaged)
+        {
+        PageThreshold = metaData.iPageThreshold;
+        test(PageThreshold >= 14);
+        }
+    else if (TestHybridHeapFunc == ETstHybrid)
+        {
+        }
+    else
+        {
+        test(0);
+        }
+
+    return heap;
+}
+
+//-------------------------------------------------------------------
+
+struct STestCell
+    {
+    enum {EMagic = 0xb8aa3b29};
+
+    TUint32 iLength;
+    TUint32 iData[1];
+
+    void Set(TInt aLength);
+    void Verify(TInt aLength);
+    void Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength);
+    };
+
+void STestCell::Set(TInt aLength)
+    {
+    TInt i;
+    TUint32 x = (TUint32)this ^ (TUint32)aLength ^ (TUint32)EMagic;
+    if (aLength < (TInt) sizeof(iLength))
+        {
+        return;
+        }
+    iLength = x;
+    aLength /= sizeof(TUint32);
+    for (i=0; i<aLength-1; ++i)
+        {
+        x *= 69069;
+        x += 41;
+        iData[i] = x;
+        }
+    }
+
+void STestCell::Verify(TInt aLength)
+    {
+    Verify(this, aLength, aLength);
+    }
+
+void STestCell::Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength)
+    {
+    TInt i;
+    TUint32 x = (TUint32)aInitPtr ^ (TUint32)aInitLength ^ (TUint32)EMagic;
+    if (aLength < (TInt) sizeof(iLength))
+        {
+        return;
+        }
+    test(iLength == x);
+    aLength /= sizeof(TUint32);
+    for (i=0; i<aLength-1; ++i)
+        {
+        x *= 69069;
+        x += 41;
+        test(iData[i] == x);
+        }
+    }
+
+class RTestHeap : public RHeap
+    {
+public:
+    TInt CheckAllocatedCell(const TAny* aCell) const;
+    void FullCheckAllocatedCell(const TAny* aCell) const;
+    TAny* TestAlloc(TInt aSize);
+    void TestFree(TAny* aPtr);
+    TAny* TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0);
+    void FullCheck();
+    static void WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen);
+    };
+
+TInt RTestHeap::CheckAllocatedCell(const TAny* aCell) const
+    {
+    TInt len = AllocLen(aCell);
+    return len;
+    }
+
+void RTestHeap::FullCheckAllocatedCell(const TAny* aCell) const
+    {
+    ((STestCell*)aCell)->Verify(CheckAllocatedCell(aCell));
+    }
+
+TAny* RTestHeap::TestAlloc(TInt aSize)
+    {
+    TAny* p = Alloc(aSize);
+    if (p)
+        {
+        TInt len = CheckAllocatedCell(p);
+        test(len>=aSize);       
+        ((STestCell*)p)->Set(len);
+        }
+    return p;
+    }
+
+void RTestHeap::TestFree(TAny* aPtr)
+    {
+    if (aPtr)
+        {
+        FullCheckAllocatedCell(aPtr);
+        }
+    Free(aPtr);
+    }
+
+TAny* RTestHeap::TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
+    {
+    TInt old_len = aPtr ? CheckAllocatedCell(aPtr) : 0;
+    if (aPtr)
+        ((STestCell*)aPtr)->Verify(old_len);
+    TAny* p = ReAlloc(aPtr, aSize, aMode);
+    if (!p)
+        {
+        ((STestCell*)aPtr)->Verify(old_len);
+        return p;
+        }
+    TInt new_len = CheckAllocatedCell(p);
+    test(new_len>=aSize);       
+    if (p == aPtr)
+        {
+        ((STestCell*)p)->Verify(p, old_len, Min(old_len, new_len));
+        if (new_len != old_len)
+            ((STestCell*)p)->Set(new_len);
+        return p;
+        }
+    test(!(aMode & ENeverMove));
+    test((new_len > old_len) || (aMode & EAllowMoveOnShrink));
+    if (old_len)
+        ((STestCell*)p)->Verify(aPtr, old_len, Min(old_len, aSize));
+    ((STestCell*)p)->Set(new_len);
+    return p;
+    }
+
+struct SHeapCellInfo
+    {
+    RTestHeap* iHeap;
+    TInt iTotalAlloc;
+    TInt iTotalAllocSize;
+    TInt iTotalFree;
+    TUint8* iNextCell;
+    };
+
+void RTestHeap::WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen)
+    {
+    (void)aCell;
+    ::SHeapCellInfo& info = *(::SHeapCellInfo*)aPtr;
+    switch(aType)
+        {
+        case EGoodAllocatedCell:
+            {
+            TInt len = aLen;
+            info.iTotalAllocSize += len;
+            STestCell* pT = (STestCell*)aCell;
+            ++info.iTotalAlloc;
+            pT->Verify(len);
+            break;
+            }
+        case EGoodFreeCell:
+            {
+            ++info.iTotalFree;
+            break;
+            }
+        default:
+            test.Printf(_L("TYPE=%d ??\n"),aType);
+            test(0);
+            break;
+        }
+    }
+
+void RTestHeap::FullCheck()
+    {
+    ::SHeapCellInfo info;
+    Mem::FillZ(&info, sizeof(info));
+    info.iHeap = this;
+    DebugFunction(EWalk, (TAny*)&WalkFullCheckCell, &info);
+    TInt count = AllocSize(iTotalAllocSize);
+    test(info.iTotalAlloc == count);
+    test(info.iTotalAllocSize == iTotalAllocSize);
+    }
+
+
+struct STestStress
+    {
+    RThread iThread;
+    volatile TBool iStop;
+    TInt iAllocs;
+    TInt iFailedAllocs;
+    TInt iFrees;
+    TInt iReAllocs;
+    TInt iFailedReAllocs;
+    TInt iChecks;
+    TUint32 iSeed;
+    RAllocator* iAllocator;
+    TInt iThreadIndex;
+
+    TUint32 Random();
+    };
+
+TUint32 FirstSeed(TInt aThreadIndex)
+    {
+    static TUint32 seed0 = 0xb504f334;
+    static TUint32 seed1 = 0xddb3d743;
+    static TBool first = ETrue;
+
+    TUint32 ret;
+
+    if (aThreadIndex == 0)
+        {
+        ret = seed0;
+        }
+    else
+        {
+        ret = seed1;
+        }
+    
+    if (first)
+        {
+        first = EFalse;
+        }
+    
+    if (aThreadIndex == 0)
+        {
+        seed0 *= 69069;
+        seed0 += 41;
+        }
+    else
+        {
+        seed1 *= 69069;
+        seed1 += 41;
+        }
+
+    test.Printf(_L("FirstSeed: 0x%08x\n"), ret);
+    return ret;
+    }
+
+TUint32 STestStress::Random()
+    {
+    iSeed *= 69069;
+    iSeed += 41;
+    return iSeed;
+    }
+
+TInt RandomLength(TUint32 aRandom)
+    {
+    TUint32 ret = 0;
+    
+    if (TestHybridHeapFunc == ETstOnlySlab)
+        {
+        test(SlabThreshold != 0);
+        ret = aRandom;
+        TInt realSlabThreshold = SlabThreshold;
+#ifdef _DEBUG
+        realSlabThreshold -= RHeap::EDebugHdrSize;
+#endif
+        ret %= realSlabThreshold;
+        }
+    else if (TestHybridHeapFunc == ETstOnlyDl)
+        {
+        TUint8 x = (TUint8)aRandom;
+        if (x & 0x80)
+            {
+            ret = x & 0x7f;
+            }
+        else
+            {
+            ret = (x & 0x7f) << 7;
+            }
+        }
+    else if (TestHybridHeapFunc == ETstOnlyPaged)
+        {
+        ret = RandomPagedLength(aRandom);
+        }
+    else if (TestHybridHeapFunc == ETstHybrid)
+        {
+        TUint8 x = (TUint8)aRandom;
+        if (x & 0x80)
+            {
+            ret = x & 0x7f;
+            }
+        else
+            {
+            if (x & 0x10)
+                {
+                ret = (x & 0x7f) << 7;
+                }
+            else
+                {
+                ret = RandomPagedLength(aRandom);
+                }
+            }
+        }
+    else
+        {
+        test(0);
+        }
+
+    return (TInt)ret;
+    }
+
+TInt HeapStress(TAny* aPtr)
+    {
+    STestStress& stress = *(STestStress*)aPtr;
+    RTestHeap* heap = (RTestHeap*)&User::Allocator();
+    TUint8** cell;
+    TInt* len;
+
+    if (stress.iThreadIndex >= MAX_THREAD_COUNT)
+        {
+        test(0);
+        }
+    cell = &HeapStressCell[stress.iThreadIndex][0];
+    len = &HeapStressLen[stress.iThreadIndex][0];
+
+    Mem::FillZ(cell, sizeof(*cell)*CurrMaxCellCount);
+    Mem::FillZ(len, sizeof(*len)*CurrMaxCellCount);
+
+    RThread::Rendezvous(KErrNone);
+    while (!stress.iStop)
+        {
+        // allocate all cells
+        TInt i;
+        for (i=0; i<CurrMaxCellCount; ++i)
+            {
+            if (!cell[i])
+                {
+                ++stress.iAllocs;
+                cell[i] = (TUint8*)heap->TestAlloc(RandomLength(stress.Random()));
+                if (cell[i])
+                    len[i] = heap->AllocLen(cell[i]);
+                else
+                    ++stress.iFailedAllocs;
+                }
+            }
+
+        // free some cells
+        TInt n = (CurrMaxCellCount/4) + (stress.Random() & (CurrMaxCellCount/2-1));
+        while (--n)
+            {
+            i = stress.Random() & (CurrMaxCellCount-1);
+            if (cell[i])
+                {
+                test(heap->AllocLen(cell[i]) == len[i]);
+                heap->TestFree(cell[i]);
+                cell[i] = NULL;
+                len[i] = 0;
+                ++stress.iFrees;
+                }
+            }
+
+        // realloc some cells
+        n = (CurrMaxCellCount/4) + (stress.Random() & (CurrMaxCellCount/2-1));
+        while (--n)
+            {
+            TUint32 rn = stress.Random();
+            i = (rn >> 8) & (CurrMaxCellCount-1);
+            TInt new_len = RandomLength(rn);
+            if (cell[i])
+                {
+                test(heap->AllocLen(cell[i]) == len[i]);
+                ++stress.iReAllocs;
+                TUint8* p = (TUint8*)heap->TestReAlloc(cell[i], new_len, rn >> 16);
+                if (p)
+                    {
+                    cell[i] = p;
+                    len[i] = heap->AllocLen(p);
+                    }
+                else
+                    {
+                    ++stress.iFailedReAllocs;
+                    }
+                }
+            }
+                
+        // check the heap
+        heap->Check();
+        ++stress.iChecks;
+        }
+    
+    return 0;
+    }
+
+void PrintSummary(STestStress& aStress)
+    {
+    test.Printf(_L("Total Allocs    : %11d\n"), aStress.iAllocs);
+    test.Printf(_L("Failed Allocs   : %11d\n"), aStress.iFailedAllocs);
+    test.Printf(_L("Total Frees     : %11d\n"), aStress.iFrees);
+    test.Printf(_L("Total ReAllocs  : %11d\n"), aStress.iReAllocs);
+    test.Printf(_L("Failed ReAllocs : %11d\n"), aStress.iFailedReAllocs);
+    test.Printf(_L("Heap checks     : %11d\n"), aStress.iChecks);
+    }
+    
+void CreateStressThread(STestStress& aStress)
+    {
+    RThread& thread = aStress.iThread;
+    TInt err = thread.Create(KNullDesC(), &HeapStress, 0x2000, aStress.iAllocator, &aStress);
+    test(err==KErrNone);
+    thread.SetPriority(EPriorityLess);
+    TRequestStatus status;
+    thread.Rendezvous(status);
+    test(status == KRequestPending);
+    thread.Resume();
+    User::WaitForRequest(status);
+    test(status == KErrNone);
+    test(thread.ExitType() == EExitPending);
+    thread.SetPriority(EPriorityMuchLess);
+    }
+
+void StopStressThread(STestStress& aStress)
+    {
+    RThread& thread = aStress.iThread;
+    TRequestStatus status;
+    thread.Logon(status);
+    aStress.iStop = ETrue;
+    User::WaitForRequest(status);
+    const TDesC& exitCat = thread.ExitCategory();
+    TInt exitReason = thread.ExitReason();
+    TInt exitType = thread.ExitType();
+    test.Printf(_L("Exit type %d,%d,%S\n"), exitType, exitReason, &exitCat);
+    test(exitType == EExitKill);
+    test(exitReason == KErrNone);
+    test(status == KErrNone);
+    PrintSummary(aStress);
+    }
+
+void WaitForKey(STestStress* aStress1, STestStress* aStress2)
+{
+    TRequestStatus keyStatus;
+    CConsoleBase* console = test.Console();
+    console->Read(keyStatus);
+    
+    for (;;)
+        {
+        User::WaitForRequest(keyStatus);
+        if (keyStatus != KRequestPending)
+            {
+            test(keyStatus == KErrNone);
+            if (console->KeyCode() == EKeyEscape)
+                {
+                test.Printf(_L("Forever test aborted by user\n"));
+                break;
+                }
+            else if (console->KeyCode() == EKeySpace)
+                {
+                if (aStress1 != NULL)
+                    {
+                    PrintSummary(*aStress1);
+                    }
+                if (aStress2 != NULL)
+                    {
+                    PrintSummary(*aStress2);
+                    }
+                }
+            }
+        console->Read(keyStatus);
+        }
+}
+
+TBool WaitForTimeoutOrKey(STestStress* aStress1, STestStress* aStress2)
+{
+    TBool abortedByUser = EFalse;
+    RTimer timer;
+    TRequestStatus timerStatus;
+    TInt err = timer.CreateLocal();
+    test(err == KErrNone);
+    timer.After(timerStatus, TestTimeAsSeconds*1000000);
+    
+    TRequestStatus keyStatus;
+    CConsoleBase* console = test.Console();
+    console->Read(keyStatus);
+    
+    for (;;)
+        {
+        User::WaitForRequest(keyStatus, timerStatus);
+        if (keyStatus != KRequestPending)
+            {
+            test(keyStatus == KErrNone);
+            if (console->KeyCode() == EKeyEscape)
+                {
+                abortedByUser = ETrue;
+                timer.Cancel();
+                test.Printf(_L("Forever test aborted by user\n"));
+                break;
+                }
+            else if (console->KeyCode() == EKeySpace)
+                {
+                if (aStress1 != NULL)
+                    {
+                    PrintSummary(*aStress1);
+                    }
+                if (aStress2 != NULL)
+                    {
+                    PrintSummary(*aStress2);
+                    }
+                }
+            console->Read(keyStatus);
+            }
+        if (timerStatus != KRequestPending)
+            {
+            if (timerStatus != KErrNone)
+                {
+                test(0);
+                }
+            console->ReadCancel();
+            break;
+            }
+        }
+    timer.Close();
+    return abortedByUser;
+}
+    
+TBool DoStressTest1(RAllocator* aAllocator)
+    {
+    TBool abortedByUser = EFalse;
+    
+    RTestHeap* heap = (RTestHeap*)aAllocator;
+    //test.Printf(_L("Test Stress 1: max=0x%x\n"),  heap->MaxLength());
+    
+    STestStress stress;
+    Mem::FillZ(&stress, sizeof(STestStress));
+    stress.iAllocator = aAllocator;
+    stress.iThreadIndex = 0;
+    if (TestType == ETestForeverAll)
+        {
+        stress.iSeed = FirstSeed(stress.iThreadIndex);
+        }
+    else
+        {
+        stress.iSeed = 0xb504f334;;
+        }
+    
+    CreateStressThread(stress);
+    
+    if (TestType == ETestE32Test)
+        {
+        User::After(TestTimeAsSeconds*1000000);
+        }
+    else if (TestType == ETestForeverAll)
+        {
+        abortedByUser = WaitForTimeoutOrKey(&stress, NULL);
+        }
+    else if (TestType == ETestForeverOne)
+        {
+        WaitForKey(&stress, NULL);
+        abortedByUser = ETrue;
+        }
+    else
+        {
+        test(0);
+        }
+    
+    StopStressThread(stress);
+    CLOSE_AND_WAIT(stress.iThread);
+    heap->FullCheck();
+    return abortedByUser;
+    }
+
+TBool DoStressTest2(RAllocator* aAllocator)
+    {
+    TBool abortedByUser = EFalse;
+    
+    RTestHeap* heap = (RTestHeap*)aAllocator;
+    //test.Printf(_L("Test Stress 2: max=0x%x\n"),  heap->MaxLength());    
+    
+    STestStress stress1;
+    Mem::FillZ(&stress1, sizeof(STestStress));
+    stress1.iAllocator = aAllocator;
+    stress1.iThreadIndex = 0;
+    
+    STestStress stress2;
+    Mem::FillZ(&stress2, sizeof(STestStress));
+    stress2.iAllocator = aAllocator;
+    stress2.iThreadIndex = 1;
+    
+    if (TestType == ETestForeverAll)
+        {
+        stress1.iSeed = FirstSeed(stress1.iThreadIndex);
+        stress2.iSeed = FirstSeed(stress2.iThreadIndex);
+        }
+    else
+        {
+        stress1.iSeed = 0xb504f334;
+        stress2.iSeed = 0xddb3d743;
+        }
+    CreateStressThread(stress1);
+    CreateStressThread(stress2);
+
+    if (TestType == ETestE32Test)
+        {
+        User::After(2*TestTimeAsSeconds*1000000);
+        }
+    else if (TestType == ETestForeverAll)
+        {
+        abortedByUser = WaitForTimeoutOrKey(&stress1, &stress2);
+        }
+    else if (TestType == ETestForeverOne)
+        {
+        WaitForKey(&stress1, &stress2);
+        abortedByUser = ETrue;
+        }
+    else
+        {
+        test(0);
+        }
+    
+    StopStressThread(stress1);
+    StopStressThread(stress2);
+    CLOSE_AND_WAIT(stress1.iThread);
+    CLOSE_AND_WAIT(stress2.iThread);
+    heap->FullCheck();
+    return abortedByUser;
+    }
+
+TBool StressTests(void)
+    {
+    TBool abortedByUser = EFalse;
+    RHeap* heap = 0;
+    
+    for (;;)
+        {
+        if (TestType == ETestE32Test ||
+            TestType == ETestForeverAll)
+            {
+            heap = CreateTestHeap(4);
+            test(heap != NULL);
+            test.Next(_L("one thread, align 4"));
+            abortedByUser = DoStressTest1(heap);
+            if (abortedByUser)
+                {
+                break;
+                }
+            heap->Close();
+            
+            heap = CreateTestHeap(4);
+            test.Next(_L("two threads, align 4"));
+            abortedByUser = DoStressTest2(heap);
+            if (abortedByUser)
+                {
+                break;
+                }
+            heap->Close();
+                
+            heap = CreateTestHeap(8);
+            test(heap != NULL);
+            test.Next(_L("one thread, align 8"));
+            abortedByUser = DoStressTest1(heap);
+            if (abortedByUser)
+                {
+                break;
+                }
+            heap->Close();
+
+            heap = CreateTestHeap(8);
+            test.Next(_L("two threads, align 8"));
+            abortedByUser = DoStressTest2(heap);
+            }
+        else if (TestType == ETestForeverOne)
+            {
+            heap = CreateTestHeap(4);
+            test(heap != NULL);
+            if (TestForeverMultiThreadTest)
+                {
+                test.Next(_L("two threads, align 4"));
+                abortedByUser = DoStressTest2(heap);
+                }
+            else
+                {
+                test.Next(_L("one thread, align 4"));
+                abortedByUser = DoStressTest1(heap);
+                }
+            }
+        else
+            {
+            test(0);
+            }
+        break;
+        }
+    heap->Close();
+    
+    return abortedByUser;
+    }           
+
+        
+void ForeverOneTest(void)
+    {
+    //--------- config parameters - begin
+    TestForeverMultiThreadTest = ETrue; // EFalse
+    TestHybridHeapFunc = ETstOnlySlab; // ETstOnlySlab // ETstOnlyDl // ETstOnlyPaged // ETstHybrid
+    //--------- config parameters - end
+
+    if (TestHybridHeapFunc == ETstOnlySlab && !DlOnly)
+        {
+        // slab tests
+#ifdef __WINS__
+        test.Next(_L("slab test 48M"));
+        CurrMaxCellCount = 0x100000; //0x10000; 0x100000
+        HeapMaxLength = 0x3000000; // 48M
+#else
+        test.Next(_L("slab test 3M"));
+        CurrMaxCellCount = 0x10000; //0x10000; 0x100000
+        HeapMaxLength = 0x300000; // 3M
+#endif          
+        StressTests();
+        }
+    else if (TestHybridHeapFunc == ETstOnlyDl)
+        {
+        // DL tests
+        test.Next(_L("DL test 32M"));
+        CurrMaxCellCount = 0x1000; //0x10000;
+        HeapMaxLength = 0x2000000; // 32M
+        StressTests();
+        }
+    else if (TestHybridHeapFunc == ETstOnlyPaged && !DlOnly)
+        {
+        // paged tests
+        test.Next(_L("paged test 64M"));
+        CurrMaxCellCount = 0x100; //0x10000;
+        HeapMaxLength = 0x4000000; // 64M
+        StressTests();
+        }
+    else if (TestHybridHeapFunc == ETstHybrid && !DlOnly)
+        {
+        // hybrid tests
+        test.Next(_L("hybrid test 64M"));
+        CurrMaxCellCount = 0x1000; //0x10000;
+        HeapMaxLength = 0x4000000; // 64M
+        StressTests();
+        }
+    else
+        {
+        test(0);
+        }
+    }
+    
+void ForeverAllTests(void)
+    {
+    //--------- config parameters - begin
+    TInt basicTimeAsSeconds = 30; //10;
+    //--------- config parameters - end
+
+    for (;;)
+        {
+        if (!DlOnly)
+            {
+            // slab tests
+            TestHybridHeapFunc = ETstOnlySlab;
+            TestTimeAsSeconds = basicTimeAsSeconds * 3;
+#ifdef __WINS__
+            test.Next(_L("slab test 48M"));
+            CurrMaxCellCount = 0x100000; //0x10000; 0x100000
+            HeapMaxLength = 0x3000000; // 48M
+#else
+            test.Next(_L("slab test 3M"));
+            CurrMaxCellCount = 0x10000; //0x10000; 0x100000
+            HeapMaxLength = 0x300000; // 3M
+#endif          
+            if (StressTests())
+                {
+                break;
+                }
+            }
+        
+        // DL tests
+        TestHybridHeapFunc = ETstOnlyDl;
+        TestTimeAsSeconds = basicTimeAsSeconds;
+        
+        test.Next(_L("DL test 32M"));
+        CurrMaxCellCount = 0x1000; //0x10000;
+        HeapMaxLength = 0x2000000; // 32M
+        if (StressTests())
+            {
+            break;
+            }
+        
+        test.Next(_L("DL test 16M"));
+        CurrMaxCellCount = 0x1000; //0x10000;
+        HeapMaxLength = 0x1000000; // 16M
+        if (StressTests())
+            {
+            break;
+            }
+        
+        if (!DlOnly)
+            {
+            // paged tests
+            TestHybridHeapFunc = ETstOnlyPaged;
+            TestTimeAsSeconds = basicTimeAsSeconds;
+            
+            test.Next(_L("paged test 64M"));
+            CurrMaxCellCount = 0x100; //0x10000;
+            HeapMaxLength = 0x4000000; // 64M
+            if (StressTests())
+                {
+                break;
+                }
+            }
+        
+        if (!DlOnly)
+            {
+            // hybrid tests
+            TestHybridHeapFunc = ETstHybrid;
+            TestTimeAsSeconds = basicTimeAsSeconds * 2;
+            
+            test.Next(_L("hybrid test 64M"));
+            CurrMaxCellCount = 0x1000; //0x10000;
+            HeapMaxLength = 0x4000000; // 64M
+            if (StressTests())
+                {
+                break;
+                }
+            }
+        }
+    }
+    
+void TestUsedInE32Tests(void)
+    {
+    //--------- config parameters - begin
+    TInt basicTimeAsSeconds = 10;
+    //--------- config parameters - end
+
+    if (!DlOnly)
+        {
+        // slab tests
+        TestHybridHeapFunc = ETstOnlySlab;
+        TestTimeAsSeconds = basicTimeAsSeconds * 3;
+#ifdef __WINS__
+        test.Next(_L("slab test 48M"));
+        CurrMaxCellCount = 0x100000; //0x10000; 0x100000
+        HeapMaxLength = 0x3000000; // 48M
+#else
+        test.Next(_L("slab test 3M"));
+        CurrMaxCellCount = 0x10000; //0x10000; 0x100000
+        HeapMaxLength = 0x300000; // 3M
+#endif          
+        StressTests();
+        }
+    
+    // DL tests
+    TestHybridHeapFunc = ETstOnlyDl;
+    TestTimeAsSeconds = basicTimeAsSeconds;
+    
+    test.Next(_L("DL test 32M"));
+    CurrMaxCellCount = 0x1000; //0x10000;
+    HeapMaxLength = 0x2000000; // 32M
+    StressTests();
+    
+    test.Next(_L("DL test 16M"));
+    CurrMaxCellCount = 0x1000; //0x10000;
+    HeapMaxLength = 0x1000000; // 16M
+    StressTests();
+    
+    if (!DlOnly)
+        {
+        // paged tests
+        TestHybridHeapFunc = ETstOnlyPaged;
+        TestTimeAsSeconds = basicTimeAsSeconds;
+        
+        test.Next(_L("paged test 64M"));
+        CurrMaxCellCount = 0x100; //0x10000;
+        HeapMaxLength = 0x4000000; // 64M
+        StressTests();
+        }
+
+    if (!DlOnly)
+        {
+        // hybrid tests
+        TestHybridHeapFunc = ETstHybrid;
+        TestTimeAsSeconds = basicTimeAsSeconds * 2;
+        
+        test.Next(_L("hybrid test 64M"));
+        CurrMaxCellCount = 0x1000; //0x10000;
+        HeapMaxLength = 0x4000000; // 64M
+        StressTests();
+        }
+    }
+    
+TInt E32Main()
+    {
+    test.Title();
+    __KHEAP_MARK;
+    test.Start(_L("Testing heaps"));
+
+    TInt err = UserHal::TickPeriod(TickPeriod);
+    test(err == KErrNone);
+
+    DlOnly = IsDlOnly();
+    
+    TestType = ETestE32Test; //ETestE32Test // ETestForeverOne // ETestForeverAll
+    // see other config parameters: TestUsedInE32Tests()/ForeverOneTest()/ForeverAllTests()
+   
+    if (TestType == ETestE32Test)
+        {
+        TestUsedInE32Tests();
+        }
+    else if (TestType == ETestForeverOne)
+        {
+        ForeverOneTest();
+        }
+    else if (TestType == ETestForeverAll)
+        {
+        ForeverAllTests();
+        }
+    else
+        {
+        test(0);
+        }
+    
+    test.End();
+    __KHEAP_MARKEND;
+    return 0;
+    }