kerneltest/e32test/misc/cpumeter.cpp
changeset 9 96e5fb8b040d
child 43 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/misc/cpumeter.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -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;
+	}
+