--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/demandpaging/t_wdpsoak.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,643 @@
+// 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\mmu\t_wdpsoak.cpp
+//
+//
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <dptest.h>
+#include <hal.h>
+#include "../mmu/mmudetect.h"
+#include "../mmu/freeram.h"
+
+#define MAX_CHUNKS 10
+#define PRINT(string) if (!gQuiet) test.Printf(string)
+#define PRINT1(string,param) if (!gQuiet) test.Printf(string,param)
+#define TESTNEXT(string) if (!gQuiet) test.Next(string)
+
+//------------globals---------------------
+LOCAL_D RTest test(_L("T_WDPSOAK"));
+LOCAL_D TInt gPageSize = 0;
+LOCAL_D TUint gChunkSize = 0; // default chunk size
+LOCAL_D RChunk gChunk[MAX_CHUNKS];
+LOCAL_D TUint gNextChunk = 0;
+LOCAL_D TBool gQuiet = EFalse;
+LOCAL_D TUint gPeriod = 0;
+LOCAL_D TUint gMin = 0;
+LOCAL_D TUint gMax = 0;
+LOCAL_D TUint gMemScheme = 0;
+
+const TUint32 KFlushQuietLimit = 100000;
+
+TUint64 SwapFree()
+ {
+ SVMSwapInfo swapInfo;
+ test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalGetSwapInfo, &swapInfo, 0));
+
+ return swapInfo.iSwapFree;
+ }
+
+TUint64 SwapSize()
+ {
+ SVMSwapInfo swapInfo;
+ test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalGetSwapInfo, &swapInfo, 0));
+
+ return swapInfo.iSwapSize;
+ }
+
+void CacheSize(TUint aMin, TUint aMax)
+ {
+ SVMCacheInfo info;
+ if (UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&info,0) != KErrNone)
+ {
+ return;
+ }
+
+ if (aMin > 0 || aMax > 0)
+ {
+ if (aMin > 0)
+ {
+ info.iMinSize = aMin;
+ }
+ if (aMax > 0)
+ {
+ info.iMaxSize = aMax;
+ }
+ UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)info.iMinSize,(TAny*)info.iMaxSize);
+ if (UserSvr::HalFunction(EHalGroupVM,EVMHalGetCacheSize,&info,0) != KErrNone)
+ {
+ return;
+ }
+ }
+
+ PRINT1(_L("Paging Cache min size %d"),info.iMinSize);
+ PRINT1(_L(" max size %d"),info.iMaxSize);
+ PRINT1(_L(" current size %d\n"),info.iCurrentSize);
+ }
+
+void ShowMemoryUse()
+ {
+ PRINT1(_L("RAM free 0x%08X bytes"),FreeRam());
+ PRINT1(_L(" Swap free 0x%08X bytes\n"),SwapFree());
+
+ TPckgBuf<DPTest::TEventInfo> infoBuf;
+ TInt r = UserSvr::HalFunction(EHalGroupVM,EVMHalGetEventInfo,&infoBuf,0);
+ if (r!=KErrNone)
+ {
+ return;
+ }
+ PRINT1(_L("Page fault count %d"),infoBuf().iPageFaultCount);
+ PRINT1(_L(" Page IN count %d\n"),infoBuf().iPageInReadCount);
+
+ return;
+ }
+
+void ShowHelp()
+ {
+ PRINT(_L("***************************************\n"));
+ PRINT(_L("The following are immediate commands\n"));
+ PRINT(_L("F flush the paging cache\n"));
+ PRINT(_L("I show memory information\n"));
+ PRINT(_L("? show this help\n"));
+ PRINT(_L("Rn read all pages of chunk n\n"));
+ PRINT(_L("Wn write all pages of chunk n\n"));
+ PRINT(_L("Mn periodic memory scheme n\n"));
+ PRINT(_L("The following require a <CR> termination\n"));
+ PRINT(_L("C=nnnn create a chunnk of size nnnn\n"));
+ PRINT(_L("L=nnnn paging cache min size nnnn\n"));
+ PRINT(_L("H=nnnn paging cache max size nnnn\n"));
+ PRINT(_L("P=nnnn periodic flush/memory scheme nnnn microseconds\n"));
+ PRINT(_L("Esc to exit\n"));
+ PRINT(_L("***************************************\n"));
+ }
+
+void CreateChunk(RChunk * aChunk, TUint aSize)
+ {
+ TESTNEXT(_L("Creating a paged chunk"));
+ TChunkCreateInfo createInfo;
+ PRINT1(_L("Creating chunk size 0x%08X bytes "),aSize);
+ PRINT1(_L("at index %d\n"),gNextChunk);
+ createInfo.SetPaging(TChunkCreateInfo::EPaged);
+ createInfo.SetNormal(aSize,aSize);
+ test_KErrNone(aChunk->Create(createInfo));
+ }
+
+void ReadChunk(RChunk * aChunk)
+ {
+ TESTNEXT(_L("Reading from each page of chunk"));
+ TUint8* chunkBase = aChunk->Base();
+
+ TUint8 chunkVal = 0;
+ for (TInt i = 0; i < aChunk->Size(); i += gPageSize)
+ {
+ chunkVal = * (chunkBase + i);
+ }
+
+ // only needed to remove compiler warning on unused variable
+ if (chunkVal)
+ chunkVal = 0;
+
+ return;
+ }
+
+void WriteChunk(RChunk * aChunk, TUint8 aValue = 0)
+ {
+ static TUint8 lastWriteValue = 1;
+ TESTNEXT(_L("Writing to each page of chunk"));
+ TUint8* chunkBase = aChunk->Base();
+
+ lastWriteValue = (TUint8)(aValue == 0 ? lastWriteValue + 1 : aValue);
+ for (TInt i = 0; i < aChunk->Size(); i += gPageSize)
+ {
+ * (chunkBase + i) = lastWriteValue;
+ }
+
+ return;
+ }
+
+void ParseCommandLine ()
+ {
+ TBuf<64> c;
+
+ User::CommandLine(c);
+ c.LowerCase();
+
+ if (c != KNullDesC)
+ {
+ TLex lex(c);
+ TPtrC token;
+
+ while (token.Set(lex.NextToken()), token != KNullDesC)
+ {
+ if (token.Mid(0) == _L("quiet"))
+ {
+ gQuiet = ETrue;
+ continue;
+ }
+
+ if (token.Mid(0) == _L("verbose"))
+ {
+ gQuiet = EFalse;
+ continue;
+ }
+
+ if (token.Left(5) == _L("chunk"))
+ {
+ TInt equalPos;
+ equalPos = token.Locate('=');
+ if (equalPos > 0 && (equalPos+1) < token.Length())
+ {
+ TLex lexNum(token.Mid(equalPos+1));
+ lexNum.Val(gChunkSize,EDecimal);
+ }
+ continue;
+ }
+
+ if (token.Left(3) == _L("low"))
+ {
+ TInt equalPos;
+ equalPos = token.Locate('=');
+ if (equalPos > 0 && (equalPos+1) < token.Length())
+ {
+ TLex lexNum(token.Mid(equalPos+1));
+ lexNum.Val(gMin,EDecimal);
+ }
+ continue;
+ }
+
+ if (token.Left(5) == _L("high"))
+ {
+ TInt equalPos;
+ equalPos = token.Locate('=');
+ if (equalPos > 0 && (equalPos+1) < token.Length())
+ {
+ TLex lexNum(token.Mid(equalPos+1));
+ lexNum.Val(gMax,EDecimal);
+ }
+ continue;
+ }
+
+ if (token.Left(6) == _L("period"))
+ {
+ TInt equalPos;
+ equalPos = token.Locate('=');
+ if (equalPos > 0 && (equalPos+1) < token.Length())
+ {
+ TLex lexNum(token.Mid(equalPos+1));
+ lexNum.Val(gPeriod,EDecimal);
+ }
+ continue;
+ }
+
+ if (token.Left(3) == _L("mem"))
+ {
+ TInt equalPos;
+ equalPos = token.Locate('=');
+ if (equalPos > 0 && (equalPos+1) < token.Length())
+ {
+ TLex lexNum(token.Mid(equalPos+1));
+ lexNum.Val(gMemScheme,EDecimal);
+ }
+ continue;
+ }
+
+ }
+ }
+ }
+
+enum TimerActions
+ {
+ ENoaction = 0,
+ EFlush = 1,
+ EFlushQuiet = 2,
+ EMemScheme1 = 1 << 4,
+ EMemScheme2 = 2 << 4,
+ EMemScheme3 = 3 << 4,
+ EMemScheme4 = 4 << 4,
+ };
+
+// CActive class to monitor KeyStrokes from User
+class CActiveConsole : public CActive
+ {
+public:
+ CActiveConsole();
+ ~CActiveConsole();
+ void GetCharacter();
+ static TInt Callback(TAny* aCtrl);
+
+private:
+ CPeriodic* iTimer;
+ TChar iCmdGetValue;
+ TBool iGetHexValue;
+ TBool iPrompt;
+ TChar iLastChar;
+ TUint iValue;
+ TUint16 iActions;
+ TUint32 iPeriod;
+
+ // Defined as pure virtual by CActive;
+ // implementation provided by this class.
+ virtual void DoCancel();
+ // Defined as pure virtual by CActive;
+ // implementation provided by this class,
+ virtual void RunL();
+ void ProcessKeyPressL(TChar aChar);
+ void ProcessValue();
+ };
+
+// Class CActiveConsole
+CActiveConsole::CActiveConsole()
+ : CActive(EPriorityHigh)
+ {
+ CActiveScheduler::Add(this);
+
+ iTimer = CPeriodic::NewL(EPriorityNormal);
+ iActions = ENoaction;
+ iPrompt = ETrue;
+ iPeriod = 0;
+ if (gPeriod > 0)
+ {
+ if (gMemScheme > 0)
+ {
+ iActions = (TUint16)(gMemScheme << 4);
+ }
+ else
+ {
+ iActions = (TUint16)(gPeriod < KFlushQuietLimit ? EFlushQuiet : EFlush);
+ }
+ iPeriod = gPeriod;
+ iTimer->Start(0,gPeriod,TCallBack(Callback,this));
+ }
+ }
+
+CActiveConsole::~CActiveConsole()
+ {
+ iTimer->Cancel();
+ delete iTimer;
+
+ Cancel();
+ }
+
+// Callback function for timer expiry
+TInt CActiveConsole::Callback(TAny* aControl)
+ {
+ switch (((CActiveConsole*)aControl)->iActions & 0x0F)
+ {
+ case ENoaction :
+ break;
+
+ case EFlush :
+ PRINT(_L("Flush\n"));
+ // drop through to quiet
+
+ case EFlushQuiet :
+ test_KErrNone(DPTest::FlushCache());
+ break;
+
+ default :
+ break;
+ }
+
+ switch (((CActiveConsole*)aControl)->iActions & 0xF0)
+ {
+ TUint i;
+ case EMemScheme1 :
+ for (i = 0; i < gNextChunk; i++)
+ ReadChunk (&gChunk[i]);
+ break;
+
+ case EMemScheme2 :
+ for (i = 0; i < gNextChunk; i++)
+ WriteChunk (&gChunk[i]);
+ break;
+
+ default :
+ break;
+ }
+
+ return KErrNone;
+ }
+
+void CActiveConsole::GetCharacter()
+ {
+ if (iPrompt)
+ {
+ PRINT(_L("***Command (F,I,Q,V,?,Rn,Wn,Mn,C=nnnnn,H=nnnn,L=nnnn,P=nnnn) or Esc to exit ***\n"));
+ iPrompt = EFalse;
+ }
+ test.Console()->Read(iStatus);
+ SetActive();
+ }
+
+void CActiveConsole::DoCancel()
+ {
+ PRINT(_L("CActiveConsole::DoCancel\n"));
+ test.Console()->ReadCancel();
+ }
+
+void CActiveConsole::ProcessKeyPressL(TChar aChar)
+ {
+ if (aChar == EKeyEscape)
+ {
+ PRINT(_L("CActiveConsole: ESC key pressed -> stopping active scheduler...\n"));
+ CActiveScheduler::Stop();
+ return;
+ }
+ aChar.UpperCase();
+ if (iCmdGetValue != 0 && aChar == '\r')
+ {
+ if (iLastChar == 'K')
+ {
+ iValue *= iGetHexValue ? 0x400 : 1000;
+ }
+ if (iLastChar == 'M')
+ {
+ iValue *= iGetHexValue ? 0x10000 : 1000000;
+ }
+ PRINT1(_L("CActiveConsole: Value %d\n"),iValue);
+ ProcessValue();
+ }
+ if (iCmdGetValue != 0 )
+ {
+ if (iGetHexValue)
+ {
+ if (aChar.IsDigit())
+ {
+ iValue = iValue * 16 + aChar.GetNumericValue();
+ }
+ else
+ {
+ if (aChar.IsHexDigit())
+ {
+ iValue = iValue * 16 + (TUint)aChar - 'A' + 10;
+ }
+ else
+ {
+ if (aChar != 'K' && aChar != 'M')
+ {
+ PRINT(_L("Illegal hexadecimal character - Enter command\n"));
+ iCmdGetValue = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (aChar.IsDigit())
+ {
+ iValue = iValue * 10 + aChar.GetNumericValue();
+ }
+ else
+ {
+ if ((aChar == 'X') && (iLastChar == '0') && (iValue == 0))
+ iGetHexValue = ETrue;
+ else
+ {
+ if (aChar != 'K' && aChar != 'M')
+ {
+ test.Printf(_L("Illegal decimal character - Enter command\n"));
+ iCmdGetValue = 0;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ switch (aChar)
+ {
+ case 'F' :
+ TESTNEXT(_L("Flushing Cache"));
+ test_KErrNone(DPTest::FlushCache());
+ ShowMemoryUse();
+ iPrompt = ETrue;
+ break;
+
+ case 'I' :
+ CacheSize(0,0);
+ ShowMemoryUse();
+ iPrompt = ETrue;
+ break;
+
+ case 'Q' :
+ gQuiet = ETrue;
+ iPrompt = ETrue;
+ break;
+
+ case 'V' :
+ gQuiet = EFalse;
+ iPrompt = ETrue;
+ break;
+
+ case '?' :
+ ShowHelp();
+ break;
+
+ case '=' :
+ iCmdGetValue = iLastChar;
+ iGetHexValue = EFalse;
+ iValue = 0;
+ break;
+
+ default :
+ if (aChar.IsDigit())
+ {
+ if (iLastChar == 'R')
+ {
+ if (aChar.GetNumericValue() < (TInt)gNextChunk)
+ {
+ ReadChunk (&gChunk[aChar.GetNumericValue()]);
+ }
+ else
+ {
+ for (TUint i = 0; i < gNextChunk; i++)
+ ReadChunk (&gChunk[i]);
+ }
+ iPrompt = ETrue;
+ }
+ if (iLastChar == 'W')
+ {
+ if (aChar.GetNumericValue() < (TInt)gNextChunk)
+ {
+ WriteChunk (&gChunk[aChar.GetNumericValue()]);
+ }
+ else
+ {
+ for (TUint i = 0; i < gNextChunk; i++)
+ WriteChunk (&gChunk[i]);
+ }
+ iPrompt = ETrue;
+ }
+ if (iLastChar == 'M')
+ {
+ if (aChar.GetNumericValue() == 0)
+ {
+ iActions = (TUint16)(iPeriod < KFlushQuietLimit ? EFlushQuiet : EFlush);
+ }
+ else
+ {
+ iActions = (TUint16)(aChar.GetNumericValue() << 4);
+ }
+ iPrompt = ETrue;
+ }
+ }
+ break;
+ }
+ }
+ iLastChar = aChar;
+ GetCharacter();
+ return;
+ }
+
+void CActiveConsole::ProcessValue()
+ {
+ switch (iCmdGetValue)
+ {
+ case 'C' :
+ if (iValue > 0 && gNextChunk < MAX_CHUNKS)
+ {
+ CreateChunk (&gChunk[gNextChunk], iValue);
+ ReadChunk (&gChunk[gNextChunk]);
+ ShowMemoryUse();
+ gNextChunk++;
+ }
+ break;
+
+ case 'H' :
+ CacheSize (0,iValue);
+ break;
+
+ case 'L' :
+ CacheSize (iValue,0);
+ break;
+
+ case 'P' :
+ iPeriod = iValue;
+ iActions = (TUint16)(iValue < KFlushQuietLimit ? EFlushQuiet : EFlush);
+ iTimer->Cancel();
+ if (iValue > 0)
+ {
+ iTimer->Start(0,iValue,TCallBack(Callback,this));
+ }
+ break;
+
+ default :
+ break;
+ }
+ iCmdGetValue = 0;
+ iPrompt = ETrue;
+ }
+
+void CActiveConsole::RunL()
+ {
+ ProcessKeyPressL(static_cast<TChar>(test.Console()->KeyCode()));
+ }
+
+TInt E32Main()
+ {
+ test.Title();
+ test.Start(_L("Writable Data Paging Soak Test"));
+
+ ParseCommandLine();
+
+ if (DPTest::Attributes() & DPTest::ERomPaging)
+ test.Printf(_L("Rom paging supported\n"));
+ if (DPTest::Attributes() & DPTest::ECodePaging)
+ test.Printf(_L("Code paging supported\n"));
+ if (DPTest::Attributes() & DPTest::EDataPaging)
+ test.Printf(_L("Data paging supported\n"));
+
+ TInt totalRamSize;
+ HAL::Get(HAL::EMemoryRAM,totalRamSize);
+ HAL::Get(HAL::EMemoryPageSize,gPageSize);
+ test.Printf(_L("Total RAM size 0x%08X bytes"),totalRamSize);
+ test.Printf(_L(" Swap size 0x%08X bytes"),SwapSize());
+ test.Printf(_L(" Page size 0x%08X bytes\n"),gPageSize);
+ CacheSize(gMin,gMax);
+
+ if ((DPTest::Attributes() & DPTest::EDataPaging) == 0)
+ {
+ test.Printf(_L("Writable Demand Paging not supported\n"));
+ test.End();
+ return 0;
+ }
+
+ ShowMemoryUse();
+
+ //User::SetDebugMask(0x00000008); //KMMU
+ //User::SetDebugMask(0x00000080); //KEXEC
+ //User::SetDebugMask(0x90000000); //KPANIC KMMU2
+ //User::SetDebugMask(0x40000000, 1); //KPAGING
+
+ if (gChunkSize)
+ {
+ CreateChunk (&gChunk[gNextChunk], gChunkSize);
+ ReadChunk (&gChunk[gNextChunk]);
+ ShowMemoryUse();
+ gNextChunk++;
+ }
+
+ CActiveScheduler* myScheduler = new (ELeave) CActiveScheduler();
+ CActiveScheduler::Install(myScheduler);
+
+ CActiveConsole* myActiveConsole = new CActiveConsole();
+ myActiveConsole->GetCharacter();
+
+ CActiveScheduler::Start();
+
+ test.End();
+
+ return 0;
+ }