kerneltest/e32test/realtime/t_lat2.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/realtime/t_lat2.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,381 @@
+// Copyright (c) 1999-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\realtime\t_lat2.cpp
+// 
+//
+
+#include <e32test.h>
+#include <e32svr.h>
+#include <e32property.h>
+#include <e32atomics.h>
+#include "runtests.h"
+#include "d_latncy.h"
+
+_LIT(KLatencyLddFileName,"D_LATNCY");
+_LIT(KThreadName,"LatencyThreadU");
+
+RTest test(_L("Latency"));
+RThread Main;
+TUint TicksPerMs;
+
+struct SFullLatencyResults : public SLatencyResults
+	{
+	TUint iKernRetAddr;
+	TUint iUserRetAddr;
+	TInt64 iCount;
+	TInt64 iSumIntTicks;
+	TInt64 iSumKernTicks;
+	TInt64 iSumUserTicks;
+	TUint iIntCpsr;
+	TUint iKernCpsr;
+	TUint iKernR14;
+	TUint iUserCpsr;
+	TUint iUserR14;
+
+	void Update(SLatencyResults& aResults);
+	};
+
+SFullLatencyResults Latencies;
+volatile TUint32 UpdateCount=0;
+
+TUint TimerToMicroseconds(TUint aTimerValue)
+	{
+	return (aTimerValue*1000+TicksPerMs-1)/TicksPerMs;
+	}
+
+void SFullLatencyResults::Update(SLatencyResults& aResults)
+	{
+	__e32_atomic_add_acq32(&UpdateCount, 1);
+
+	// memory barrier
+
+	if (aResults.iIntTicks>iIntTicks)
+		{
+		iIntTicks=aResults.iIntTicks;
+		iIntRetAddr=aResults.iIntRetAddr;
+#ifdef __CAPTURE_EXTRAS
+		iIntCpsr=aResults.iIntSpsr;
+		iIntR14=aResults.iIntR14;
+#endif
+		}
+	if (aResults.iKernThreadTicks>iKernThreadTicks)
+		{
+		iKernThreadTicks=aResults.iKernThreadTicks;
+		iKernRetAddr=aResults.iIntRetAddr;
+#ifdef __CAPTURE_EXTRAS
+		iKernCpsr=aResults.iIntSpsr;
+		iKernR14=aResults.iIntR14;
+#endif
+		}
+	if (aResults.iUserThreadTicks>iUserThreadTicks)
+		{
+		iUserThreadTicks=aResults.iUserThreadTicks;
+		iUserRetAddr=aResults.iIntRetAddr;
+#ifdef __CAPTURE_EXTRAS
+		iUserCpsr=aResults.iIntSpsr;
+		iUserR14=aResults.iIntR14;
+#endif
+		}
+	iSumIntTicks+=aResults.iIntTicks;
+	iSumKernTicks+=aResults.iKernThreadTicks;
+	iSumUserTicks+=aResults.iUserThreadTicks;
+	++iCount;
+
+	// memory barrier
+
+	__e32_atomic_add_rel32(&UpdateCount, 1);
+	}
+
+TInt LatencyThread(TAny* aStatus)
+	{
+	TRequestStatus* pS=(TRequestStatus*)aStatus;
+	RLatency l;
+	TInt r=l.Open();
+	if (r!=KErrNone)
+		return r;
+	TicksPerMs=l.TicksPerMs();
+	Mem::FillZ(&Latencies,sizeof(Latencies));
+	Main.RequestComplete(pS,0);
+	SLatencyResults results;
+
+	l.Start();
+	FOREVER
+		{
+		User::WaitForAnyRequest();
+		l.GetResults(results);
+		Latencies.Update(results);
+		}
+	return r;
+	}
+
+void GetLatencies(SFullLatencyResults& aResults)
+	{
+	FOREVER
+		{
+		TUint32 u1 = UpdateCount;
+		__e32_memory_barrier();
+		aResults=Latencies;
+		__e32_memory_barrier();
+		TUint32 u2 = UpdateCount;
+		if (u1==u2 && !(u1&1))	// no good if it changed partway through or was changing when we started
+			break;
+		}
+	}
+
+_LIT(KPrefixRuntests, "RUNTESTS: RT");
+void DisplayMaxValues(const TDesC& aPrefix)
+	{
+	SFullLatencyResults v;
+	GetLatencies(v);
+	TUint i=TimerToMicroseconds(v.iIntTicks);
+	TUint k=TimerToMicroseconds(v.iKernThreadTicks);
+	TUint u=TimerToMicroseconds(v.iUserThreadTicks);
+	TUint ia=v.iIntRetAddr;
+	TUint ka=v.iKernRetAddr;
+	TUint ua=v.iUserRetAddr;
+	test.Printf(_L("%SMAX: Int %4d %08x Kern %4d %08x User %4d %08x\n"),&aPrefix,i,ia,k,ka,u,ua);
+	}
+
+void DisplayAvgValues(const TDesC& aPrefix)
+	{
+	SFullLatencyResults v;
+	GetLatencies(v);
+	TUint i=TimerToMicroseconds(I64LOW(v.iSumIntTicks/v.iCount));
+	TUint k=TimerToMicroseconds(I64LOW(v.iSumKernTicks/v.iCount));
+	TUint u=TimerToMicroseconds(I64LOW(v.iSumUserTicks/v.iCount));
+	test.Printf(_L("%SAVG: Int %4d Kern %4d User %4d Count %Ld\n"),&aPrefix,i,k,u,v.iCount);
+	}
+
+#ifdef __CAPTURE_EXTRAS
+void DisplayExtras(const TDesC& aPrefix)
+	{
+	SFullLatencyResults v;
+	GetLatencies(v);
+	test.Printf(_L("%SInt : Cpsr %08x R14 %08x\n"),&aPrefix,v.iIntCpsr,v.iIntR14);
+	test.Printf(_L("%SKern: Cpsr %08x R14 %08x\n"),&aPrefix,v.iKernCpsr,v.iKernR14);
+	test.Printf(_L("%SUser: Cpsr %08x R14 %08x\n"),&aPrefix,v.iUserCpsr,v.iUserR14);
+	}
+#endif
+
+void ClearMaxValues()
+	{
+	Mem::FillZ(&Latencies,6*sizeof(TUint));
+	}
+
+void ClearAvgValues()
+	{
+	Mem::FillZ(&Latencies.iCount,4*sizeof(TInt64));
+	}
+
+_LIT_SECURITY_POLICY_PASS(KPersistencePropReadPolicy);
+_LIT_SECURITY_POLICY_PASS(KPersistencePropWritePolicy);
+void AnnouncePersistence()
+	{
+	TInt r = RProperty::Define(KRuntestsIntentionalPersistenceKey, RProperty::EInt, KPersistencePropReadPolicy, KPersistencePropWritePolicy);
+	test(r==KErrNone || r==KErrAlreadyExists);
+	r = RProperty::Set(RProcess().SecureId(), KRuntestsIntentionalPersistenceKey, KRuntestsIntentionalPersistenceValue);
+	test(r==KErrNone);
+	}
+
+class CConsoleReader : public CActive
+	{
+public:
+	CConsoleReader();
+	static void New();
+	void Start();
+	virtual void RunL();
+	virtual void DoCancel();
+public:
+	CConsoleBase* iConsole;
+	};
+
+CConsoleReader::CConsoleReader()
+	:	CActive(0)
+	{
+	}
+
+void CConsoleReader::RunL()
+	{
+	TKeyCode k = iConsole->KeyCode();
+	switch(k)
+		{
+		case '1':
+			test.Printf(_L("Clearing Maximum Values\n"));
+			ClearMaxValues();
+			break;
+		case '2':
+			DisplayMaxValues(KNullDesC);
+			break;
+		case '3':
+			test.Printf(_L("Clearing Average Values\n"));
+			ClearAvgValues();
+			break;
+		case '4':
+			DisplayAvgValues(KNullDesC);
+			break;
+#ifdef __CAPTURE_EXTRAS
+		case '5':
+			DisplayExtras(KNullDesC);
+			break;
+#endif
+		case 'x':
+		case 'X':
+			CActiveScheduler::Stop();
+			return;
+		default:
+			break;
+		}
+	Start();
+	}
+
+void CConsoleReader::DoCancel()
+	{
+	iConsole->ReadCancel();
+	}
+
+void CConsoleReader::New()
+	{
+	CConsoleReader* crdr = new CConsoleReader;
+	test(crdr != NULL);
+	crdr->iConsole = test.Console();
+	CActiveScheduler::Add(crdr);
+	crdr->Start();
+	}
+
+void CConsoleReader::Start()
+	{
+	iConsole->Read(iStatus);
+	SetActive();
+	}
+
+class CPubSubWatcher : public CActive
+	{
+public:
+	CPubSubWatcher();
+	static void New();
+	void Start();
+	virtual ~CPubSubWatcher();
+	virtual void RunL();
+	virtual void DoCancel();
+public:
+	RProperty iProperty;
+	};
+
+CPubSubWatcher::CPubSubWatcher()
+	:	CActive(0)
+	{
+	}
+
+void CPubSubWatcher::RunL()
+	{
+	Start();
+	DisplayMaxValues(KPrefixRuntests);
+	DisplayAvgValues(KPrefixRuntests);
+	}
+
+void CPubSubWatcher::DoCancel()
+	{
+	iProperty.Cancel();
+	}
+
+void CPubSubWatcher::New()
+	{
+	CPubSubWatcher* psw = new CPubSubWatcher;
+	test(psw != NULL);
+	TInt r = psw->iProperty.Attach(KRuntestsCategory, KRuntestsCurrentTestKey, EOwnerThread);
+	test(r==KErrNone);
+	CActiveScheduler::Add(psw);
+	psw->Start();
+	}
+
+void CPubSubWatcher::Start()
+	{
+	iProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+CPubSubWatcher::~CPubSubWatcher()
+	{
+	iProperty.Close();
+	}
+
+GLDEF_C TInt E32Main()
+	{
+#ifdef _DEBUG
+	// Don't run automatically on debug builds
+	TUint32 creator_sid = User::CreatorSecureId();
+	if (creator_sid == TUint32(KRuntestsCategoryValue))
+		return KErrNone;
+#endif
+	// disable anything which will interfere, e.g. plat sec diagnostics
+	User::SetDebugMask(UserSvr::DebugMask(2)|4, 2);
+
+	test.Title();
+	
+	test.Printf(_L("*** Please note ***\n"));
+	test.Printf(_L("\n"));
+	test.Printf(_L("t_lat2 runs in the backgroud to measure latency while other tests are\n"));
+	test.Printf(_L("running.  It should not be run as a standalone test, only as part of a\n"));
+	test.Printf(_L("test run coordinated by runtests.  If run on its owm, it will simply wait\n"));
+	test.Printf(_L("forever.\n"));
+	test.Printf(_L("\n"));
+	
+	test.Start(_L("Load LDD"));
+	TInt r=User::LoadLogicalDevice(KLatencyLddFileName);
+	test(r==KErrNone || r==KErrAlreadyExists);
+
+	test.Next(_L("Duplicate handle"));
+	r=Main.Duplicate(RThread());
+	test(r==KErrNone);
+
+	test.Next(_L("Create thread"));
+	RThread t;
+	TRequestStatus sx;
+	TRequestStatus sc;
+	r=t.Create(KThreadName,LatencyThread,0x1000,NULL,&sc);
+	test(r==KErrNone);
+	t.Logon(sx);
+	t.Resume();
+	User::WaitForRequest(sx,sc);
+	if (sx!=KRequestPending)
+		{
+		if (t.ExitType()==EExitKill && t.ExitReason()==KErrAlreadyExists)
+			{
+			test.Printf(_L("T_LAT2 already running.\n"));
+			test.End();
+			return 0;
+			}
+		test.Printf(_L("Initialisation failed, error %d\n"),sx.Int());
+		test(0);
+		}
+	test(sc==KErrNone);
+
+	CTrapCleanup* tcln = CTrapCleanup::New();
+	test(tcln != NULL);
+	CActiveScheduler* as = new CActiveScheduler;
+	test(as != NULL);
+	CActiveScheduler::Install(as);
+	CConsoleReader::New();
+	CPubSubWatcher::New();
+	AnnouncePersistence();
+	RProcess::Rendezvous(KErrNone);
+
+	CActiveScheduler::Start();
+
+	// latency test over
+	User::SetDebugMask(UserSvr::DebugMask(2)&~4, 2);
+
+	test.End();
+	return 0;
+	}