os/kernelhwsrv/kerneltest/e32test/defrag/d_pagemove.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/defrag/d_pagemove.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,504 @@
     1.4 +// Copyright (c) 2006-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\defrag\d_pagemove.cpp
    1.18 +// LDD for testing defrag page moving
    1.19 +// 
    1.20 +//
    1.21 +
    1.22 +#include <kernel/kern_priv.h>
    1.23 +#include "platform.h"
    1.24 +#include "d_pagemove.h"
    1.25 +#include "nk_priv.h"
    1.26 +
    1.27 +// debug tracing for this test driver is very noisy - off by default
    1.28 +#undef DEBUG_PAGEMOVE
    1.29 +#ifdef DEBUG_PAGEMOVE
    1.30 +#define DBG(a) a
    1.31 +#else
    1.32 +#define DBG(a)
    1.33 +#endif
    1.34 +
    1.35 +const TInt KArbitraryNumber = 4;
    1.36 +
    1.37 +// This driver is ram loaded (see mmp file) so this function will do fine
    1.38 +// as a test of RAM-loaded code.
    1.39 +TInt RamLoadedFunction()
    1.40 +	{
    1.41 +	return KArbitraryNumber;
    1.42 +	}
    1.43 +
    1.44 +const TInt KMajorVersionNumber=0;
    1.45 +const TInt KMinorVersionNumber=1;
    1.46 +const TInt KBuildVersionNumber=1;
    1.47 +
    1.48 +class DPageMove;
    1.49 +
    1.50 +class DPageMoveFactory : public DLogicalDevice
    1.51 +//
    1.52 +// Page move LDD factory
    1.53 +//
    1.54 +	{
    1.55 +public:
    1.56 +	DPageMoveFactory();
    1.57 +	virtual TInt Install();						//overriding pure virtual
    1.58 +	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
    1.59 +	virtual TInt Create(DLogicalChannelBase*& aChannel);	//overriding pure virtual
    1.60 +	};
    1.61 +
    1.62 +class DPageMove : public DLogicalChannelBase
    1.63 +//
    1.64 +// Page move logical channel
    1.65 +//
    1.66 +	{
    1.67 +public:
    1.68 +	DPageMove();
    1.69 +	~DPageMove();
    1.70 +protected:
    1.71 +	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
    1.72 +	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
    1.73 +	TInt DoPageMove(TLinAddr aAddr, TBool aEchoOff=EFalse);
    1.74 +	TInt KernelDataMovePerformance(void);
    1.75 +	TInt iPageSize;
    1.76 +	};
    1.77 +
    1.78 +DECLARE_STANDARD_LDD()
    1.79 +	{
    1.80 +    return new DPageMoveFactory;
    1.81 +    }
    1.82 +
    1.83 +DPageMoveFactory::DPageMoveFactory()
    1.84 +//
    1.85 +// Constructor
    1.86 +//
    1.87 +    {
    1.88 +    iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
    1.89 +    //iParseMask=0;//No units, no info, no PDD
    1.90 +    //iUnitsMask=0;//Only one thing
    1.91 +    }
    1.92 +
    1.93 +TInt DPageMoveFactory::Create(DLogicalChannelBase*& aChannel)
    1.94 +//
    1.95 +// Create a new DPageMove on this logical device
    1.96 +//
    1.97 +    {
    1.98 +	aChannel=new DPageMove;
    1.99 +	return aChannel?KErrNone:KErrNoMemory;
   1.100 +    }
   1.101 +
   1.102 +TInt DPageMoveFactory::Install()
   1.103 +//
   1.104 +// Install the LDD - overriding pure virtual
   1.105 +//
   1.106 +    {
   1.107 +    return SetName(&KPageMoveLddName);
   1.108 +    }
   1.109 +
   1.110 +void DPageMoveFactory::GetCaps(TDes8& aDes) const
   1.111 +//
   1.112 +// Get capabilities - overriding pure virtual
   1.113 +//
   1.114 +    {
   1.115 +    TCapsPageMoveV01 b;
   1.116 +    b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
   1.117 +    Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
   1.118 +    }
   1.119 +
   1.120 +DPageMove::DPageMove()
   1.121 +//
   1.122 +// Constructor
   1.123 +//
   1.124 +    {
   1.125 +    }
   1.126 +
   1.127 +TInt DPageMove::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
   1.128 +//
   1.129 +// Create channel
   1.130 +//
   1.131 +    {
   1.132 +    if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
   1.133 +    	return KErrNotSupported;
   1.134 +	iPageSize=Kern::RoundToPageSize(1);
   1.135 +	return KErrNone;
   1.136 +	}
   1.137 +
   1.138 +DPageMove::~DPageMove()
   1.139 +//
   1.140 +// Destructor
   1.141 +//
   1.142 +    {
   1.143 +    }
   1.144 +
   1.145 +TInt DPageMove::Request(TInt aFunction, TAny* a1, TAny* a2)
   1.146 +	{
   1.147 +	TInt r=KErrNone;
   1.148 +	DBG(Kern::Printf("DPageMove::Request func=%d a1=%08x a2=%08x", aFunction, a1, a2));
   1.149 +	NKern::ThreadEnterCS();
   1.150 +	switch (aFunction)
   1.151 +		{
   1.152 +		case RPageMove::EControlTryMovingKHeap:
   1.153 +			// Allocate a large array on the kernel heap and try moving it around.
   1.154 +			{
   1.155 +			const TInt size=16384;
   1.156 +			TUint8* array = new TUint8[size];
   1.157 +			if (array == NULL)
   1.158 +				r=KErrNoMemory;
   1.159 +			else
   1.160 +				{
   1.161 +				for (TInt i=0; i<size; i++) array[i] = i*i;
   1.162 +
   1.163 +				TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)array, iPageSize);
   1.164 +				for (TUint8* page=firstpage; page<array+size; page+=iPageSize)
   1.165 +					{
   1.166 +					r=DoPageMove((TLinAddr)page);
   1.167 +					if (r!=KErrNone)
   1.168 +						{
   1.169 +						Kern::Printf("Move returned %d", r);
   1.170 +						break;
   1.171 +						}
   1.172 +					}
   1.173 +
   1.174 +				if (r==KErrNone)
   1.175 +					{
   1.176 +					for (TInt i=0; i<size; i++)
   1.177 +						{
   1.178 +						if (array[i] != (TUint8)(i*i))
   1.179 +							{
   1.180 +							r=KErrGeneral;
   1.181 +							Kern::Printf("Data differs at index %d address %08x, expected %02x got %02x", i, &array[i], (TUint8)(i*i), array[i]);
   1.182 +							}
   1.183 +						}
   1.184 +					}
   1.185 +
   1.186 +				Kern::ValidateHeap();
   1.187 +
   1.188 +				delete [] array;
   1.189 +				}
   1.190 +			}
   1.191 +			break;
   1.192 +
   1.193 +		case RPageMove::EControlTryMovingKStack:
   1.194 +			// Stick a not-too-large array on the current thread's kernel stack and try moving it around.
   1.195 +			{
   1.196 +			const TInt size=1024;
   1.197 +			TUint8 array[size];
   1.198 +			for (TInt i=0; i<size; i++) array[i] = i*i;
   1.199 +
   1.200 +			TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)array, iPageSize);
   1.201 +			for (TUint8* page=firstpage; page<array+size; page+=iPageSize)
   1.202 +				{
   1.203 +				r=DoPageMove((TLinAddr)page);
   1.204 +				if (r!=KErrNone)
   1.205 +					{
   1.206 +					Kern::Printf("Move returned %d", r);
   1.207 +					break;
   1.208 +					}
   1.209 +				}
   1.210 +
   1.211 +			if (r==KErrNone)
   1.212 +				{
   1.213 +				for (TInt i=0; i<size; i++)
   1.214 +					{
   1.215 +					if (array[i] != (TUint8)(i*i))
   1.216 +						{
   1.217 +						r=KErrGeneral;
   1.218 +						Kern::Printf("Data differs at index %d address %08x, expected %02x got %02x", i, &array[i], (TUint8)(i*i), array[i]);
   1.219 +						}
   1.220 +					}
   1.221 +				}
   1.222 +			}
   1.223 +			break;
   1.224 +
   1.225 +		case RPageMove::EControlTryMovingUserPage:
   1.226 +		case RPageMove::EControlTryMovingLocale:
   1.227 +			// Try moving the page that the user part of the test told us to.
   1.228 +			r=DoPageMove((TLinAddr)a1, (TBool)a2);
   1.229 +			if (r!=KErrNone && !a2)
   1.230 +				Kern::Printf("Move returned %d", r);
   1.231 +			break;
   1.232 +
   1.233 +		case RPageMove::EControlTryMovingKCode:
   1.234 +			{
   1.235 +			r=DoPageMove((TLinAddr)&RamLoadedFunction);
   1.236 +			if (r==KErrNone)
   1.237 +				{
   1.238 +				if (RamLoadedFunction()!=KArbitraryNumber)
   1.239 +					r=KErrGeneral;
   1.240 +				}	
   1.241 +			else
   1.242 +				Kern::Printf("Move returned %d", r);
   1.243 +			}
   1.244 +			break;
   1.245 +
   1.246 +		case RPageMove::EControlPerfMovingKData:
   1.247 +			r = KernelDataMovePerformance();
   1.248 +			break;
   1.249 +
   1.250 +		case RPageMove::EControlGetPhysAddr:
   1.251 +			TPhysAddr addr;
   1.252 +			addr = (TUint)Epoc::LinearToPhysical((TLinAddr)a1);
   1.253 +			Kern::ThreadRawWrite(&Kern::CurrentThread(),a2, &addr, sizeof(TPhysAddr));
   1.254 +			break;
   1.255 +
   1.256 +		case RPageMove::EControlTryMovingPhysAddr:
   1.257 +			{
   1.258 +			TPhysAddr newAddr;
   1.259 +			r = Epoc::MovePhysicalPage((TPhysAddr)a1, newAddr);
   1.260 +			Kern::ThreadRawWrite(&Kern::CurrentThread(),a2, &newAddr, sizeof(TPhysAddr));
   1.261 +			break;
   1.262 +			}
   1.263 +
   1.264 +		case RPageMove::EControlTryMovingPageTable:
   1.265 +			{
   1.266 +			TPhysAddr newAddr;
   1.267 +			r = Epoc::MovePhysicalPage((TPhysAddr) a1, newAddr, Epoc::ERamDefragPage_PageTable);
   1.268 +			if (newAddr != KPhysAddrInvalid)
   1.269 +				r = KErrGeneral;
   1.270 +			break;
   1.271 +			}
   1.272 +
   1.273 +		case RPageMove::EControlTryMovingPageTableInfo:
   1.274 +			{
   1.275 +			TPhysAddr newAddr;
   1.276 +			r = Epoc::MovePhysicalPage((TPhysAddr) a1, newAddr, Epoc::ERamDefragPage_PageTableInfo);
   1.277 +			if (newAddr != KPhysAddrInvalid)
   1.278 +				r = KErrGeneral;
   1.279 +			break;
   1.280 +			}
   1.281 +
   1.282 +		case RPageMove::EControlNumberOfCpus:
   1.283 +			r = NKern::NumberOfCpus();
   1.284 +			break;
   1.285 +		default:
   1.286 +			r=KErrNotSupported;
   1.287 +			break;
   1.288 +		}
   1.289 +	NKern::ThreadLeaveCS();
   1.290 +	if (r!=KErrNone)
   1.291 +		DBG(Kern::Printf("DPageMove::Request returns %d", r));
   1.292 +	return r;
   1.293 +	}
   1.294 +
   1.295 +TInt DPageMove::DoPageMove(TLinAddr aAddr, TBool aEchoOff)
   1.296 +	{
   1.297 +	DBG(Kern::Printf("DPageMove::DoPageMove() addr=%08x",aAddr));
   1.298 +	aAddr = _ALIGN_DOWN(aAddr, iPageSize);
   1.299 +
   1.300 +	TPhysAddr aOld = Epoc::LinearToPhysical(aAddr);
   1.301 +	TInt r;
   1.302 +	if (aOld == KPhysAddrInvalid)
   1.303 +		r=KErrArgument;
   1.304 +	else
   1.305 +		{
   1.306 +		TPhysAddr aNew;
   1.307 +		r=Epoc::MovePhysicalPage(aOld, aNew);
   1.308 +		if (r==KErrNone)
   1.309 +			{
   1.310 +			TPhysAddr aNewCheck = Epoc::LinearToPhysical(aAddr);
   1.311 +			if (aNewCheck != aNew)
   1.312 +				{
   1.313 +				if (!aEchoOff)
   1.314 +					Kern::Printf("Address mismatch: expected %08x actual %08x\n",aNew,aNewCheck);
   1.315 +				if (aNew != KPhysAddrInvalid && aNewCheck != KPhysAddrInvalid)
   1.316 +					{// The page was not paged out by the moving so don't allow 
   1.317 +					// addresses to differ.  If is was paged out then it may have 
   1.318 +					// been paged back in again but to any free page so the addresses will differ.
   1.319 +					r=KErrGeneral;
   1.320 +					}
   1.321 +				}
   1.322 +			}
   1.323 +		}
   1.324 +	if (r!=KErrNone)
   1.325 +		DBG(Kern::Printf("DPageMove::DoPageMove() returns %d", r));
   1.326 +	return r;
   1.327 +	}
   1.328 +
   1.329 +
   1.330 +#ifndef __MSVC6__ 	// VC6 can't cope with variable arguments in macros.
   1.331 +#define KERN_PRINTF(x...) Kern::Printf(x)
   1.332 +#endif
   1.333 +
   1.334 +//#define EXTRA_TRACE
   1.335 +#ifdef EXTRA_TRACE
   1.336 +#define PRINTF(x)	x
   1.337 +#else
   1.338 +#define PRINTF(x)
   1.339 +#endif
   1.340 +
   1.341 +
   1.342 +TInt DPageMove::KernelDataMovePerformance(void)
   1.343 +{
   1.344 +	const TInt KHeapPagesToMove = 2000;
   1.345 +	const TInt KMoveAttempts = 50;
   1.346 +	const TInt KStackSize=1024;
   1.347 +	enum TKMoveMode
   1.348 +		{
   1.349 +		EKMoveHeap,
   1.350 +		EKMoveStack,
   1.351 +		EKMoveModes,
   1.352 +		};
   1.353 +
   1.354 +	TInt r = KErrNone;
   1.355 +
   1.356 +	// Create some kernel stack pages
   1.357 +	TUint8 stackArray[KStackSize];
   1.358 +
   1.359 +	/// Create some kernel heap pages
   1.360 +	TUint actualHeapPages = KHeapPagesToMove;
   1.361 +	TInt heapArraySize = iPageSize * KHeapPagesToMove;
   1.362 +	TUint8* heapArray = new TUint8[heapArraySize];
   1.363 +	if (heapArray == NULL)
   1.364 +		return KErrNoMemory;
   1.365 +	
   1.366 +	TInt i = 0;
   1.367 +	for (; i < heapArraySize; i++)
   1.368 +		{
   1.369 +		heapArray[i] = i;
   1.370 +		}
   1.371 +
   1.372 +	PRINTF(KERN_PRINTF("Testing Performance of Moving Kernel Data Pages"));
   1.373 +
   1.374 +	TInt moveMode = EKMoveStack;
   1.375 +	for (; moveMode < EKMoveModes; moveMode++)
   1.376 +		{
   1.377 +		TLinAddr pageAddr = NULL;
   1.378 +		TLinAddr endAddr = NULL;
   1.379 +		TLinAddr baseAddr = NULL;
   1.380 +		switch (moveMode)
   1.381 +			{
   1.382 +			case EKMoveHeap:
   1.383 +				pageAddr = _ALIGN_DOWN((TLinAddr)heapArray, iPageSize);
   1.384 +				baseAddr = pageAddr;
   1.385 +				endAddr = _ALIGN_UP((TLinAddr)heapArray + heapArraySize, iPageSize);
   1.386 +				actualHeapPages = (endAddr - baseAddr) / iPageSize;
   1.387 +				PRINTF(KERN_PRINTF("heap baseAddr %x endAddr %x", baseAddr, endAddr));
   1.388 +				break;
   1.389 +
   1.390 +			case EKMoveStack:
   1.391 +				pageAddr = _ALIGN_DOWN((TLinAddr)stackArray, iPageSize);
   1.392 +				baseAddr = pageAddr;
   1.393 +				endAddr = _ALIGN_UP((TLinAddr)stackArray + KStackSize, iPageSize);
   1.394 +				PRINTF(KERN_PRINTF("stack baseAddr %x endAddr %x", baseAddr, endAddr));
   1.395 +				break;
   1.396 +			}
   1.397 +
   1.398 +		TUint32 minTime = KMaxTUint32;
   1.399 +		TUint32 maxTime = 0; 
   1.400 +		TUint32 cummulative = 0;
   1.401 +		TInt iterations = KMoveAttempts;
   1.402 +		TInt tot = iterations;
   1.403 +		TUint pagesMoved = (endAddr - baseAddr) / iPageSize;
   1.404 +		while (iterations--)
   1.405 +			{
   1.406 +			TUint32 diff;
   1.407 +			TUint32 startTime=0;
   1.408 +			TUint32 endTime=0;
   1.409 +			switch (moveMode)
   1.410 +				{
   1.411 +				case EKMoveHeap:
   1.412 +					startTime = NKern::FastCounter(); 
   1.413 +				
   1.414 +					while (pageAddr < endAddr) 
   1.415 +						{
   1.416 +						r = DoPageMove(pageAddr);
   1.417 +
   1.418 +						if (r != KErrNone)
   1.419 +							{
   1.420 +							goto exit;
   1.421 +							}
   1.422 +						pageAddr += iPageSize;
   1.423 +						}
   1.424 +					endTime = NKern::FastCounter();
   1.425 +					break;
   1.426 +			
   1.427 +				case EKMoveStack:
   1.428 +					// Normally will move same number of pages as heap to make comparison easier
   1.429 +					TUint i = actualHeapPages;
   1.430 +					startTime = NKern::FastCounter();
   1.431 +					for (; i > 0; i--)
   1.432 +						{
   1.433 +						while (pageAddr < endAddr) 
   1.434 +							{
   1.435 +							r = DoPageMove(pageAddr);
   1.436 +
   1.437 +							if (r != KErrNone)
   1.438 +								{
   1.439 +								goto exit;
   1.440 +								}
   1.441 +							pageAddr += iPageSize;
   1.442 +							}
   1.443 +						pageAddr = baseAddr;
   1.444 +						}
   1.445 +					endTime = NKern::FastCounter();
   1.446 +					break;
   1.447 +				}
   1.448 +			diff = endTime - startTime;
   1.449 +			if (endTime < startTime) 
   1.450 +				{
   1.451 +				Kern::Printf("WARNING - fast counter overflowed. Assuming only once and continuing");
   1.452 +				diff = (KMaxTUint32 - startTime) + endTime;
   1.453 +				}
   1.454 +
   1.455 +			if (diff == 0)
   1.456 +				{
   1.457 +				Kern::Printf("difference 0!");
   1.458 +				tot--;
   1.459 +				}
   1.460 +
   1.461 +			if (diff > maxTime)
   1.462 +				maxTime = diff;
   1.463 +			if (diff < minTime)
   1.464 +				minTime = diff;
   1.465 +
   1.466 +			if (cummulative + diff < cummulative)
   1.467 +				{
   1.468 +				Kern::Printf("OverFlow!!!");
   1.469 +				r = KErrOverflow;
   1.470 +				goto exit;
   1.471 +				}
   1.472 +			pageAddr = baseAddr;
   1.473 +			cummulative += diff;
   1.474 +			}
   1.475 +		switch (moveMode)
   1.476 +			{
   1.477 +			case EKMoveHeap:				
   1.478 +				if (tot != 0)
   1.479 +					{
   1.480 +					TUint average = (cummulative / tot);
   1.481 +					Kern::Printf("Fast counter ticks to move %d kernel heap pages: Av %d Min %d Max %d (non zero iterations = %d out of %d)", pagesMoved, average, minTime, maxTime, tot, KMoveAttempts);
   1.482 +					Kern::Printf("Average of %d ticks to move one page\n", average / pagesMoved);
   1.483 +					}
   1.484 +				else
   1.485 +					Kern::Printf("WARNING - all kernel heap page moves took 0 fast counter ticks");
   1.486 +				break;
   1.487 +			
   1.488 +			case EKMoveStack:
   1.489 +				if (tot != 0)
   1.490 +					{
   1.491 +					TUint average = (cummulative / tot);
   1.492 +					Kern::Printf("Fast counter ticks to move %d kernel stack pages %d times: Av %d Min %d Max %d (non zero iterations = %d out of %d)", pagesMoved, actualHeapPages, average, minTime, maxTime, tot, KMoveAttempts);
   1.493 +					Kern::Printf("Average of %d ticks to move one page\n", average / (pagesMoved * actualHeapPages));
   1.494 +					}
   1.495 +				else
   1.496 +					Kern::Printf("WARNING - all kernel stack page moves took 0 fast counter ticks");
   1.497 +				break;
   1.498 +			}
   1.499 +		}
   1.500 +
   1.501 +	r = KErrNone;
   1.502 +exit:
   1.503 +	delete [] heapArray;
   1.504 +	return r;
   1.505 +	}
   1.506 +	
   1.507 +