Update contrib.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\defrag\d_pagemove.cpp
15 // LDD for testing defrag page moving
19 #include <kernel/kern_priv.h>
21 #include "d_pagemove.h"
24 // debug tracing for this test driver is very noisy - off by default
32 const TInt KArbitraryNumber = 4;
34 // This driver is ram loaded (see mmp file) so this function will do fine
35 // as a test of RAM-loaded code.
36 TInt RamLoadedFunction()
38 return KArbitraryNumber;
41 const TInt KMajorVersionNumber=0;
42 const TInt KMinorVersionNumber=1;
43 const TInt KBuildVersionNumber=1;
47 class DPageMoveFactory : public DLogicalDevice
49 // Page move LDD factory
54 virtual TInt Install(); //overriding pure virtual
55 virtual void GetCaps(TDes8& aDes) const; //overriding pure virtual
56 virtual TInt Create(DLogicalChannelBase*& aChannel); //overriding pure virtual
59 class DPageMove : public DLogicalChannelBase
61 // Page move logical channel
68 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
69 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
70 TInt DoPageMove(TLinAddr aAddr, TBool aEchoOff=EFalse);
71 TInt KernelDataMovePerformance(void);
75 DECLARE_STANDARD_LDD()
77 return new DPageMoveFactory;
80 DPageMoveFactory::DPageMoveFactory()
85 iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
86 //iParseMask=0;//No units, no info, no PDD
87 //iUnitsMask=0;//Only one thing
90 TInt DPageMoveFactory::Create(DLogicalChannelBase*& aChannel)
92 // Create a new DPageMove on this logical device
95 aChannel=new DPageMove;
96 return aChannel?KErrNone:KErrNoMemory;
99 TInt DPageMoveFactory::Install()
101 // Install the LDD - overriding pure virtual
104 return SetName(&KPageMoveLddName);
107 void DPageMoveFactory::GetCaps(TDes8& aDes) const
109 // Get capabilities - overriding pure virtual
113 b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
114 Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
117 DPageMove::DPageMove()
124 TInt DPageMove::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
129 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
130 return KErrNotSupported;
131 iPageSize=Kern::RoundToPageSize(1);
135 DPageMove::~DPageMove()
142 TInt DPageMove::Request(TInt aFunction, TAny* a1, TAny* a2)
145 DBG(Kern::Printf("DPageMove::Request func=%d a1=%08x a2=%08x", aFunction, a1, a2));
146 NKern::ThreadEnterCS();
149 case RPageMove::EControlTryMovingKHeap:
150 // Allocate a large array on the kernel heap and try moving it around.
152 const TInt size=16384;
153 TUint8* array = new TUint8[size];
158 for (TInt i=0; i<size; i++) array[i] = i*i;
160 TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)array, iPageSize);
161 for (TUint8* page=firstpage; page<array+size; page+=iPageSize)
163 r=DoPageMove((TLinAddr)page);
166 Kern::Printf("Move returned %d", r);
173 for (TInt i=0; i<size; i++)
175 if (array[i] != (TUint8)(i*i))
178 Kern::Printf("Data differs at index %d address %08x, expected %02x got %02x", i, &array[i], (TUint8)(i*i), array[i]);
183 Kern::ValidateHeap();
190 case RPageMove::EControlTryMovingKStack:
191 // Stick a not-too-large array on the current thread's kernel stack and try moving it around.
193 const TInt size=1024;
195 for (TInt i=0; i<size; i++) array[i] = i*i;
197 TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)array, iPageSize);
198 for (TUint8* page=firstpage; page<array+size; page+=iPageSize)
200 r=DoPageMove((TLinAddr)page);
203 Kern::Printf("Move returned %d", r);
210 for (TInt i=0; i<size; i++)
212 if (array[i] != (TUint8)(i*i))
215 Kern::Printf("Data differs at index %d address %08x, expected %02x got %02x", i, &array[i], (TUint8)(i*i), array[i]);
222 case RPageMove::EControlTryMovingUserPage:
223 case RPageMove::EControlTryMovingLocale:
224 // Try moving the page that the user part of the test told us to.
225 r=DoPageMove((TLinAddr)a1, (TBool)a2);
226 if (r!=KErrNone && !a2)
227 Kern::Printf("Move returned %d", r);
230 case RPageMove::EControlTryMovingKCode:
232 r=DoPageMove((TLinAddr)&RamLoadedFunction);
235 if (RamLoadedFunction()!=KArbitraryNumber)
239 Kern::Printf("Move returned %d", r);
243 case RPageMove::EControlPerfMovingKData:
244 r = KernelDataMovePerformance();
247 case RPageMove::EControlGetPhysAddr:
249 addr = (TUint)Epoc::LinearToPhysical((TLinAddr)a1);
250 Kern::ThreadRawWrite(&Kern::CurrentThread(),a2, &addr, sizeof(TPhysAddr));
253 case RPageMove::EControlTryMovingPhysAddr:
256 r = Epoc::MovePhysicalPage((TPhysAddr)a1, newAddr);
257 Kern::ThreadRawWrite(&Kern::CurrentThread(),a2, &newAddr, sizeof(TPhysAddr));
261 case RPageMove::EControlTryMovingPageTable:
264 r = Epoc::MovePhysicalPage((TPhysAddr) a1, newAddr, Epoc::ERamDefragPage_PageTable);
265 if (newAddr != KPhysAddrInvalid)
270 case RPageMove::EControlTryMovingPageTableInfo:
273 r = Epoc::MovePhysicalPage((TPhysAddr) a1, newAddr, Epoc::ERamDefragPage_PageTableInfo);
274 if (newAddr != KPhysAddrInvalid)
279 case RPageMove::EControlNumberOfCpus:
280 r = NKern::NumberOfCpus();
286 NKern::ThreadLeaveCS();
288 DBG(Kern::Printf("DPageMove::Request returns %d", r));
292 TInt DPageMove::DoPageMove(TLinAddr aAddr, TBool aEchoOff)
294 DBG(Kern::Printf("DPageMove::DoPageMove() addr=%08x",aAddr));
295 aAddr = _ALIGN_DOWN(aAddr, iPageSize);
297 TPhysAddr aOld = Epoc::LinearToPhysical(aAddr);
299 if (aOld == KPhysAddrInvalid)
304 r=Epoc::MovePhysicalPage(aOld, aNew);
307 TPhysAddr aNewCheck = Epoc::LinearToPhysical(aAddr);
308 if (aNewCheck != aNew)
311 Kern::Printf("Address mismatch: expected %08x actual %08x\n",aNew,aNewCheck);
312 if (aNew != KPhysAddrInvalid && aNewCheck != KPhysAddrInvalid)
313 {// The page was not paged out by the moving so don't allow
314 // addresses to differ. If is was paged out then it may have
315 // been paged back in again but to any free page so the addresses will differ.
322 DBG(Kern::Printf("DPageMove::DoPageMove() returns %d", r));
327 #ifndef __MSVC6__ // VC6 can't cope with variable arguments in macros.
328 #define KERN_PRINTF(x...) Kern::Printf(x)
331 //#define EXTRA_TRACE
339 TInt DPageMove::KernelDataMovePerformance(void)
341 const TInt KHeapPagesToMove = 2000;
342 const TInt KMoveAttempts = 50;
343 const TInt KStackSize=1024;
353 // Create some kernel stack pages
354 TUint8 stackArray[KStackSize];
356 /// Create some kernel heap pages
357 TUint actualHeapPages = KHeapPagesToMove;
358 TInt heapArraySize = iPageSize * KHeapPagesToMove;
359 TUint8* heapArray = new TUint8[heapArraySize];
360 if (heapArray == NULL)
364 for (; i < heapArraySize; i++)
369 PRINTF(KERN_PRINTF("Testing Performance of Moving Kernel Data Pages"));
371 TInt moveMode = EKMoveStack;
372 for (; moveMode < EKMoveModes; moveMode++)
374 TLinAddr pageAddr = NULL;
375 TLinAddr endAddr = NULL;
376 TLinAddr baseAddr = NULL;
380 pageAddr = _ALIGN_DOWN((TLinAddr)heapArray, iPageSize);
382 endAddr = _ALIGN_UP((TLinAddr)heapArray + heapArraySize, iPageSize);
383 actualHeapPages = (endAddr - baseAddr) / iPageSize;
384 PRINTF(KERN_PRINTF("heap baseAddr %x endAddr %x", baseAddr, endAddr));
388 pageAddr = _ALIGN_DOWN((TLinAddr)stackArray, iPageSize);
390 endAddr = _ALIGN_UP((TLinAddr)stackArray + KStackSize, iPageSize);
391 PRINTF(KERN_PRINTF("stack baseAddr %x endAddr %x", baseAddr, endAddr));
395 TUint32 minTime = KMaxTUint32;
397 TUint32 cummulative = 0;
398 TInt iterations = KMoveAttempts;
399 TInt tot = iterations;
400 TUint pagesMoved = (endAddr - baseAddr) / iPageSize;
409 startTime = NKern::FastCounter();
411 while (pageAddr < endAddr)
413 r = DoPageMove(pageAddr);
419 pageAddr += iPageSize;
421 endTime = NKern::FastCounter();
425 // Normally will move same number of pages as heap to make comparison easier
426 TUint i = actualHeapPages;
427 startTime = NKern::FastCounter();
430 while (pageAddr < endAddr)
432 r = DoPageMove(pageAddr);
438 pageAddr += iPageSize;
442 endTime = NKern::FastCounter();
445 diff = endTime - startTime;
446 if (endTime < startTime)
448 Kern::Printf("WARNING - fast counter overflowed. Assuming only once and continuing");
449 diff = (KMaxTUint32 - startTime) + endTime;
454 Kern::Printf("difference 0!");
463 if (cummulative + diff < cummulative)
465 Kern::Printf("OverFlow!!!");
477 TUint average = (cummulative / tot);
478 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);
479 Kern::Printf("Average of %d ticks to move one page\n", average / pagesMoved);
482 Kern::Printf("WARNING - all kernel heap page moves took 0 fast counter ticks");
488 TUint average = (cummulative / tot);
489 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);
490 Kern::Printf("Average of %d ticks to move one page\n", average / (pagesMoved * actualHeapPages));
493 Kern::Printf("WARNING - all kernel stack page moves took 0 fast counter ticks");