kerneltest/e32test/demandpaging/d_pagestress.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/demandpaging/d_pagestress.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,465 @@
+// Copyright (c) 2005-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\demandpaging\d_pagestrss.cpp
+// 
+//
+
+#include <kernel/kern_priv.h>
+#include <kernel/cache.h>
+#include "d_pagestress.h"
+
+//
+// Class definitions
+//
+
+class DPageStressTestFactory : public DLogicalDevice
+	{
+public:
+	~DPageStressTestFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+class DPageStressTestChannel : public DLogicalChannelBase
+	{
+public:
+	DPageStressTestChannel();
+	~DPageStressTestChannel();
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+
+	TInt DoConsumeRamSetup(TInt aNumPagesLeft, TInt aPagesInBlock);
+	TInt DoConsumeRamFinish(void);
+	TInt DoConsumeSomeRam(TInt aBlocks);
+	TInt DoReleaseSomeRam(TInt aBlocks);
+	TInt FreeRam();
+	TInt DoSetDebugFlag(TInt aState);
+public:
+	DPageStressTestFactory*	iFactory;
+	
+private:
+	TBool		 iRamAllocd;
+	TInt		 iInitialFreeRam;
+	TInt		 iTotalBlocks;
+	TInt		 iBlockSize;
+	TInt		 iLastBlockAllocd;
+	TPhysAddr*	 iAddrArray;
+	TInt		 iDebug;
+	DMutex*      iMutex;
+	TInt		 iThreadCounter;
+	TPhysAddr	 iAddrMin;
+	TPhysAddr	 iAddrMax;
+	TBool		 iDemandPaging;
+	};
+
+//
+// DPageStressTestFactory
+//
+
+TInt DPageStressTestFactory::Install()
+	{
+	return SetName(&KPageStressTestLddName);
+	}
+
+DPageStressTestFactory::~DPageStressTestFactory()
+	{
+	}
+
+void DPageStressTestFactory::GetCaps(TDes8& /*aDes*/) const
+	{
+	// Not used but required as DLogicalDevice::GetCaps is pure virtual
+	}
+
+TInt DPageStressTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	aChannel = NULL;
+	DPageStressTestChannel* channel=new DPageStressTestChannel;
+	if(!channel)
+		return KErrNoMemory;
+	channel->iFactory = this;
+	aChannel = channel;
+	return KErrNone;
+	}
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DPageStressTestFactory;
+	}
+
+//
+// DPageStressTestChannel
+//
+
+TInt DPageStressTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	return KErrNone;
+	}
+
+DPageStressTestChannel::DPageStressTestChannel()
+	: iRamAllocd(EFalse), iInitialFreeRam(0), iTotalBlocks(0), iBlockSize(0), iLastBlockAllocd(0), 
+	iAddrArray(NULL), iDebug(0), iThreadCounter(1), iAddrMin(0), iAddrMax(0), iDemandPaging(ETrue)
+	{
+	_LIT(KMutexName,"TPageStressMutex");
+	NKern::ThreadEnterCS();
+	Kern::MutexCreate(iMutex, KMutexName,KMutexOrdNone);
+	NKern::ThreadLeaveCS();
+	SVMCacheInfo tempPages;
+	if (Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) != KErrNone)
+		{
+		iDemandPaging = EFalse;
+		}
+	}
+
+DPageStressTestChannel::~DPageStressTestChannel()
+	{
+	if (iRamAllocd)
+		{
+		DoConsumeRamFinish();
+		}
+	if (iMutex)
+        {
+		iMutex->Close(NULL);
+		iMutex = NULL;
+		}
+	}
+
+TInt DPageStressTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt threadCount = __e32_atomic_tas_ord32(&iThreadCounter, 1, 1, 0);
+	if (threadCount >= 2)
+		{
+		Kern::Printf("DPageStressTestChannel::Request threadCount = %d\n", threadCount);
+		}
+	NKern::ThreadEnterCS();
+	Kern::MutexWait(*iMutex);
+	TInt retVal = KErrNotSupported;
+	switch(aFunction)
+		{
+		case RPageStressTestLdd::EDoConsumeRamSetup:
+			{
+			retVal = DPageStressTestChannel::DoConsumeRamSetup((TInt)a1, (TInt)a2);
+			}
+		break;
+
+		case RPageStressTestLdd::EDoConsumeRamFinish:
+			{
+			retVal = DPageStressTestChannel::DoConsumeRamFinish();
+			}
+		break;
+
+		case RPageStressTestLdd::EDoConsumeSomeRam:
+			{
+			retVal = DPageStressTestChannel::DoConsumeSomeRam((TInt)a1);
+			}
+		break;
+
+		case RPageStressTestLdd::EDoReleaseSomeRam:
+			{
+			retVal = DPageStressTestChannel::DoReleaseSomeRam((TInt)a1);
+			}
+		break;
+		
+		case RPageStressTestLdd::EDoSetDebugFlag:
+			{
+			retVal = DoSetDebugFlag((TInt) a1);
+			}
+		break;
+		
+		default: break;
+		}
+	Kern::MutexSignal(*iMutex);
+	NKern::ThreadLeaveCS();
+	__e32_atomic_tas_ord32(&iThreadCounter, 1, -1, 0);
+	return retVal;
+	}
+
+// 
+// DPageStressTestChannel::DoConsumeRamSetup
+//
+// This test attempts to consume most of the available Contiguous Ram until we need to ask the 
+// demand paging code to release memory for it.
+// 
+// 
+//
+#define CHECK(c) { if(!(c)) { Kern::Printf("Fail  %d", __LINE__); ; retVal = __LINE__;} }
+
+TInt DPageStressTestChannel::DoConsumeRamSetup(TInt aNumPagesLeft, TInt aPagesInBlock)
+	{
+	if (iRamAllocd)
+		{
+		Kern::Printf("DPageStressTestChannel trying to start again when RAM alloc'd\n");
+		DoConsumeRamFinish();
+		}
+
+	TInt retVal = KErrNone;
+
+	TInt pageSize = 0;
+	CHECK(Kern::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0)==KErrNone);
+	
+	iBlockSize = aPagesInBlock * pageSize;
+	iInitialFreeRam = FreeRam();
+	iTotalBlocks = (iInitialFreeRam/iBlockSize) + 10;
+	
+	iAddrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * iTotalBlocks);
+
+	CHECK(iAddrArray);
+	if(!iAddrArray)
+		{
+		return KErrNoMemory;
+		}
+	
+	SVMCacheInfo tempPages;
+
+	iRamAllocd = ETrue;
+
+	// get the initial free ram again as the heap may have grabbed a page during the alloc
+	iInitialFreeRam = FreeRam();
+
+
+	if (iDemandPaging)
+		{
+		CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+		if (iDebug)
+			{
+			Kern::Printf("Start : min %d max %d current %d maxFree %d freeRam %d",
+						 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam());
+			}
+		}
+	// allocate blocks to use up RAM until we fail to allocate any further...
+	TInt index;
+	// only alloc upto the point where we have a number of pages left.
+	iLastBlockAllocd = iTotalBlocks - (aNumPagesLeft / aPagesInBlock);
+	for (index = 0; index < iLastBlockAllocd; index ++)
+		{
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			}
+
+		if (KErrNone != Epoc::AllocPhysicalRam(iBlockSize, iAddrArray[index], 0))
+			{
+			iAddrArray[index] = NULL;
+			break;
+			}
+
+		if ((iAddrMin == 0) || (iAddrMin > iAddrArray[index]))
+			{
+			iAddrMin = iAddrArray[index];
+			}
+		
+		if (iAddrMax < iAddrArray[index])
+			{
+			iAddrMax = iAddrArray[index];
+			}
+
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			}
+		}
+	iLastBlockAllocd = index - 1;
+
+	if (iDemandPaging)
+		{
+		CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+		if (iDebug)
+			{
+			Kern::Printf("Alloc'd : min %d max %d current %d maxFree %d freeRam %d lastIndex %d addrMin 0x%08x addrMax 0x%08x",
+						 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam(), iLastBlockAllocd, iAddrMin, iAddrMax);
+			}
+		}
+	return retVal;
+	}
+
+TInt DPageStressTestChannel::DoConsumeRamFinish(void)
+	{
+	TInt retVal = KErrNone;
+	if (iRamAllocd)
+		{
+		SVMCacheInfo tempPages;
+
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			if (iDebug)
+				{
+				Kern::Printf("Cleanup cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d",
+							 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize);
+				}
+			}
+		TInt index = iTotalBlocks - 1;
+
+		TBool firstTime = ETrue;
+
+		// free the memory we allocated...
+		while(index >= 0)
+			{
+			if (iAddrArray[index])
+				{
+				if ((iAddrArray[index] < iAddrMin) || (iAddrArray[index] > iAddrMax))
+					{
+					Kern::Printf("ERROR: DoConsumeRamFinish : index %d addr 0x%08x min 0x%08x max 0x%08x\n     : firstTime %d iLastBlockAllocd %d iTotalBlock %d", index, iAddrArray[index], iAddrMin, iAddrMax, firstTime, iLastBlockAllocd, iTotalBlocks);
+					TInt tempIndex = index - 8;
+					while (tempIndex < (index + 8))
+						{
+						Kern::Printf("      --> index %d addr 0x%08x", tempIndex, iAddrArray[tempIndex]);
+						tempIndex ++;
+						}
+					
+					iAddrArray[index] = NULL;
+					}
+				else
+					{
+					TInt r = Epoc::FreePhysicalRam(iAddrArray[index], iBlockSize);
+					iAddrArray[index] = NULL;
+					CHECK(r==KErrNone);
+					}
+				}
+
+			firstTime = EFalse;
+			--index;
+			}
+
+		if (iDebug)
+			{
+			Kern::Printf("DoConsumeRamFinish : FreeRam Initial 0x%x now 0x%x",iInitialFreeRam, FreeRam());
+			}
+		//CHECK(FreeRam() == iInitialFreeRam)
+		if (FreeRam() != iInitialFreeRam)
+			{
+			Kern::Printf("DoConsumeRamFinish : FreeRam Initial 0x%x now 0x%x NOT EQUAL!",iInitialFreeRam, FreeRam());
+			}
+
+		Kern::Free(iAddrArray);
+		iAddrArray = NULL;
+		iAddrMin = 0;
+		iAddrMax = 0;
+		iLastBlockAllocd = -1;
+		iTotalBlocks = 0;
+		iRamAllocd = EFalse;
+
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			if (iDebug)
+				{
+				Kern::Printf("End cache info: iMinSize %d iMaxSize %d iCurrentSize %d iMaxFreeSize %d",
+							 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize);
+				}
+			}
+		}	
+	return retVal;
+	}
+
+TInt DPageStressTestChannel::DoConsumeSomeRam(TInt aBlocks)
+	{
+	TInt retVal = KErrNone;
+
+	return retVal;
+	}
+
+TInt DPageStressTestChannel::DoReleaseSomeRam(TInt aBlocks)
+	{
+	if(iLastBlockAllocd<0)
+		return KErrUnderflow;
+
+	TInt retVal = KErrNone;
+	if (iRamAllocd)
+		{
+		SVMCacheInfo tempPages;
+
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			if (iDebug)
+				{
+				Kern::Printf("Release  : min %d max %d current %d maxFree %d freeRam %d lastIndex %d",
+							 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam(), iLastBlockAllocd);
+				}
+			}
+		
+		TInt index = iLastBlockAllocd;
+		iLastBlockAllocd -= aBlocks;
+		
+		TBool firstTime = ETrue;
+
+		// free the memory we allocated...
+		while((index >= 0) && (index > iLastBlockAllocd))
+			{
+			if (iAddrArray[index])
+				{
+				//Kern::Printf("DoReleaseSomeRam : index %d addr 0x%08x size %d", index, iAddrArray[index], iBlockSize);
+				if ((iAddrArray[index] < iAddrMin) || (iAddrArray[index] > iAddrMax))
+					{
+					Kern::Printf("ERROR: DoReleaseSomeRam : index %d addr 0x%08x min 0x%08x max 0x%08x\n     : firstTime %d iLastBlockAllocd %d iTotalBlock %d", index, iAddrArray[index], iAddrMin, iAddrMax, firstTime, iLastBlockAllocd + aBlocks, iTotalBlocks);
+					TInt tempIndex = index - 8;
+					while (tempIndex < (index + 8))
+						{
+						Kern::Printf("      --> index %d addr 0x%08x", tempIndex, iAddrArray[tempIndex]);
+						tempIndex ++;
+						}
+
+					iAddrArray[index] = NULL;
+					}
+				else
+					{
+					TInt r = Epoc::FreePhysicalRam(iAddrArray[index], iBlockSize);
+					iAddrArray[index] = NULL;
+					CHECK(r==KErrNone);
+					}
+				}
+			else
+				{
+				Kern::Printf("ERROR: DoReleaseSomeRam : trying to free NULL index %d", index, iAddrArray[index], iAddrMin, iAddrMax);
+				TInt tempIndex = index - 8;
+				while (tempIndex < (index + 8))
+					{
+					Kern::Printf("      --> index %d addr 0x%08x", tempIndex, iAddrArray[tempIndex]);
+					tempIndex ++;
+					}
+
+				}
+			firstTime = EFalse;
+			--index;
+			}
+		if (index <= 0)
+			{
+			Kern::Printf("WARNING : DoReleaseSomeRam : index %d !!!!!", index);
+			}
+
+		if (iDemandPaging)
+			{
+			CHECK(Kern::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&tempPages,0) == KErrNone);
+			if (iDebug)
+				{
+				Kern::Printf("Released : min %d max %d current %d maxFree %d freeRam %d lastIndex %d",
+							 tempPages.iMinSize, tempPages.iMaxSize, tempPages.iCurrentSize ,tempPages.iMaxFreeSize, FreeRam(), iLastBlockAllocd);
+				}	
+			}
+		}
+	return retVal;
+	}
+
+
+TInt DPageStressTestChannel::FreeRam()
+	{
+	return Kern::FreeRamInBytes();
+	}
+
+TInt DPageStressTestChannel::DoSetDebugFlag(TInt aState)
+	{
+	iDebug = aState;
+	return KErrNone;
+	}