libraries/ltkutils/tsrc/tallochelper.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 37 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// 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;
		}
	}