--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/misc/cpumeter.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,273 @@
+// Copyright (c) 1996-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\misc\cpumeter.cpp
+//
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <e32hal.h>
+#include <e32svr.h>
+#include "u32std.h"
+
+RTest test(_L("CPU METER"));
+
+TBool CpuTimeSupported()
+ {
+ TTimeIntervalMicroSeconds time;
+ TInt err = RThread().GetCpuTime(time);
+ test(err == KErrNone || err == KErrNotSupported);
+ return err == KErrNone;
+ }
+
+TInt NumberOfCpus()
+ {
+ TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
+ test(r>0);
+ return r;
+ }
+
+class CCpuMeter : public CBase
+ {
+public:
+ CCpuMeter();
+ ~CCpuMeter();
+ static CCpuMeter* New();
+ TInt Construct();
+ void Measure();
+ void Display(TInt aInterval);
+public:
+ TInt iNumCpus;
+ TInt iNextMeas;
+ RThread* iNullThreads;
+ TTimeIntervalMicroSeconds* iMeas[2];
+ TInt* iDelta;
+ };
+
+CCpuMeter::CCpuMeter()
+ {
+ }
+
+CCpuMeter::~CCpuMeter()
+ {
+ TInt i;
+ if (iNullThreads)
+ {
+ for (i=0; i<iNumCpus; ++i)
+ iNullThreads[i].Close();
+ User::Free(iNullThreads);
+ }
+ User::Free(iMeas[0]);
+ User::Free(iMeas[1]);
+ User::Free(iDelta);
+ }
+
+TInt CCpuMeter::Construct()
+ {
+ iNumCpus = NumberOfCpus();
+ iNullThreads = (RThread*)User::AllocZ(iNumCpus*sizeof(RThread));
+ iDelta = (TInt*)User::AllocZ(iNumCpus*sizeof(TInt));
+ iMeas[0] = (TTimeIntervalMicroSeconds*)User::AllocZ(iNumCpus*sizeof(TTimeIntervalMicroSeconds));
+ iMeas[1] = (TTimeIntervalMicroSeconds*)User::AllocZ(iNumCpus*sizeof(TTimeIntervalMicroSeconds));
+ if (!iNullThreads || !iDelta || !iMeas[0] || !iMeas[1])
+ return KErrNoMemory;
+ TFullName kname;
+ _LIT(KLitKernelName, "ekern.exe*");
+ _LIT(KLitNull, "::Null");
+ TFindProcess fp(KLitKernelName);
+ test_KErrNone(fp.Next(kname));
+ test.Printf(_L("Found kernel process: %S\n"), &kname);
+ kname.Append(KLitNull);
+ TInt i;
+ for (i=0; i<iNumCpus; ++i)
+ {
+ TFullName tname(kname);
+ TFullName tname2;
+ if (i>0)
+ tname.AppendNum(i);
+ TFindThread ft(tname);
+ test_KErrNone(ft.Next(tname2));
+ TInt r = iNullThreads[i].Open(ft);
+ test_KErrNone(r);
+ iNullThreads[i].FullName(tname2);
+ test.Printf(_L("Found and opened %S\n"), &tname2);
+ }
+ for (i=0; i<iNumCpus; ++i)
+ iNullThreads[i].GetCpuTime(iMeas[0][i]);
+ iNextMeas = 1;
+ return KErrNone;
+ }
+
+CCpuMeter* CCpuMeter::New()
+ {
+ CCpuMeter* p = new CCpuMeter;
+ if (!p)
+ return 0;
+ TInt r = p->Construct();
+ if (r!=KErrNone)
+ {
+ delete p;
+ return 0;
+ }
+ return p;
+ }
+
+void CCpuMeter::Measure()
+ {
+ TInt i;
+ for (i=0; i<iNumCpus; ++i)
+ iNullThreads[i].GetCpuTime(iMeas[iNextMeas][i]);
+ TInt prev = 1 - iNextMeas;
+ for (i=0; i<iNumCpus; ++i)
+ iDelta[i] = TInt(iMeas[iNextMeas][i].Int64() - iMeas[prev][i].Int64());
+ iNextMeas = prev;
+ }
+
+void CCpuMeter::Display(TInt aInterval)
+ {
+ TBuf<80> buf;
+ TInt i;
+ for (i=0; i<iNumCpus; ++i)
+ {
+ TInt dv = (1000*(aInterval - iDelta[i]))/aInterval;
+ if (dv<0)
+ dv=0;
+ if (dv>1000)
+ dv=1000;
+ buf.AppendFormat(_L(" %4d"),dv);
+ }
+ buf.Append(TChar('\n'));
+ test.Printf(buf);
+ }
+
+void UseKernelCpuTime()
+ {
+ test.Start(_L("Create CCpuMeter"));
+ CCpuMeter* m = CCpuMeter::New();
+ test_NotNull(m);
+ TInt iv = 1000500; // on average 1000.5 ms
+ TRequestStatus s;
+ CConsoleBase* console = test.Console();
+ console->Read(s);
+ FOREVER
+ {
+ User::AfterHighRes(1000000);
+ m->Measure();
+ m->Display(iv);
+ while (s!=KRequestPending)
+ {
+ User::WaitForRequest(s);
+ TKeyCode k = console->KeyCode();
+ if (k == EKeyEscape)
+ {
+ delete m;
+ return;
+ }
+ console->Read(s);
+ }
+ }
+ }
+
+
+
+TUint32 NopCount=0;
+TUint MaxCycles;
+_LIT(KLitThreadName,"IdleThread");
+extern TInt CountNops(TAny*);
+
+void MeasureByNOPs()
+ {
+ test.Start(_L("Create thread"));
+ RThread t;
+ TInt r=t.Create(KLitThreadName,CountNops,0x1000,NULL,NULL);
+ test(r==KErrNone);
+ t.SetPriority(EPriorityAbsoluteVeryLow);
+ t.Resume();
+
+ test.Next(_L("Get processor clock frequency"));
+ TMachineInfoV2Buf buf;
+ TMachineInfoV2& info=buf();
+ r=UserHal::MachineInfo(buf);
+ test(r==KErrNone);
+ MaxCycles=info.iProcessorClockInKHz*1000;
+ test.Printf(_L("Clock frequency %dHz\n"),MaxCycles);
+ TRequestStatus s;
+ CConsoleBase* console=test.Console();
+ console->Read(s);
+#ifdef __WINS__
+ TInt timerperiod = 5;
+ UserSvr::HalFunction(EHalGroupEmulator,EEmulatorHalIntProperty,(TAny*)"TimerResolution",&timerperiod);
+#endif
+
+ FOREVER
+ {
+ TUint32 init_count=NopCount;
+ TUint32 init_ms=User::NTickCount();
+ User::After(1000000);
+ TUint32 final_count=NopCount;
+ TUint32 final_ms=User::NTickCount();
+ TUint32 cycles=final_count-init_count;
+ TUint32 ms=final_ms-init_ms;
+#ifdef __WINS__
+ ms*=timerperiod;
+#endif
+ while (s!=KRequestPending)
+ {
+ User::WaitForRequest(s);
+ TKeyCode k=console->KeyCode();
+ if (k==EKeyTab)
+ {
+ // calibrate
+ TInt64 inst64 = MAKE_TINT64(0, cycles);
+ inst64*=1000;
+ inst64/=MAKE_TINT64(0,ms);
+ MaxCycles=I64LOW(inst64);
+ test.Printf(_L("NOPs per second %u\n"),MaxCycles);
+ }
+ else if (k==EKeyEscape)
+ return;
+ console->Read(s);
+ }
+ TInt64 used64=MAKE_TINT64(0, MaxCycles);
+
+ used64-=MAKE_TINT64(0,cycles);
+ used64*=1000000;
+ used64/=MAKE_TINT64(0,ms);
+ used64/=MAKE_TINT64(0, MaxCycles);
+ test.Printf(_L("%4d\n"),I64INT(used64));
+ }
+ }
+
+
+GLDEF_C TInt E32Main()
+ {
+ test.SetLogged(EFalse);
+ test.Title();
+ RThread().SetPriority(EPriorityAbsoluteHigh);
+
+ if (CpuTimeSupported())
+ {
+ UseKernelCpuTime();
+ }
+ if (NumberOfCpus()>1)
+ {
+ test.Printf(_L("Needs RThread::GetCpuTime() on SMP systems\n"));
+ }
+ else
+ MeasureByNOPs();
+
+ return 0;
+ }
+