// 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;
}