// tallochelper.cpp
//
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <fshell/ioutils.h>
#include <fshell/common.mmh>
#include <fshell/heaputils.h>
#include <fshell/ltkutils.h>
using namespace IoUtils;
using LtkUtils::RAllocatorHelper;
class CCmdTAllocHelper : public CCommandBase
{
public:
static CCommandBase* NewLC();
~CCmdTAllocHelper();
private:
CCmdTAllocHelper();
void PrintStats(const TDesC& aDesc);
void AllocL(TInt aSize, TInt aNumber=1);
void Free(TInt aNumber=1);
void FormatSize(TDes& aBuf, TInt64 aSize);
static TBool WalkCallback(RAllocatorHelper& aAlloc, TAny* aContext, RAllocatorHelper::TExtendedCellType aType, TLinAddr aAddress, TInt aLength);
static void RHeapWalkCallback(TAny* aContext, RHeap::TCellType aType, TAny* aCell, TInt aLength);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual const TDesC& Description() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private:
RAllocatorHelper iAlloc;
RArray<TAny*> iAllocations;
TBool iBytes;
TBool iWaitOnExit;
TInt iAllocationsAccordingToRHeapWalker;
};
EXE_BOILER_PLATE(CCmdTAllocHelper)
CCommandBase* CCmdTAllocHelper::NewLC()
{
CCmdTAllocHelper* self = new(ELeave) CCmdTAllocHelper();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdTAllocHelper::~CCmdTAllocHelper()
{
iAlloc.Close();
Free(iAllocations.Count());
iAllocations.Close();
}
CCmdTAllocHelper::CCmdTAllocHelper()
: CCommandBase(EManualComplete)
{
}
const TDesC& CCmdTAllocHelper::Name() const
{
_LIT(KName, "tallochelper");
return KName;
}
const TDesC& CCmdTAllocHelper::Description() const
{
_LIT(KDescription, "Test code for RAllocatorHelper");
return KDescription;
}
void CCmdTAllocHelper::ArgumentsL(RCommandArgumentList& /*aArguments*/)
{
}
void CCmdTAllocHelper::OptionsL(RCommandOptionList& aOptions)
{
aOptions.AppendBoolL(iBytes, 'b', _L("bytes"), _L("Display sizes in bytes rather than rounded off KB or MB"));
aOptions.AppendBoolL(iWaitOnExit, 'w', _L("wait"), _L("Wait indefinitely before exiting - for testing remote heap walking"));
}
void CCmdTAllocHelper::DoRunL()
{
LeaveIfErr(iAlloc.Open(&User::Allocator()), _L("Couldn't open RAllocatorHelper"));
iAllocations.ReserveL(128);
Printf(_L("Udeb allocator=%d\r\n"), iAlloc.AllocatorIsUdeb());
PrintStats(_L("Initial stats"));
// And do an RHeap walk, just to compare
User::Allocator().DebugFunction(128, (TAny*)&RHeapWalkCallback, this);
Printf(_L("allocated size according to RHeap::Walk: %d\r\n"), iAllocationsAccordingToRHeapWalker);
AllocL(64*1024);
PrintStats(_L("Stats after 1 64K alloc"));
User::Allocator().DebugFunction(128, (TAny*)&RHeapWalkCallback, this); // debug
AllocL(4, 50);
PrintStats(_L("Stats after 50 small allocs"));
/*
// Open a new RAllocatorHelper cos the stats will be cached otherwise
RAllocatorHelper h; h.Open(&User::Allocator());
iAllocationsAccordingToRHeapWalker = 0;
User::Allocator().DebugFunction(128, (TAny*)&RHeapWalkCallback, this);
Printf(_L("allocated size according to RHeap::Walk: %d\r\n"), iAllocationsAccordingToRHeapWalker);
Printf(_L("iTotalAllocSize is %d\r\n"), h.AllocatedSize());
h.Close();
*/
if (!iWaitOnExit)
{
Free(50);
PrintStats(_L("Stats after freeing them"));
Complete();
}
}
void CCmdTAllocHelper::PrintStats(const TDesC& aDesc)
{
iAlloc.RefreshDetails();
TBuf<16> allocSize, freeSize, dlaSize, slabSize, freeDlaSize, partiallyFreeSlabSize, freeSlabSize, pageSize;
FormatSize(allocSize, iAlloc.SizeForCellType(RAllocatorHelper::EAllocationMask));
FormatSize(freeSize, iAlloc.SizeForCellType(RAllocatorHelper::EFreeMask));
FormatSize(dlaSize, iAlloc.SizeForCellType(RAllocatorHelper::EDlaAllocation));
FormatSize(slabSize, iAlloc.SizeForCellType(RAllocatorHelper::ESlabAllocation));
FormatSize(freeDlaSize, iAlloc.SizeForCellType(RAllocatorHelper::EDlaFreeCell));
FormatSize(partiallyFreeSlabSize, iAlloc.SizeForCellType(RAllocatorHelper::ESlabFreeCell));
FormatSize(freeSlabSize, iAlloc.SizeForCellType(RAllocatorHelper::ESlabFreeSlab));
FormatSize(pageSize, iAlloc.SizeForCellType(RAllocatorHelper::EPageAllocation));
Printf(_L("\r\n%S:\r\n\
Alloc: %d (%S), DLA: %d (%S) Slab: %d (%S) Paged: %d (%S)\r\n\
Free: %d (%S), DLA: %d (%S) Slab: %d (%S) Free slabs: %d (%S)\r\n"),
&aDesc, iAlloc.AllocationCount(), &allocSize,
iAlloc.CountForCellType(RAllocatorHelper::EDlaAllocation), &dlaSize,
iAlloc.CountForCellType(RAllocatorHelper::ESlabAllocation), &slabSize,
iAlloc.CountForCellType(RAllocatorHelper::EPageAllocation), &pageSize,
iAlloc.CountForCellType(RAllocatorHelper::EFreeMask), &freeSize,
iAlloc.CountForCellType(RAllocatorHelper::EDlaFreeCell), &freeDlaSize,
iAlloc.CountForCellType(RAllocatorHelper::ESlabFreeCell), &partiallyFreeSlabSize,
iAlloc.CountForCellType(RAllocatorHelper::ESlabFreeSlab), &freeSlabSize
);
iAlloc.Walk(&WalkCallback, this); // Check cell lengths match up
}
void CCmdTAllocHelper::AllocL(TInt aSize, TInt aNumber)
{
while (aNumber--)
{
TAny* result = User::AllocL(aSize);
TInt err = iAllocations.Append(result);
if (err)
{
User::Free(result);
User::Leave(KErrNoMemory);
}
}
}
void CCmdTAllocHelper::Free(TInt aNumber)
{
while (aNumber--)
{
TInt i = iAllocations.Count() - 1;
User::Free(iAllocations[i]);
iAllocations.Remove(i);
}
}
void CCmdTAllocHelper::FormatSize(TDes& aBuf, TInt64 aSize)
{
if (iBytes)
{
aBuf.Num(aSize);
}
else
{
LtkUtils::FormatSize(aBuf, aSize);
}
}
TBool CCmdTAllocHelper::WalkCallback(RAllocatorHelper& /*aAlloc*/, TAny* aContext, RAllocatorHelper::TExtendedCellType aType, TLinAddr aAddress, TInt aLength)
{
if (aType & RAllocatorHelper::EAllocationMask)
{
TInt lenFromAllocLen = User::AllocLen((TAny*)aAddress);
if (lenFromAllocLen != aLength)
{
static_cast<CCmdTAllocHelper*>(aContext)->PrintWarning(_L("Walker reports cell 0x%08x size %d but AllocLen says %d\r\n"), aAddress, aLength, lenFromAllocLen);
}
}
return ETrue; // Keep walking
}
void CCmdTAllocHelper::RHeapWalkCallback(TAny* aContext, RHeap::TCellType aType, TAny* aCell, TInt aLength)
{
if (aType == RHeap::EGoodAllocatedCell)
{
CCmdTAllocHelper* self = static_cast<CCmdTAllocHelper*>(aContext);
self->iAllocationsAccordingToRHeapWalker += aLength;
}
}