1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/heap/t_heap2.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1455 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\heap\t_heap2.cpp
1.18 +// Overview:
1.19 +// Tests RHeap class, including a stress test and a "grow in place"
1.20 +// ReAlloc test.
1.21 +// API Information:
1.22 +// RHeap
1.23 +// Details:
1.24 +// - Test allocation on fixed length heaps in local, disconnected chunks for
1.25 +// different heap sizes and alignments. Assumes knowledge of heap
1.26 +// implementation.
1.27 +// - Test allocation, free, reallocation and compression on chunk heaps with
1.28 +// different maximum and minimum lengths and alignments. Assumes knowledge
1.29 +// of heap implementation.
1.30 +// - Stress test heap implementation with a single thread that allocates, frees
1.31 +// and reallocates cells, and checks the heap.
1.32 +// - Stress test heap implementation with two threads that run concurrently.
1.33 +// - Create a chunk heap, test growing in place by allocating a cell and
1.34 +// then reallocating additional space until failure, verify that the cell
1.35 +// did not move and the size was increased.
1.36 +// - The heap is checked to verify that no cells remain allocated after the
1.37 +// tests are complete.
1.38 +// Platforms/Drives/Compatibility:
1.39 +// All
1.40 +// Assumptions/Requirement/Pre-requisites:
1.41 +// Failures and causes:
1.42 +// Base Port information:
1.43 +//
1.44 +//
1.45 +
1.46 +#include <e32test.h>
1.47 +#include <e32hal.h>
1.48 +#include <e32def.h>
1.49 +#include <e32def_private.h>
1.50 +
1.51 +// Needed for KHeapShrinkHysRatio which is now ROM 'patchdata'
1.52 +#include "TestRHeapShrink.h"
1.53 +
1.54 +#define DECL_GET(T,x) inline T x() const {return i##x;}
1.55 +#define DECL_GET2(T,x,y) inline T y() const {return i##x;}
1.56 +
1.57 +
1.58 +#ifdef __EABI__
1.59 + IMPORT_D extern const TInt KHeapMinCellSize;
1.60 +#else
1.61 + const TInt KHeapMinCellSize = 0;
1.62 +#endif
1.63 +
1.64 +RTest test(_L("T_HEAP2"));
1.65 +
1.66 +#define TEST_ALIGN(p,a) test((TLinAddr(p)&((a)-1))==0)
1.67 +
1.68 +struct STestCell
1.69 + {
1.70 + enum {EMagic = 0xb8aa3b29};
1.71 +
1.72 + TUint32 iLength;
1.73 + TUint32 iData[1];
1.74 +
1.75 + void Set(TInt aLength);
1.76 + void Verify(TInt aLength);
1.77 + void Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength);
1.78 + };
1.79 +
1.80 +void STestCell::Set(TInt aLength)
1.81 + {
1.82 + TInt i;
1.83 + TUint32 x = (TUint32)this ^ (TUint32)aLength ^ (TUint32)EMagic;
1.84 + aLength -= RHeap::EAllocCellSize;
1.85 + if (aLength==0)
1.86 + return;
1.87 + iLength = x;
1.88 + aLength /= sizeof(TUint32);
1.89 + for (i=0; i<aLength-1; ++i)
1.90 + {
1.91 + x *= 69069;
1.92 + x += 41;
1.93 + iData[i] = x;
1.94 + }
1.95 + }
1.96 +
1.97 +void STestCell::Verify(TInt aLength)
1.98 + {
1.99 + Verify(this, aLength, aLength);
1.100 + }
1.101 +
1.102 +void STestCell::Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength)
1.103 + {
1.104 + TInt i;
1.105 + TUint32 x = (TUint32)aInitPtr ^ (TUint32)aInitLength ^ (TUint32)EMagic;
1.106 + aLength -= RHeap::EAllocCellSize;
1.107 + if (aLength==0)
1.108 + return;
1.109 + test(iLength == x);
1.110 + aLength /= sizeof(TUint32);
1.111 + for (i=0; i<aLength-1; ++i)
1.112 + {
1.113 + x *= 69069;
1.114 + x += 41;
1.115 + test(iData[i] == x);
1.116 + }
1.117 + }
1.118 +
1.119 +class RTestHeap : public RHeap
1.120 + {
1.121 +public:
1.122 + DECL_GET(TInt,AccessCount)
1.123 + DECL_GET(TInt,HandleCount)
1.124 + DECL_GET(TInt*,Handles)
1.125 + DECL_GET(TUint32,Flags)
1.126 + DECL_GET(TInt,CellCount)
1.127 + DECL_GET(TInt,TotalAllocSize)
1.128 + DECL_GET(TInt,MinLength)
1.129 + DECL_GET(TInt,Offset)
1.130 + DECL_GET(TInt,GrowBy)
1.131 + DECL_GET(TInt,ChunkHandle)
1.132 + DECL_GET2(const RFastLock&,Lock,LockRef)
1.133 + DECL_GET(TUint8*,Top)
1.134 + DECL_GET(TInt,Align)
1.135 + DECL_GET(TInt,MinCell)
1.136 + DECL_GET(TInt,PageSize)
1.137 + DECL_GET2(const SCell&,Free,FreeRef)
1.138 +public:
1.139 + TInt CheckAllocatedCell(const TAny* aCell) const;
1.140 + void FullCheckAllocatedCell(const TAny* aCell) const;
1.141 + TAny* TestAlloc(TInt aSize);
1.142 + void TestFree(TAny* aPtr);
1.143 + TAny* TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0);
1.144 + void FullCheck();
1.145 + static void WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen);
1.146 + TInt FreeCellLen(const TAny* aPtr) const;
1.147 + static RTestHeap* FixedHeap(TInt aMaxLength, TInt aAlign=0, TBool aSingleThread=ETrue);
1.148 + void TakeChunkOwnership(RChunk aChunk);
1.149 + TInt LastFreeCellLen(void) const;
1.150 + TInt CalcComp(TInt aCompSize);
1.151 + void ForceCompress(TInt aFreed);
1.152 + };
1.153 +
1.154 +TInt RTestHeap::CheckAllocatedCell(const TAny* aCell) const
1.155 + {
1.156 + SCell* pC = GetAddress(aCell);
1.157 + TInt len = pC->len;
1.158 + TUint8* pEnd = (TUint8*)pC + len;
1.159 + TEST_ALIGN(aCell, iAlign);
1.160 + TEST_ALIGN(len, iAlign);
1.161 + test(len >= iMinCell);
1.162 + test((TUint8*)pC>=iBase && pEnd<=iTop);
1.163 + return len;
1.164 + }
1.165 +
1.166 +void RTestHeap::FullCheckAllocatedCell(const TAny* aCell) const
1.167 + {
1.168 + ((STestCell*)aCell)->Verify(CheckAllocatedCell(aCell));
1.169 + }
1.170 +
1.171 +TAny* RTestHeap::TestAlloc(TInt aSize)
1.172 + {
1.173 + TAny* p = Alloc(aSize);
1.174 + if (p)
1.175 + {
1.176 + TInt len = CheckAllocatedCell(p);
1.177 + test((len-RHeap::EAllocCellSize)>=aSize);
1.178 + ((STestCell*)p)->Set(len);
1.179 + }
1.180 + return p;
1.181 + }
1.182 +
1.183 +void RTestHeap::TestFree(TAny* aPtr)
1.184 + {
1.185 + if (aPtr)
1.186 + FullCheckAllocatedCell(aPtr);
1.187 + Free(aPtr);
1.188 + }
1.189 +
1.190 +TAny* RTestHeap::TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
1.191 + {
1.192 + TInt old_len = aPtr ? CheckAllocatedCell(aPtr) : 0;
1.193 + if (aPtr)
1.194 + ((STestCell*)aPtr)->Verify(old_len);
1.195 + TAny* p = ReAlloc(aPtr, aSize, aMode);
1.196 + if (!p)
1.197 + {
1.198 + ((STestCell*)aPtr)->Verify(old_len);
1.199 + return p;
1.200 + }
1.201 + TInt new_len = CheckAllocatedCell(p);
1.202 + test((new_len-RHeap::EAllocCellSize)>=aSize);
1.203 + if (p == aPtr)
1.204 + {
1.205 + ((STestCell*)p)->Verify(p, old_len, Min(old_len, new_len));
1.206 + if (new_len != old_len)
1.207 + ((STestCell*)p)->Set(new_len);
1.208 + return p;
1.209 + }
1.210 + test(!(aMode & ENeverMove));
1.211 + test((new_len > old_len) || (aMode & EAllowMoveOnShrink));
1.212 + if (old_len)
1.213 + ((STestCell*)p)->Verify(aPtr, old_len, Min(old_len, new_len));
1.214 + if (new_len != old_len)
1.215 + ((STestCell*)p)->Set(new_len);
1.216 + return p;
1.217 + }
1.218 +
1.219 +struct SHeapCellInfo
1.220 + {
1.221 + RTestHeap* iHeap;
1.222 + TInt iTotalAlloc;
1.223 + TInt iTotalAllocSize;
1.224 + TInt iTotalFree;
1.225 + TUint8* iNextCell;
1.226 + };
1.227 +
1.228 +void RTestHeap::WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen)
1.229 + {
1.230 + (void)aCell;
1.231 + ::SHeapCellInfo& info = *(::SHeapCellInfo*)aPtr;
1.232 + switch(aType)
1.233 + {
1.234 + case EGoodAllocatedCell:
1.235 + {
1.236 + test(aCell == info.iNextCell);
1.237 + TInt len = ((SCell*)aCell)->len;
1.238 + test(len == aLen);
1.239 + info.iNextCell += len;
1.240 + ++info.iTotalAlloc;
1.241 + info.iTotalAllocSize += (aLen-EAllocCellSize);
1.242 + STestCell* pT = (STestCell*)((TUint8*)aCell + EAllocCellSize);
1.243 + pT->Verify(len);
1.244 + break;
1.245 + }
1.246 + case EGoodFreeCell:
1.247 + {
1.248 + test(aCell == info.iNextCell);
1.249 + TInt len = ((SCell*)aCell)->len;
1.250 + test(len == aLen);
1.251 + info.iNextCell += len;
1.252 + ++info.iTotalFree;
1.253 + break;
1.254 + }
1.255 + default:
1.256 + test.Printf(_L("TYPE=%d ??\n"),aType);
1.257 + test(0);
1.258 + break;
1.259 + }
1.260 + }
1.261 +
1.262 +void RTestHeap::FullCheck()
1.263 + {
1.264 + ::SHeapCellInfo info;
1.265 + Mem::FillZ(&info, sizeof(info));
1.266 + info.iHeap = this;
1.267 + info.iNextCell = iBase;
1.268 + DebugFunction(EWalk, (TAny*)&WalkFullCheckCell, &info);
1.269 + test(info.iNextCell == iTop);
1.270 + test(info.iTotalAlloc == iCellCount);
1.271 + test(info.iTotalAllocSize == iTotalAllocSize);
1.272 + }
1.273 +
1.274 +TInt RTestHeap::FreeCellLen(const TAny* aPtr) const
1.275 + {
1.276 + SCell* p = iFree.next;
1.277 + SCell* q = (SCell*)((TUint8*)aPtr - EAllocCellSize);
1.278 + for (; p && p!=q; p = p->next) {}
1.279 + if (p == q)
1.280 + return p->len - EAllocCellSize;
1.281 + return -1;
1.282 + }
1.283 +
1.284 +TInt RTestHeap::LastFreeCellLen(void) const
1.285 + {
1.286 + SCell* p = iFree.next;
1.287 + if (p==NULL)
1.288 + return -1;
1.289 + for (; p->next; p=p->next){}
1.290 + return p->len;
1.291 + }
1.292 +
1.293 +
1.294 +/** Checks whether a call to Compress() will actually perform a reduction
1.295 + of the heap.
1.296 + Relies on the free last cell on the heap being cell that has just been freed
1.297 + plus any extra.
1.298 + Intended for use by t_heap2.cpp - DoTest4().
1.299 + @param aFreedSize The size in bytes of the cell that was freed
1.300 +*/
1.301 +TInt RTestHeap::CalcComp(TInt aFreedSize)
1.302 + {
1.303 + TInt largestCell=0;
1.304 + largestCell = LastFreeCellLen();
1.305 + // if the largest cell is too small or it would have been compressed by the
1.306 + // free operation then return 0.
1.307 + if (largestCell < iPageSize || aFreedSize >= KHeapShrinkHysRatio*(iGrowBy>>8))
1.308 + {
1.309 + return 0;
1.310 + }
1.311 + else
1.312 + {
1.313 + return _ALIGN_DOWN(aFreedSize,iPageSize);
1.314 + }
1.315 + }
1.316 +
1.317 +/** compress the heap if the KHeapShrinkRatio is too large for what we are
1.318 + expecting in DoTest4().
1.319 +*/
1.320 +void RTestHeap::ForceCompress(TInt aFreed)
1.321 + {
1.322 + if (aFreed < KHeapShrinkHysRatio*(iGrowBy>>8))
1.323 + {
1.324 + Compress();
1.325 + }
1.326 + }
1.327 +RTestHeap* RTestHeap::FixedHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
1.328 + {
1.329 + RChunk c;
1.330 + TInt bottom = 0x40000;
1.331 + TInt top = bottom + aMaxLength;
1.332 + TInt r = c.CreateDisconnectedLocal(bottom, top, top + bottom, EOwnerThread);
1.333 + if (r!=KErrNone)
1.334 + return NULL;
1.335 + TUint8* base = c.Base() + bottom;
1.336 + RTestHeap* h = (RTestHeap*)UserHeap::FixedHeap(base, aMaxLength, aAlign, aSingleThread);
1.337 + if (!aAlign)
1.338 + aAlign = RHeap::ECellAlignment;
1.339 + test((TUint8*)h == base);
1.340 + test(h->AccessCount() == 1);
1.341 + test(h->HandleCount() == (aSingleThread ? 0 : 1));
1.342 + test(h->Handles() == (aSingleThread ? NULL : (TInt*)&h->LockRef()));
1.343 + test(h->Flags() == TUint32(RAllocator::EFixedSize | (aSingleThread ? RAllocator::ESingleThreaded : 0)));
1.344 + test(h->CellCount() == 0);
1.345 + test(h->TotalAllocSize() == 0);
1.346 + test(h->MaxLength() == aMaxLength);
1.347 + test(h->MinLength() == h->Top() - (TUint8*)h);
1.348 + test(h->Offset() == 0);
1.349 + test(h->GrowBy() == 0);
1.350 + test(h->ChunkHandle() == 0);
1.351 + test(h->Align() == aAlign);
1.352 + TInt min_cell = _ALIGN_UP((KHeapMinCellSize + Max((TInt)RHeap::EAllocCellSize, (TInt)RHeap::EFreeCellSize)), aAlign);
1.353 + TInt hdr_len = _ALIGN_UP(sizeof(RHeap) + RHeap::EAllocCellSize, aAlign) - RHeap::EAllocCellSize;
1.354 + TInt user_len = _ALIGN_DOWN(aMaxLength - hdr_len, aAlign);
1.355 + test(h->Base() == base + hdr_len);
1.356 + test(h->MinCell() == min_cell);
1.357 + test(h->Top() - h->Base() == user_len);
1.358 + test(h->FreeRef().next == (RHeap::SCell*)h->Base());
1.359 + h->TakeChunkOwnership(c);
1.360 + return h;
1.361 + }
1.362 +
1.363 +void RTestHeap::TakeChunkOwnership(RChunk aChunk)
1.364 + {
1.365 + iChunkHandle = aChunk.Handle();
1.366 + ++iHandleCount;
1.367 + iHandles = &iChunkHandle;
1.368 + }
1.369 +
1.370 +
1.371 +#define ACCESS_COUNT(h) (((RTestHeap*)h)->AccessCount())
1.372 +#define HANDLE_COUNT(h) (((RTestHeap*)h)->HandleCount())
1.373 +#define HANDLES(h) (((RTestHeap*)h)->Handles())
1.374 +#define FLAGS(h) (((RTestHeap*)h)->Flags())
1.375 +#define CELL_COUNT(h) (((RTestHeap*)h)->CellCount())
1.376 +#define TOTAL_ALLOC_SIZE(h) (((RTestHeap*)h)->TotalAllocSize())
1.377 +#define MIN_LENGTH(h) (((RTestHeap*)h)->MinLength())
1.378 +#define OFFSET(h) (((RTestHeap*)h)->Offset())
1.379 +#define GROW_BY(h) (((RTestHeap*)h)->GrowBy())
1.380 +#define CHUNK_HANDLE(h) (((RTestHeap*)h)->ChunkHandle())
1.381 +#define LOCK_REF(h) (((RTestHeap*)h)->LockRef())
1.382 +#define TOP(h) (((RTestHeap*)h)->Top())
1.383 +#define ALIGN(h) (((RTestHeap*)h)->Align())
1.384 +#define MIN_CELL(h) (((RTestHeap*)h)->MinCell())
1.385 +#define PAGE_SIZE(h) (((RTestHeap*)h)->PageSize())
1.386 +#define FREE_REF(h) (((RTestHeap*)h)->FreeRef())
1.387 +
1.388 +void DoTest1(RHeap* aH)
1.389 + {
1.390 + RTestHeap* h = (RTestHeap*)aH;
1.391 + test.Printf(_L("Test Alloc: min=%x max=%x align=%d growby=%d\n"),
1.392 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.393 + TInt l;
1.394 + TAny* p = NULL;
1.395 + TUint8* next = h->Base();
1.396 + TUint8* top = h->Top();
1.397 + TUint8* limit = (TUint8*)h + h->MaxLength();
1.398 + TBool fixed = h->Flags() & RAllocator::EFixedSize;
1.399 + for (l=1; l<=1024; ++l)
1.400 + {
1.401 + TInt remain1 = top - next;
1.402 + TInt xl1 = _ALIGN_UP(Max((l+RHeap::EAllocCellSize), h->MinCell()), h->Align());
1.403 + p = h->TestAlloc(l);
1.404 + if ( (fixed && remain1 < xl1) || (next + xl1 > limit) )
1.405 + {
1.406 + test(p == NULL);
1.407 + test(top == h->Top());
1.408 + test.Printf(_L("Alloc failed at l=%d next=%08x\n"), l, next);
1.409 + break;
1.410 + }
1.411 + test(p == next + RHeap::EAllocCellSize);
1.412 + if (xl1 > remain1)
1.413 + {
1.414 + // no room for this cell
1.415 + TInt g = h->GrowBy();
1.416 + while (xl1 > remain1)
1.417 + {
1.418 + top += g;
1.419 + remain1 += g;
1.420 + }
1.421 + }
1.422 + test(top == h->Top());
1.423 + if (xl1 + h->MinCell() > remain1)
1.424 + {
1.425 + // this cell fits but remainder is too small or nonexistent
1.426 + xl1 = top - next;
1.427 + next = top;
1.428 + test(h->FreeRef().next == NULL);
1.429 + }
1.430 + else
1.431 + {
1.432 + // this cell fits and remainder can be reused
1.433 + next += xl1;
1.434 + }
1.435 + test(aH->AllocLen(p) == xl1 - RHeap::EAllocCellSize);
1.436 + }
1.437 + h->FullCheck();
1.438 + }
1.439 +
1.440 +void DoTest2(RHeap* aH)
1.441 + {
1.442 + RTestHeap* h = (RTestHeap*)aH;
1.443 + test.Printf(_L("Test Free: min=%x max=%x align=%d growby=%d\n"),
1.444 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.445 + TInt al;
1.446 + TInt min = h->MinCell();
1.447 + TBool pad = EFalse;
1.448 + for (al=1; al<256; (void)((pad=!pad)!=0 || (al+=al+1)) )
1.449 + {
1.450 + TAny* p[32];
1.451 + TInt last_len = 0;
1.452 + TAny* last = NULL;
1.453 + TInt i;
1.454 + test.Printf(_L("al=%d pad=%d\n"), al, pad);
1.455 + TUint8* top=0;
1.456 + TAny* spare=0;
1.457 + TBool heapReduced = EFalse;
1.458 + for (i=0; i<32; ++i)
1.459 + {
1.460 + // Check whether the cell created for the allocation of al would end up
1.461 + // including extra bytes from the last free cell that aren't enough
1.462 + // to create a new free cell.
1.463 + top = h->Top();
1.464 + TInt freeLen=h->LastFreeCellLen();
1.465 + TInt actualAllocBytes = Max(_ALIGN_UP(al + RHeap::EAllocCellSize, h->Align()), min);
1.466 + TInt remainingBytes = freeLen - actualAllocBytes;
1.467 + if (remainingBytes < min)
1.468 + {
1.469 + // Force the heap to grow so that once this allocation is freed
1.470 + // the free cell left will be large enough to include the al allocation
1.471 + // and to create a new free cell if necessary.
1.472 + actualAllocBytes = _ALIGN_UP(actualAllocBytes + min, h->Align());
1.473 + TAny* q = h->TestAlloc(actualAllocBytes);
1.474 + // Check heap has grown
1.475 + test(top < h->Top());
1.476 + top = h->Top();
1.477 + test(q!=NULL);
1.478 + // Have grown the heap so allocate a cell as a place holder to stop
1.479 + // the heap being shrunk and the actual cell we want to allocate from being the
1.480 + // wrong size
1.481 + spare=h->TestAlloc(8);
1.482 + h->TestFree(q);
1.483 + // Ensure heap wasn't shrunk after free
1.484 + test(top == h->Top());
1.485 + }
1.486 + top = h->Top();
1.487 + // Allocate the new
1.488 + p[i] = h->TestAlloc(al);
1.489 + test(p[i]!=NULL);
1.490 + if (remainingBytes < min)
1.491 + {// now safe to free any padding as p[i] now allocated and its size can't change
1.492 + h->TestFree(spare);
1.493 + }
1.494 + TInt tmp1=h->AllocLen(p[i]);
1.495 + TInt tmp2=Max(_ALIGN_UP(al+RHeap::EAllocCellSize,h->Align()), min)-RHeap::EAllocCellSize;
1.496 + test(tmp1 == tmp2);
1.497 + }
1.498 + last = (TUint8*)p[31] + _ALIGN_UP(Max((al + RHeap::EAllocCellSize), min), h->Align());
1.499 + last_len = h->FreeCellLen(last);
1.500 + test(last_len > 0);
1.501 + if (pad)
1.502 + {
1.503 + test(h->TestAlloc(last_len) == last);
1.504 + test(h->FreeRef().next == NULL);
1.505 + }
1.506 + else
1.507 + last = NULL;
1.508 + top = h->Top();
1.509 + for (i=0,heapReduced=EFalse; i<32; ++i)
1.510 + {
1.511 + h->TestFree(p[i]);
1.512 + TInt fl = h->FreeCellLen(p[i]);
1.513 + TInt xfl = _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
1.514 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.515 + {
1.516 + top = h->Top();
1.517 + heapReduced = ETrue;
1.518 + }
1.519 +
1.520 + if (i < 31 || pad)
1.521 + test(fl == xfl);
1.522 + else
1.523 + {
1.524 + if (!heapReduced)
1.525 + test(fl == xfl + RHeap::EAllocCellSize + last_len);
1.526 + else
1.527 + {
1.528 + heapReduced = EFalse;
1.529 + }
1.530 + }
1.531 + test(h->TestAlloc(al)==p[i]);
1.532 + }
1.533 + for (i=0,heapReduced=EFalse; i<31; ++i)
1.534 + {
1.535 + TInt j = i+1;
1.536 + TUint8* q;
1.537 + // Free to adjacent cells and check that the free cell left is the combined
1.538 + // size of the 2 adjacent cells just freed
1.539 + h->TestFree(p[i]);
1.540 + h->TestFree(p[j]);
1.541 + TInt fl = h->FreeCellLen(p[i]);
1.542 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.543 + {
1.544 + top = h->Top();
1.545 + heapReduced = ETrue;
1.546 + }
1.547 + TInt xfl = 2 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
1.548 + if (j < 31 || pad)
1.549 + test(fl == xfl);
1.550 + else
1.551 + {
1.552 + if (!heapReduced)
1.553 + test(fl == xfl + RHeap::EAllocCellSize + last_len);
1.554 + else
1.555 + {
1.556 + heapReduced = EFalse;
1.557 + }
1.558 + }
1.559 + test(h->FreeCellLen(p[j]) < 0);
1.560 + test(h->TestAlloc(fl)==p[i]);
1.561 + test(h->Top() == top);
1.562 + h->TestFree(p[i]);
1.563 + test(h->FreeCellLen(p[i]) == fl);
1.564 + // test when you alloc a cell that is larger than cells just freed
1.565 + // that its position is not the same as the freed cells
1.566 + // will hold for all cells except top/last one
1.567 + if (j < 31 && !pad && fl < last_len)
1.568 + {
1.569 + q = (TUint8*)h->TestAlloc(fl+1);
1.570 + if (h->Top() > top)
1.571 + top = h->Top();
1.572 + test(h->Top() == top);
1.573 + test(q > p[i]);
1.574 + h->TestFree(q);
1.575 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.576 + {
1.577 + top = h->Top();
1.578 + heapReduced = ETrue;
1.579 + }
1.580 + }
1.581 + // check cell that is just smaller than space but not small enough
1.582 + // for a new free cell to be created, is the size of whole free cell
1.583 + test(h->TestAlloc(fl-min+1)==p[i]);
1.584 + test(h->Top() == top);
1.585 + test(h->AllocLen(p[i])==fl);
1.586 + h->TestFree(p[i]);
1.587 + // Check cell that is small enough for new free cell and alloc'd cell to be
1.588 + // created at p[i] cell is created at p[i]
1.589 + test(h->TestAlloc(fl-min)==p[i]);
1.590 + test(h->Top() == top);
1.591 + // check free cell is at expected position
1.592 + q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
1.593 + test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
1.594 + // alloc 0 length cell at q, will work as new cell of min length will be created
1.595 + test(h->TestAlloc(0) == q);
1.596 + test(h->Top() == top);
1.597 + h->TestFree(p[i]);
1.598 + test(h->FreeCellLen(p[i]) == fl - min);
1.599 + h->TestFree(q);
1.600 + // again check free cells are combined
1.601 + test(h->FreeCellLen(q) < 0);
1.602 + test(h->FreeCellLen(p[i]) == fl);
1.603 + // check reallocating the cells places them back to same positions
1.604 + test(h->TestAlloc(al)==p[i]);
1.605 + test(h->Top() == top);
1.606 + test(h->TestAlloc(al)==p[j]);
1.607 + test(h->Top() == top);
1.608 + if (pad)
1.609 + test(h->FreeRef().next == NULL);
1.610 + }
1.611 + for (i=0,heapReduced=EFalse; i<30; ++i)
1.612 + {
1.613 + TInt j = i+1;
1.614 + TInt k = i+2;
1.615 + TUint8* q;
1.616 + // Free 3 adjacent cells and check free cell created is combined size
1.617 + h->TestFree(p[i]);
1.618 + h->TestFree(p[k]);
1.619 + h->TestFree(p[j]);
1.620 + h->FullCheck();
1.621 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.622 + {
1.623 + top = h->Top();
1.624 + heapReduced = ETrue;
1.625 + }
1.626 + TInt fl = h->FreeCellLen(p[i]);
1.627 + TInt xfl = 3 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
1.628 + if (k < 31 || pad)
1.629 + test(fl == xfl);
1.630 + else
1.631 + {
1.632 + if (!heapReduced)
1.633 + test(fl == xfl + RHeap::EAllocCellSize + last_len);
1.634 + else
1.635 + {
1.636 + heapReduced = EFalse;
1.637 + }
1.638 + }
1.639 + test(h->FreeCellLen(p[j]) < 0);
1.640 + test(h->FreeCellLen(p[k]) < 0);
1.641 + //ensure created free cell is allocated to new cell of free cell size
1.642 + test(h->TestAlloc(fl)==p[i]);
1.643 + test(h->Top() == top);
1.644 + h->TestFree(p[i]);
1.645 + test(h->FreeCellLen(p[i]) == fl);
1.646 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.647 + top = h->Top();
1.648 + if (k < 31 && !pad && fl < last_len)
1.649 + {
1.650 + // Test new cell one larger than free cell size is allocated somewhere else
1.651 + q = (TUint8*)h->TestAlloc(fl+1);
1.652 + if (h->Top() > top)
1.653 + top = h->Top();
1.654 + test(h->Top() == top);
1.655 + test(q > p[i]);
1.656 + h->TestFree(q);
1.657 + if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
1.658 + {
1.659 + top = h->Top();
1.660 + heapReduced = ETrue;
1.661 + }
1.662 + }
1.663 + // check allocating cell just smaller than free cell size but
1.664 + // too large for neew free cell to be created, is size of whole free cell
1.665 + test(h->TestAlloc(fl-min+1)==p[i]);
1.666 + test(h->Top() == top);
1.667 + test(h->AllocLen(p[i])==fl);
1.668 + h->TestFree(p[i]);
1.669 + // ensure free cell is created this time as well as alloc'd cell
1.670 + test(h->TestAlloc(fl-min)==p[i]);
1.671 + test(h->Top() == top);
1.672 + q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
1.673 + test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
1.674 + test(h->TestAlloc(0) == q);
1.675 + test(h->Top() == top);
1.676 + h->TestFree(p[i]);
1.677 + test(h->FreeCellLen(p[i]) == fl - min);
1.678 + h->TestFree(q);
1.679 + test(h->FreeCellLen(q) < 0);
1.680 + test(h->FreeCellLen(p[i]) == fl);
1.681 + // realloc all cells and check heap not expanded
1.682 + test(h->TestAlloc(al)==p[i]);
1.683 + test(h->Top() == top);
1.684 + test(h->TestAlloc(al)==p[j]);
1.685 + test(h->Top() == top);
1.686 + test(h->TestAlloc(al)==p[k]);
1.687 + test(h->Top() == top);
1.688 + // If padding than no space should left on heap
1.689 + if (pad)
1.690 + test(h->FreeRef().next == NULL);
1.691 + }
1.692 + // when padding this will free padding from top of heap
1.693 + h->TestFree(last);
1.694 + }
1.695 + h->FullCheck();
1.696 + }
1.697 +
1.698 +void DoTest3(RHeap* aH)
1.699 + {
1.700 + RTestHeap* h = (RTestHeap*)aH;
1.701 + test.Printf(_L("Test ReAlloc: min=%x max=%x align=%d growby=%d\n"),
1.702 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.703 + // allocate continuous heap cell, then free them and reallocate again
1.704 + TInt al;
1.705 + for (al=1; al<256; al+=al+1)
1.706 + {
1.707 + TAny* p0 = h->TestAlloc(al);
1.708 + TInt al0 = h->AllocLen(p0);
1.709 + h->TestFree(p0);
1.710 + TAny* p1 = h->TestReAlloc(NULL, al, 0);
1.711 + TInt al1 = h->AllocLen(p1);
1.712 + test(p1 == p0);
1.713 + test(al1 == al0);
1.714 + h->TestFree(p1);
1.715 + TAny* p2 = h->TestAlloc(1);
1.716 + TAny* p3 = h->TestReAlloc(p2, al, 0);
1.717 + test(p3 == p0);
1.718 + TInt al3 = h->AllocLen(p3);
1.719 + test(al3 == al0);
1.720 + h->TestFree(p3);
1.721 + TAny* p4 = h->TestAlloc(1024);
1.722 + TAny* p5 = h->TestReAlloc(p4, al, 0);
1.723 + test(p5 == p0);
1.724 + TInt al5 = h->AllocLen(p5);
1.725 + test(al5 == al0);
1.726 + h->TestFree(p5);
1.727 + }
1.728 + TInt i;
1.729 + TInt j;
1.730 + for (j=0; j<30; j+=3)
1.731 + {
1.732 + TAny* p[30];
1.733 + TInt ala[30];
1.734 + TInt fla[30];
1.735 + h->Reset();
1.736 + for (i=0; i<30; ++i)
1.737 + {
1.738 + p[i] = h->TestAlloc(8*i*i);
1.739 + ala[i] = h->AllocLen(p[i]);
1.740 + fla[i] = 0;
1.741 + }
1.742 + for (i=1; i<30; i+=3)
1.743 + {
1.744 + h->TestFree(p[i]);
1.745 + fla[i] = h->FreeCellLen(p[i]);
1.746 + test(fla[i] == ala[i]);
1.747 + test(h->FreeCellLen(p[i-1]) < 0);
1.748 + test(h->FreeCellLen(p[i+1]) < 0);
1.749 + }
1.750 + h->FullCheck();
1.751 + TInt al1 = _ALIGN_UP(Max((RHeap::EAllocCellSize + 1), h->MinCell()), h->Align());
1.752 + // adjust al1 for some case when reallocated heap cell will not be shrinked because remainder will not big enough
1.753 + // to form a new free cell due to a big KHeapMinCellSize value
1.754 + TInt alaj = ala[j] + RHeap::EAllocCellSize;
1.755 + if (al1 < alaj && alaj - al1 < h->MinCell())
1.756 + al1 = alaj;
1.757 + TAny* p1 = h->TestReAlloc(p[j], 1, RHeap::ENeverMove);
1.758 + test(p1 == p[j]);
1.759 + test(h->AllocLen(p1) == al1 - RHeap::EAllocCellSize);
1.760 + TAny* p1b = (TUint8*)p1 + al1;
1.761 + test(h->FreeCellLen(p1b) == fla[j+1] + RHeap::EAllocCellSize + ala[j] - al1);
1.762 + TInt l2 = ala[j] + fla[j+1] + RHeap::EAllocCellSize; // max without moving
1.763 + TInt l3 = l2 - h->MinCell();
1.764 + TAny* p3 = h->TestReAlloc(p[j], l3, RHeap::ENeverMove);
1.765 + test(p3 == p[j]);
1.766 + TAny* p3b = (TUint8*)p3 + h->AllocLen(p3) + RHeap::EAllocCellSize;
1.767 + test(h->FreeCellLen(p3b) == h->MinCell() - RHeap::EAllocCellSize);
1.768 + TAny* p2 = h->TestReAlloc(p[j], l2, RHeap::ENeverMove);
1.769 + test(p2 == p[j]);
1.770 + test(h->AllocLen(p2) == l2);
1.771 + TAny* p4 = h->TestReAlloc(p[j], l2+1, RHeap::ENeverMove);
1.772 + test(p4 == NULL);
1.773 + test(h->AllocLen(p2) == l2);
1.774 + TAny* p5 = h->TestReAlloc(p[j], l2+1, 0);
1.775 + TInt k = 0;
1.776 + for (; k<30 && fla[k] <= l2; ++k) {}
1.777 + if (k < 30)
1.778 + test(p5 == p[k]);
1.779 + else
1.780 + test(p5 >= (TUint8*)p[29] + ala[29]);
1.781 + test(h->FreeCellLen(p2) == ala[j] + ala[j+1] + RHeap::EAllocCellSize);
1.782 + TInt ali = _ALIGN_UP(RHeap::EAllocCellSize,h->Align());
1.783 + TAny* p6b = (TUint8*)p[j+2] + ala[j+2] - ali + RHeap::EAllocCellSize;
1.784 + test(h->FreeCellLen(p6b) < 0);
1.785 + TAny* p6 = h->TestReAlloc(p[j+2], ala[j+2] - ali , 0);
1.786 + test(p6 == p[j+2]);
1.787 + if (h->AllocLen(p6) != ala[j+2]) // allocated heap cell size changed
1.788 + test(h->FreeCellLen(p6b) == h->MinCell() - RHeap::EAllocCellSize);
1.789 + TInt g = h->GrowBy();
1.790 + TAny* p7 = h->TestReAlloc(p5, 8*g, 0);
1.791 + test(p7 >= p5);
1.792 + TUint8* p8 = (TUint8*)p7 - RHeap::EAllocCellSize + al1;
1.793 + TUint8* p9 = (TUint8*)_ALIGN_UP(TLinAddr(p8), h->PageSize());
1.794 + if (p9-p8 < h->MinCell())
1.795 + p9 += h->PageSize();
1.796 + TAny* p7b = h->TestReAlloc(p7, 1, 0);
1.797 + test(p7b == p7);
1.798 + test(h->Top() + (RHeap::EAllocCellSize & (h->Align()-1)) == p9);
1.799 +
1.800 + h->FullCheck();
1.801 + }
1.802 + }
1.803 +
1.804 +// Test compression
1.805 +// {1 free cell, >1 free cell} x {reduce cell, eliminate cell, reduce cell but too small}
1.806 +//
1.807 +void DoTest4(RHeap* aH)
1.808 + {
1.809 + RTestHeap* h = (RTestHeap*)aH;
1.810 + test.Printf(_L("Test Compress: min=%x max=%x align=%d growby=%d\n"),
1.811 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.812 + TInt page_size;
1.813 + UserHal::PageSizeInBytes(page_size);
1.814 + test(page_size == h->PageSize());
1.815 + TInt g = h->GrowBy();
1.816 + TEST_ALIGN(g, page_size);
1.817 + test(g >= page_size);
1.818 + RChunk c;
1.819 + c.SetHandle(h->ChunkHandle());
1.820 + TInt align = h->Align();
1.821 + TInt minc = h->MinCell();
1.822 +
1.823 + TInt orig_size = c.Size();
1.824 + TUint8* orig_top = h->Top();
1.825 +
1.826 + // size in bytes that last free cell on the top of the heap must be
1.827 + // before the heap will be shrunk, size must include the no of bytes to
1.828 + // store the cell data/header i.e RHeap::EAllocCellSize
1.829 + TInt shrinkThres = KHeapShrinkHysRatio*(g>>8);
1.830 +
1.831 + TInt pass;
1.832 + for (pass=0; pass<2; ++pass)
1.833 + {
1.834 + TUint8* p0 = (TUint8*)h->TestAlloc(4);
1.835 + test(p0 == h->Base() + RHeap::EAllocCellSize);
1.836 + TInt l1 = h->Top() - (TUint8*)h->FreeRef().next;
1.837 + TEST_ALIGN(l1, align);
1.838 + l1 -= RHeap::EAllocCellSize;
1.839 + TUint8* p1;
1.840 + // Grow heap by 2*iGrowBy bytes
1.841 + p1 = (TUint8*)h->TestAlloc(l1 + 2*g);
1.842 + test(p1 == p0 + h->AllocLen(p0) + RHeap::EAllocCellSize);
1.843 + test(h->Top() - orig_top == 2*g);
1.844 + test(c.Size() - orig_size == 2*g);
1.845 + // May compress heap, may not
1.846 + h->TestFree(p1);
1.847 + h->ForceCompress(2*g);
1.848 + test(h->Top() == orig_top);
1.849 + test(c.Size() == orig_size);
1.850 + test((TUint8*)h->FreeRef().next == p1 - RHeap::EAllocCellSize);
1.851 + h->FullCheck();
1.852 + //if KHeapShrinkHysRatio is > 2.0 then heap compression will occur here
1.853 + test(h->Compress() == 0);
1.854 + test(h->TestAlloc(l1) == p1);
1.855 + test(h->FreeRef().next == NULL);
1.856 + if (pass)
1.857 + h->TestFree(p0); // leave another free cell on second pass
1.858 + TInt l2 = g - RHeap::EAllocCellSize;
1.859 + // Will grow heap by iGrowBy bytes
1.860 + TUint8* p2 = (TUint8*)h->TestAlloc(l2);
1.861 + test(p2 == orig_top + RHeap::EAllocCellSize);
1.862 + test(h->Top() - orig_top == g);
1.863 + test(c.Size() - orig_size == g);
1.864 + // may or may not compress heap
1.865 + h->TestFree(p2);
1.866 + if (l2+RHeap::EAllocCellSize >= shrinkThres)
1.867 + {
1.868 + // When KHeapShrinkRatio small enough heap will have been compressed
1.869 + test(h->Top() == orig_top);
1.870 + if (pass)
1.871 + {
1.872 + test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
1.873 + test((TUint8*)h->FreeRef().next->next == NULL);
1.874 + }
1.875 + else
1.876 + test((TUint8*)h->FreeRef().next == NULL);
1.877 + }
1.878 + else
1.879 + {
1.880 + test(h->Top() - orig_top == g);
1.881 + if (pass)
1.882 + {
1.883 + test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
1.884 + test((TUint8*)h->FreeRef().next->next == orig_top);
1.885 + }
1.886 + else
1.887 + test((TUint8*)h->FreeRef().next == orig_top);
1.888 + }
1.889 + // this compress will only do anything if the KHeapShrinkRatio is large
1.890 + // enough to introduce hysteresis otherwise the heap would have been compressed
1.891 + // by the free operation itself
1.892 + TInt tmp1,tmp2;
1.893 + tmp2=h->CalcComp(g);
1.894 + tmp1=h->Compress();
1.895 + test(tmp1 == tmp2);
1.896 + test(h->Top() == orig_top);
1.897 + test(c.Size() == orig_size);
1.898 + h->FullCheck();
1.899 + // shouldn't compress heap as already compressed
1.900 + test(h->Compress() == 0);
1.901 + //grow heap by iGrowBy bytes
1.902 + test(h->TestAlloc(l2) == p2);
1.903 + //grow heap by iGrowBy bytes
1.904 + TUint8* p3 = (TUint8*)h->TestAlloc(l2);
1.905 + test(p3 == p2 + g);
1.906 + test(h->Top() - orig_top == 2*g);
1.907 + test(c.Size() - orig_size == 2*g);
1.908 + // may or may not reduce heap
1.909 + h->TestFree(p2);
1.910 + // may or may not reduce heap
1.911 + h->TestFree(p3);
1.912 + h->ForceCompress(2*g);
1.913 + test(h->Top() == orig_top);
1.914 + test(c.Size() == orig_size);
1.915 + h->FullCheck();
1.916 + if (pass)
1.917 + {
1.918 + test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
1.919 + test((TUint8*)h->FreeRef().next->next == NULL);
1.920 + }
1.921 + else
1.922 + test((TUint8*)h->FreeRef().next == NULL);
1.923 + //grow heap by iGrowBy bytes
1.924 + test(h->TestAlloc(l2) == p2);
1.925 + //grow heap by iGrowBy*2 + page size bytes
1.926 + test(h->TestAlloc(l2 + g + page_size) == p3);
1.927 + test(h->Top() - orig_top == 4*g);
1.928 + test(c.Size() - orig_size == 4*g);
1.929 + // will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatioDflt
1.930 + test(h->TestReAlloc(p3, page_size - RHeap::EAllocCellSize, 0) == p3);
1.931 + h->ForceCompress(g+page_size);
1.932 + test(h->Top() - orig_top == g + page_size);
1.933 + test(c.Size() - orig_size == g + page_size);
1.934 + h->FullCheck();
1.935 + // will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1
1.936 + h->TestFree(p2);
1.937 + // will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1 && g<=page_size
1.938 + // or KHeapShrinkHysRatio >= 2.0 and g==page_size
1.939 + h->TestFree(p3);
1.940 + // may or may not perform further compression
1.941 + tmp1=h->CalcComp(g+page_size);
1.942 + tmp2=h->Compress();
1.943 + test(tmp1 == tmp2);
1.944 + test(h->Top() == orig_top);
1.945 + test(c.Size() == orig_size);
1.946 + h->FullCheck();
1.947 + test(h->TestAlloc(l2 - minc) == p2);
1.948 + test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
1.949 + test(h->Top() - orig_top == 4*g);
1.950 + test(c.Size() - orig_size == 4*g);
1.951 + h->TestFree(p3 - minc);
1.952 + h->ForceCompress(l2 + g + page_size + minc);
1.953 + test(h->Top() - orig_top == g);
1.954 + test(c.Size() - orig_size == g);
1.955 + h->FullCheck();
1.956 + if (pass)
1.957 + {
1.958 + test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
1.959 + test((TUint8*)h->FreeRef().next->next == p3 - minc - RHeap::EAllocCellSize);
1.960 + }
1.961 + else
1.962 + test((TUint8*)h->FreeRef().next == p3 - minc - RHeap::EAllocCellSize);
1.963 + h->TestFree(p2);
1.964 + if (l2+RHeap::EAllocCellSize >= shrinkThres)
1.965 + {
1.966 + // When KHeapShrinkRatio small enough heap will have been compressed
1.967 + test(h->Top() == orig_top);
1.968 + test(c.Size() - orig_size == 0);
1.969 + }
1.970 + else
1.971 + {
1.972 + test(h->Top() - orig_top == g);
1.973 + test(c.Size() - orig_size == g);
1.974 + }
1.975 + h->FullCheck();
1.976 + if ( ((TLinAddr)orig_top & (align-1)) == 0)
1.977 + {
1.978 + TAny* free;
1.979 + TEST_ALIGN(p2 - RHeap::EAllocCellSize, page_size);
1.980 + // will have free space of g-minc
1.981 + test(h->TestAlloc(l2 + minc) == p2);
1.982 + test(h->Top() - orig_top == 2*g);
1.983 + test(c.Size() - orig_size == 2*g);
1.984 + free = pass ? h->FreeRef().next->next : h->FreeRef().next;
1.985 + test(free != NULL);
1.986 + test(h->TestReAlloc(p2, l2 - 4, 0) == p2);
1.987 + TInt freeSp = g-minc + (l2+minc - (l2-4));
1.988 + TInt adjust = 0;
1.989 + if (freeSp >= shrinkThres && freeSp-page_size >= minc)
1.990 + {
1.991 + // if page_size is less than growBy (g) then heap will be shrunk
1.992 + // by less than a whole g.
1.993 + adjust = g-((page_size<g)?page_size:0);
1.994 + }
1.995 + test(h->Top() - orig_top == 2*g - adjust);
1.996 + test(c.Size() - orig_size == 2*g - adjust);
1.997 + free = pass ? h->FreeRef().next->next : h->FreeRef().next;
1.998 + test(free != NULL);
1.999 + TEST_ALIGN(TLinAddr(free)+4, page_size);
1.1000 + test(h->TestAlloc(l2 + g + page_size + 4) == p3 - 4);
1.1001 + test(h->Top() - orig_top == 4*g - adjust);
1.1002 + test(c.Size() - orig_size == 4*g - adjust);
1.1003 + h->TestFree(p3 - 4);
1.1004 + h->ForceCompress(l2 + g + page_size + 4);
1.1005 + test(h->Top() - orig_top == g + page_size);
1.1006 + test(c.Size() - orig_size == g + page_size);
1.1007 + h->FullCheck();
1.1008 + h->TestFree(p2);
1.1009 + h->ForceCompress(l2-4);
1.1010 + test(h->Compress() == 0);
1.1011 + // check heap is grown, will have free space of g-minc
1.1012 + test(h->TestAlloc(l2 + minc) == p2);
1.1013 + test(h->Top() - orig_top == 2*g);
1.1014 + test(c.Size() - orig_size == 2*g);
1.1015 + free = pass ? h->FreeRef().next->next : h->FreeRef().next;
1.1016 + test(free != NULL);
1.1017 + // may shrink heap as will now have g+minc free bytes
1.1018 + test(h->TestReAlloc(p2, l2 - minc, 0) == p2);
1.1019 + if (g+minc >= shrinkThres)
1.1020 + {
1.1021 + test(h->Top() - orig_top == g);
1.1022 + test(c.Size() - orig_size == g);
1.1023 + }
1.1024 + else
1.1025 + {
1.1026 + test(h->Top() - orig_top == 2*g);
1.1027 + test(c.Size() - orig_size == 2*g);
1.1028 + }
1.1029 + free = pass ? h->FreeRef().next->next : h->FreeRef().next;
1.1030 + test(free != NULL);
1.1031 + TEST_ALIGN(TLinAddr(free)+minc, page_size);
1.1032 + test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
1.1033 + test(h->Top() - orig_top == 4*g);
1.1034 + test(c.Size() - orig_size == 4*g);
1.1035 + h->TestFree(p3 - minc);
1.1036 + h->ForceCompress(l2 + g + page_size + minc);
1.1037 + test(h->Top() - orig_top == g);
1.1038 + test(c.Size() - orig_size == g);
1.1039 + h->FullCheck();
1.1040 + h->TestFree(p2);
1.1041 + }
1.1042 +
1.1043 + h->TestFree(p1);
1.1044 + if (pass == 0)
1.1045 + h->TestFree(p0);
1.1046 + h->Compress();
1.1047 + }
1.1048 + h->FullCheck();
1.1049 + }
1.1050 +
1.1051 +void Test1()
1.1052 + {
1.1053 + RHeap* h;
1.1054 + h = RTestHeap::FixedHeap(0x1000, 0);
1.1055 + test(h != NULL);
1.1056 + DoTest1(h);
1.1057 + h->Close();
1.1058 + h = RTestHeap::FixedHeap(0x1000, 0, EFalse);
1.1059 + test(h != NULL);
1.1060 + DoTest1(h);
1.1061 + h->Close();
1.1062 + h = RTestHeap::FixedHeap(0x10000, 64);
1.1063 + test(h != NULL);
1.1064 + DoTest1(h);
1.1065 + h->Close();
1.1066 + h = RTestHeap::FixedHeap(0x100000, 4096);
1.1067 + test(h != NULL);
1.1068 + DoTest1(h);
1.1069 + h->Close();
1.1070 + h = RTestHeap::FixedHeap(0x100000, 8192);
1.1071 + test(h != NULL);
1.1072 + DoTest1(h);
1.1073 + h->Close();
1.1074 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x1000, 0x1000, 4);
1.1075 + test(h != NULL);
1.1076 + DoTest1(h);
1.1077 + h->Close();
1.1078 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x10000, 0x1000, 4);
1.1079 + test(h != NULL);
1.1080 + DoTest1(h);
1.1081 + h->Close();
1.1082 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4096);
1.1083 + test(h != NULL);
1.1084 + DoTest1(h);
1.1085 + h->Close();
1.1086 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
1.1087 + test(h != NULL);
1.1088 + DoTest1(h);
1.1089 + h->Reset();
1.1090 + DoTest2(h);
1.1091 + h->Reset();
1.1092 + DoTest3(h);
1.1093 + h->Reset();
1.1094 + DoTest4(h);
1.1095 + h->Close();
1.1096 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
1.1097 + test(h != NULL);
1.1098 + DoTest1(h);
1.1099 + h->Reset();
1.1100 + DoTest2(h);
1.1101 + h->Reset();
1.1102 + DoTest3(h);
1.1103 + h->Reset();
1.1104 + DoTest4(h);
1.1105 + h->Close();
1.1106 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 16);
1.1107 + test(h != NULL);
1.1108 + DoTest1(h);
1.1109 + h->Reset();
1.1110 + DoTest2(h);
1.1111 + h->Reset();
1.1112 + DoTest3(h);
1.1113 + h->Reset();
1.1114 + DoTest4(h);
1.1115 + h->Close();
1.1116 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 32);
1.1117 + test(h != NULL);
1.1118 + DoTest1(h);
1.1119 + h->Reset();
1.1120 + DoTest2(h);
1.1121 + h->Reset();
1.1122 + DoTest3(h);
1.1123 + h->Reset();
1.1124 + DoTest4(h);
1.1125 + h->Close();
1.1126 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x3000, 0x100000, 0x3000, 4);
1.1127 + test(h != NULL);
1.1128 + DoTest1(h);
1.1129 + h->Reset();
1.1130 + DoTest2(h);
1.1131 + h->Reset();
1.1132 + DoTest3(h);
1.1133 + h->Reset();
1.1134 + DoTest4(h);
1.1135 + h->Close();
1.1136 + }
1.1137 +
1.1138 +struct SHeapStress
1.1139 + {
1.1140 + RThread iThread;
1.1141 + volatile TBool iStop;
1.1142 + TInt iAllocs;
1.1143 + TInt iFailedAllocs;
1.1144 + TInt iFrees;
1.1145 + TInt iReAllocs;
1.1146 + TInt iFailedReAllocs;
1.1147 + TInt iChecks;
1.1148 + TUint32 iSeed;
1.1149 + RAllocator* iAllocator;
1.1150 +
1.1151 + TUint32 Random();
1.1152 + };
1.1153 +
1.1154 +TUint32 SHeapStress::Random()
1.1155 + {
1.1156 + iSeed *= 69069;
1.1157 + iSeed += 41;
1.1158 + return iSeed;
1.1159 + }
1.1160 +
1.1161 +TInt RandomLength(TUint32 aRandom)
1.1162 + {
1.1163 + TUint8 x = (TUint8)aRandom;
1.1164 + if (x & 0x80)
1.1165 + return (x & 0x7f) << 7;
1.1166 + return x & 0x7f;
1.1167 + }
1.1168 +
1.1169 +TInt HeapStress(TAny* aPtr)
1.1170 + {
1.1171 + SHeapStress& hs = *(SHeapStress*)aPtr;
1.1172 + RTestHeap* h = (RTestHeap*)&User::Allocator();
1.1173 + TUint8* cell[256];
1.1174 + TInt len[256];
1.1175 +
1.1176 + Mem::FillZ(cell, sizeof(cell));
1.1177 + Mem::FillZ(len, sizeof(len));
1.1178 +
1.1179 + RThread::Rendezvous(KErrNone);
1.1180 + while (!hs.iStop)
1.1181 + {
1.1182 + // allocate all cells
1.1183 + TInt i;
1.1184 + for (i=0; i<256; ++i)
1.1185 + {
1.1186 + if (!cell[i])
1.1187 + {
1.1188 + ++hs.iAllocs;
1.1189 + cell[i] = (TUint8*)h->TestAlloc(RandomLength(hs.Random()));
1.1190 + if (cell[i])
1.1191 + len[i] = h->AllocLen(cell[i]);
1.1192 + else
1.1193 + ++hs.iFailedAllocs;
1.1194 + }
1.1195 + }
1.1196 +
1.1197 + // free some cells
1.1198 + TInt n = 64 + (hs.Random() & 127);
1.1199 + while (--n)
1.1200 + {
1.1201 + i = hs.Random() & 0xff;
1.1202 + if (cell[i])
1.1203 + {
1.1204 + test(h->AllocLen(cell[i]) == len[i]);
1.1205 + h->TestFree(cell[i]);
1.1206 + cell[i] = NULL;
1.1207 + len[i] = 0;
1.1208 + ++hs.iFrees;
1.1209 + }
1.1210 + }
1.1211 +
1.1212 + // realloc some cells
1.1213 + n = 64 + (hs.Random() & 127);
1.1214 + while (--n)
1.1215 + {
1.1216 + TUint32 rn = hs.Random();
1.1217 + i = (rn >> 8) & 0xff;
1.1218 + TInt new_len = RandomLength(rn);
1.1219 + if (cell[i])
1.1220 + {
1.1221 + test(h->AllocLen(cell[i]) == len[i]);
1.1222 + ++hs.iReAllocs;
1.1223 + TUint8* p = (TUint8*)h->TestReAlloc(cell[i], new_len, rn >> 16);
1.1224 + if (p)
1.1225 + {
1.1226 + cell[i] = p;
1.1227 + len[i] = h->AllocLen(p);
1.1228 + }
1.1229 + else
1.1230 + ++hs.iFailedReAllocs;
1.1231 + }
1.1232 + }
1.1233 +
1.1234 + // check the heap
1.1235 + h->Check();
1.1236 + ++hs.iChecks;
1.1237 + }
1.1238 + return 0;
1.1239 + }
1.1240 +
1.1241 +void CreateStressThread(SHeapStress& aInfo)
1.1242 + {
1.1243 + Mem::FillZ(&aInfo, _FOFF(SHeapStress, iSeed));
1.1244 + RThread& t = aInfo.iThread;
1.1245 + TInt r = t.Create(KNullDesC(), &HeapStress, 0x2000, aInfo.iAllocator, &aInfo);
1.1246 + test(r==KErrNone);
1.1247 + t.SetPriority(EPriorityLess);
1.1248 + TRequestStatus s;
1.1249 + t.Rendezvous(s);
1.1250 + test(s == KRequestPending);
1.1251 + t.Resume();
1.1252 + User::WaitForRequest(s);
1.1253 + test(s == KErrNone);
1.1254 + test(t.ExitType() == EExitPending);
1.1255 + t.SetPriority(EPriorityMuchLess);
1.1256 + }
1.1257 +
1.1258 +void StopStressThread(SHeapStress& aInfo)
1.1259 + {
1.1260 + RThread& t = aInfo.iThread;
1.1261 + TRequestStatus s;
1.1262 + t.Logon(s);
1.1263 + aInfo.iStop = ETrue;
1.1264 + User::WaitForRequest(s);
1.1265 + const TDesC& exitCat = t.ExitCategory();
1.1266 + TInt exitReason = t.ExitReason();
1.1267 + TInt exitType = t.ExitType();
1.1268 + test.Printf(_L("Exit type %d,%d,%S\n"), exitType, exitReason, &exitCat);
1.1269 + test(exitType == EExitKill);
1.1270 + test(exitReason == KErrNone);
1.1271 + test(s == KErrNone);
1.1272 + test.Printf(_L("Total Allocs : %d\n"), aInfo.iAllocs);
1.1273 + test.Printf(_L("Failed Allocs : %d\n"), aInfo.iFailedAllocs);
1.1274 + test.Printf(_L("Total Frees : %d\n"), aInfo.iFrees);
1.1275 + test.Printf(_L("Total ReAllocs : %d\n"), aInfo.iReAllocs);
1.1276 + test.Printf(_L("Failed ReAllocs : %d\n"), aInfo.iFailedReAllocs);
1.1277 + test.Printf(_L("Heap checks : %d\n"), aInfo.iChecks);
1.1278 + }
1.1279 +
1.1280 +void DoStressTest1(RAllocator* aAllocator)
1.1281 + {
1.1282 + RTestHeap* h = (RTestHeap*)aAllocator;
1.1283 + test.Printf(_L("Test Stress 1: min=%x max=%x align=%d growby=%d\n"),
1.1284 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.1285 + SHeapStress hs;
1.1286 + hs.iSeed = 0xb504f334;
1.1287 + hs.iAllocator = aAllocator;
1.1288 + CreateStressThread(hs);
1.1289 + User::After(10*1000000);
1.1290 + StopStressThread(hs);
1.1291 + CLOSE_AND_WAIT(hs.iThread);
1.1292 + h->FullCheck();
1.1293 + }
1.1294 +
1.1295 +void DoStressTest2(RAllocator* aAllocator)
1.1296 + {
1.1297 + RTestHeap* h = (RTestHeap*)aAllocator;
1.1298 + test.Printf(_L("Test Stress 2: min=%x max=%x align=%d growby=%d\n"),
1.1299 + h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
1.1300 + SHeapStress hs1;
1.1301 + SHeapStress hs2;
1.1302 + hs1.iSeed = 0xb504f334;
1.1303 + hs1.iAllocator = aAllocator;
1.1304 + hs2.iSeed = 0xddb3d743;
1.1305 + hs2.iAllocator = aAllocator;
1.1306 + CreateStressThread(hs1);
1.1307 + CreateStressThread(hs2);
1.1308 + User::After(20*1000000);
1.1309 + StopStressThread(hs1);
1.1310 + StopStressThread(hs2);
1.1311 + CLOSE_AND_WAIT(hs1.iThread);
1.1312 + CLOSE_AND_WAIT(hs2.iThread);
1.1313 + h->FullCheck();
1.1314 + }
1.1315 +
1.1316 +void StressTests()
1.1317 + {
1.1318 + RHeap* h;
1.1319 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
1.1320 + test(h != NULL);
1.1321 + DoStressTest1(h);
1.1322 + h->Reset();
1.1323 + DoStressTest2(h);
1.1324 + h->Close();
1.1325 + h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
1.1326 + test(h != NULL);
1.1327 + DoStressTest1(h);
1.1328 + h->Reset();
1.1329 + DoStressTest2(h);
1.1330 + h->Close();
1.1331 + }
1.1332 +
1.1333 +TInt TestHeapGrowInPlace(TInt aMode)
1.1334 + {
1.1335 + TBool reAllocs=EFalse;
1.1336 + TBool heapGrew=EFalse;
1.1337 +
1.1338 + RHeap* myHeap;
1.1339 +
1.1340 + myHeap = UserHeap::ChunkHeap(NULL,0x1000,0x4000,0x1000);
1.1341 +
1.1342 + TAny *testBuffer,*testBuffer2;
1.1343 + // Start size chosen so that 1st realloc will use up exactly all the heap.
1.1344 + // Later iterations wont, and there will be a free cell at the end of the heap.
1.1345 + TInt currentSize = ((0x800) - sizeof(RHeap)) - RHeap::EAllocCellSize;
1.1346 + TInt growBy = 0x800;
1.1347 + TInt newSpace, space;
1.1348 +
1.1349 + testBuffer2 = myHeap->Alloc(currentSize);
1.1350 +
1.1351 + newSpace = myHeap->Size();
1.1352 + do
1.1353 + {
1.1354 + space = newSpace;
1.1355 + testBuffer = testBuffer2;
1.1356 + currentSize+=growBy;
1.1357 + testBuffer2 = myHeap->ReAlloc(testBuffer,currentSize,aMode);
1.1358 +
1.1359 + newSpace = myHeap->Size();
1.1360 +
1.1361 + if (testBuffer2)
1.1362 + {
1.1363 +
1.1364 + if (testBuffer!=testBuffer2)
1.1365 + reAllocs = ETrue;
1.1366 +
1.1367 + if (newSpace>space)
1.1368 + heapGrew = ETrue;
1.1369 + }
1.1370 + growBy-=16;
1.1371 + } while (testBuffer2);
1.1372 + currentSize-=growBy;
1.1373 +
1.1374 + myHeap->Free(testBuffer);
1.1375 + myHeap->Close();
1.1376 +
1.1377 + // How did we do?
1.1378 + if (reAllocs)
1.1379 + {
1.1380 + test.Printf(_L("Failure - Memory was moved!\n"));
1.1381 + return -100;
1.1382 + }
1.1383 + if (!heapGrew)
1.1384 + {
1.1385 + test.Printf(_L("Failure - Heap Never Grew!\n"));
1.1386 + return -200;
1.1387 + }
1.1388 + if (currentSize<= 0x3000)
1.1389 + {
1.1390 + test.Printf(_L("Failed to grow by a reasonable amount!\n"));
1.1391 + return -300;
1.1392 + }
1.1393 +
1.1394 + return KErrNone;
1.1395 + }
1.1396 +
1.1397 +void ReAllocTests()
1.1398 + {
1.1399 + test.Next(_L("Testing Grow In Place"));
1.1400 + test(TestHeapGrowInPlace(0)==KErrNone);
1.1401 + test(TestHeapGrowInPlace(RHeap::ENeverMove)==KErrNone);
1.1402 + }
1.1403 +
1.1404 +RHeap* TestDEF078391Heap = 0;
1.1405 +
1.1406 +TInt TestDEF078391ThreadFunction(TAny*)
1.1407 + {
1.1408 + TestDEF078391Heap = UserHeap::ChunkHeap(NULL,0x1000,0x100000,KMinHeapGrowBy,0,EFalse);
1.1409 + return TestDEF078391Heap ? KErrNone : KErrGeneral;
1.1410 + }
1.1411 +
1.1412 +void TestDEF078391()
1.1413 + {
1.1414 + // Test that creating a multithreaded heap with UserHeap::ChunkHeap
1.1415 + // doesn't create any reference counts on the creating thread.
1.1416 + // This is done by creating a heap in a named thread, then exiting
1.1417 + // the thread and re-creating it with the same name.
1.1418 + // This will fail with KErrAlreadyExists if the orinal thread has
1.1419 + // not died because of an unclosed reference count.
1.1420 + test.Next(_L("Test that creating a multithreaded heap doesn't open references of creator"));
1.1421 + _LIT(KThreadName,"ThreadName");
1.1422 + RThread t;
1.1423 + TInt r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
1.1424 + test(r==KErrNone);
1.1425 + TRequestStatus status;
1.1426 + t.Logon(status);
1.1427 + t.Resume();
1.1428 + User::WaitForRequest(status);
1.1429 + test(status==KErrNone);
1.1430 + test(t.ExitType()==EExitKill);
1.1431 + test(t.ExitReason()==KErrNone);
1.1432 + CLOSE_AND_WAIT(t);
1.1433 + test(TestDEF078391Heap!=0);
1.1434 + User::After(1000000); // give more opportunity for thread cleanup to happen
1.1435 +
1.1436 + // create thread a second time
1.1437 + r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
1.1438 + test(r==KErrNone);
1.1439 + t.Kill(0);
1.1440 + CLOSE_AND_WAIT(t);
1.1441 +
1.1442 + // close the heap that got created earlier
1.1443 + TestDEF078391Heap->Close();
1.1444 + }
1.1445 +
1.1446 +TInt E32Main()
1.1447 + {
1.1448 + test.Title();
1.1449 + __KHEAP_MARK;
1.1450 + test.Start(_L("Testing heaps"));
1.1451 + TestDEF078391();
1.1452 + Test1();
1.1453 + StressTests();
1.1454 + ReAllocTests();
1.1455 + test.End();
1.1456 + __KHEAP_MARKEND;
1.1457 + return 0;
1.1458 + }