kerneltest/e32test/realtime/t_lat2.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

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