os/kernelhwsrv/kerneltest/e32test/benchmark/bm_ldd.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/benchmark/bm_ldd.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,704 @@
     1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "k32bm.h"
    1.20 +
    1.21 +const TUint8 KMutexOrder = 0xf0;
    1.22 +
    1.23 +class DBMLDevice : public DLogicalDevice
    1.24 +	{
    1.25 +public:
    1.26 +	DBMLDevice();
    1.27 +	virtual TInt Install();
    1.28 +	virtual void GetCaps(TDes8& aDes) const;
    1.29 +	virtual TInt Create(DLogicalChannelBase*& aChannel);
    1.30 +	};
    1.31 +
    1.32 +class DBMLChannel : public DLogicalChannelBase, public MBMIsr, public MBMInterruptLatencyIsr
    1.33 +	{
    1.34 +public:
    1.35 +	DBMLChannel();
    1.36 +	~DBMLChannel();
    1.37 +
    1.38 +	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
    1.39 +	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
    1.40 +
    1.41 +	DBMPChannel* PChannel() { return (DBMPChannel*) iPdd; }
    1.42 +
    1.43 +private:
    1.44 +	static const TInt	KBMDfcQThreadPriority;	
    1.45 +	static const TInt	KBMKernelThreadPriority;	
    1.46 +
    1.47 +	static void Dfc(TAny*);
    1.48 +
    1.49 +	virtual void Isr(TBMTicks now);
    1.50 +
    1.51 +	TInt (DBMLChannel::*iRequestInterrupt)();	// Measurement specific RBMChannel::RequestInterrupt() implmentation 
    1.52 +	TInt RequestInterrupt();					// Default iRequestInterrupt() implementation
    1.53 +
    1.54 +	TBMTicks (DBMLChannel::*iResult)();			// Measurement specific RBMChannel::Result() implmentation
    1.55 +	TBMTicks Result();							// Default iResult() implementation
    1.56 +
    1.57 +	TInt Start(RBMChannel::TMode);
    1.58 +
    1.59 +	TInt StartInterruptLatency();
    1.60 +	virtual void InterruptLatencyIsr(TBMTicks latency);
    1.61 +
    1.62 +	TInt StartKernelPreemptionLatency();
    1.63 +	static TInt KernelPreemptionLatencyThreadEntry(TAny* ptr);
    1.64 +	void KernelPreemptionLatencyThread();
    1.65 +
    1.66 +	TInt StartUserPreemptionLatency();
    1.67 +	TBMTicks UserPreemptionLatencyResult();		// iResult() implementation
    1.68 +
    1.69 +	TInt StartNTimerJitter();
    1.70 +	TInt RequestNTimerJitterInterrupt();		// iRequestInterrupt() implementation
    1.71 +	static void NTimerJitterCallBack(TAny*);
    1.72 +
    1.73 +	TInt StartTimerStampOverhead();
    1.74 +	TInt RequestTimerStampOverhead();			// iRequestInterrupt() implementation
    1.75 +
    1.76 +	TInt SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio);
    1.77 +
    1.78 +	DMutex*			iLock;	// Shall be acquired by anyone who access the object's writable state.
    1.79 +
    1.80 +	TBool			iStarted;					// ETrue when a particular sequence of measurements has been started
    1.81 +	TBool			iPendingInterruptRequest;	// ETrue when an interrupt has been requested
    1.82 +
    1.83 +	TDynamicDfcQue*	iDfcQ;
    1.84 +	TDfc			iDfc;
    1.85 +
    1.86 +	DThread*		iKernelThread;		// the kernel thread created by some benchmarks
    1.87 +	DThread*		iUserThread;		// the user-side thread
    1.88 +	DThread*		iInterruptThread;	// the thread signaled by DFC; if non-NULL either iKernelThread or iUserThread
    1.89 +
    1.90 +	NTimer			iNTimer;			// the timer used in "NTimer jitter" benchmark
    1.91 +	TBMTicks		iOneNTimerTick;		// number of high-resolution timer ticks in one NKern tick.
    1.92 +	TInt			iNTimerShotCount;	// used in "NTimer jitter" to distinguish between the first and the second shots 
    1.93 +
    1.94 +	TBMTicks		iTime;
    1.95 +	TBMTicks		iTimerPeriod;		// period of high-resolution timer in ticks
    1.96 +
    1.97 +	NFastSemaphore*	iKernelThreadExitSemaphore;
    1.98 +
    1.99 +	void Lock()
   1.100 +		{
   1.101 +		NKern::ThreadEnterCS();
   1.102 +		Kern::MutexWait(*iLock);
   1.103 +		}
   1.104 +	void Unlock()
   1.105 +		{
   1.106 +		Kern::MutexSignal(*iLock);
   1.107 +		NKern::ThreadLeaveCS();
   1.108 +		}
   1.109 +	
   1.110 +	TBMTicks Delta(TBMTicks aT0, TBMTicks aT1)
   1.111 +		{
   1.112 +		return (aT0 <= aT1) ? (aT1 - aT0) : iTimerPeriod - (aT0 - aT1);
   1.113 +		}
   1.114 +	};
   1.115 +
   1.116 +_LIT(KBMLChannelLit, "BMLChannel");
   1.117 +
   1.118 +const TInt	DBMLChannel::KBMDfcQThreadPriority = KBMLDDHighPriority;
   1.119 +const TInt	DBMLChannel::KBMKernelThreadPriority = KBMLDDMidPriority;
   1.120 +
   1.121 +
   1.122 +
   1.123 +DECLARE_STANDARD_LDD()
   1.124 +//
   1.125 +// Create a new device
   1.126 +//
   1.127 +	{
   1.128 +	__ASSERT_CRITICAL;
   1.129 +	return new DBMLDevice;
   1.130 +	}
   1.131 +
   1.132 +DBMLDevice::DBMLDevice()
   1.133 +//
   1.134 +// Constructor
   1.135 +//
   1.136 +	{
   1.137 +	//iUnitsMask=0;
   1.138 +	iVersion = TVersion(1,0,1);
   1.139 +	iParseMask = KDeviceAllowPhysicalDevice;
   1.140 +	}
   1.141 +
   1.142 +TInt DBMLDevice::Install()
   1.143 +//
   1.144 +// Install the device driver.
   1.145 +//
   1.146 +	{
   1.147 +	TInt r = SetName(&KBMLdName);
   1.148 +	return r;
   1.149 +	}
   1.150 +
   1.151 +void DBMLDevice::GetCaps(TDes8&) const
   1.152 +//
   1.153 +// Return the Comm capabilities.
   1.154 +//
   1.155 +	{
   1.156 +	}
   1.157 +
   1.158 +TInt DBMLDevice::Create(DLogicalChannelBase*& aChannel)
   1.159 +//
   1.160 +// Create a channel on the device.
   1.161 +//
   1.162 +	{
   1.163 +	__ASSERT_CRITICAL;
   1.164 +	aChannel = new DBMLChannel;
   1.165 +	return aChannel ? KErrNone : KErrNoMemory;
   1.166 +	}
   1.167 +
   1.168 +DBMLChannel::DBMLChannel() : 
   1.169 +		iDfc(0, this, 0, 0),
   1.170 +		iNTimer(NULL, this)
   1.171 +	{
   1.172 +	// iDfcQueue = NULL;
   1.173 +	// iStarted = EFalse;
   1.174 +	// iPendingInterruptRequest = EFalse;
   1.175 +	// iKernelThread = NULL;
   1.176 +	}
   1.177 +
   1.178 +TInt DBMLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer)
   1.179 +//
   1.180 +// Create the channel from the passed info.
   1.181 +//
   1.182 +	{
   1.183 +	__ASSERT_CRITICAL;
   1.184 +	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
   1.185 +		return KErrNotSupported;
   1.186 +	TInt r = Kern::MutexCreate(iLock, KBMLChannelLit, KMutexOrder);
   1.187 +	if (r != KErrNone)
   1.188 +		{
   1.189 +		return r;
   1.190 +		}
   1.191 +	iTimerPeriod = PChannel()->TimerPeriod();
   1.192 +		// Calculate the number of high-resolution timer ticks in one NKern tick
   1.193 +		// deviding the number of high-resolution timer ticks in one second by the
   1.194 +		// number of NKern ticks in one second.
   1.195 +		//
   1.196 +	iOneNTimerTick = PChannel()->TimerNsToTicks(BMSecondsToNs(1))/NKern::TimerTicks(1000);
   1.197 +	return KErrNone;
   1.198 +	}
   1.199 +
   1.200 +DBMLChannel::~DBMLChannel()
   1.201 +// Called on a channel close. Note that if the PDD channel create failed 
   1.202 +// then the DoCreate() call will not have been made so don't assume anything 
   1.203 +// about non-ctor initialisation of members.
   1.204 +	{
   1.205 +	if (iLock) 
   1.206 +		iLock->Close(0);
   1.207 +
   1.208 +	if (iPendingInterruptRequest)
   1.209 +		{
   1.210 +		PChannel()->CancelInterrupt();
   1.211 +		iDfc.Cancel();
   1.212 +		}
   1.213 +
   1.214 +	if (iDfcQ)
   1.215 +		{
   1.216 +		iDfcQ->Destroy();
   1.217 +		}
   1.218 +
   1.219 +	if (iKernelThread)
   1.220 +		{
   1.221 +		NFastSemaphore exitSemaphore;
   1.222 +		exitSemaphore.iOwningThread = NKern::CurrentThread();
   1.223 +		iKernelThreadExitSemaphore = &exitSemaphore;
   1.224 +		NKern::ThreadRequestSignal(&iKernelThread->iNThread);
   1.225 +		NKern::FSWait(&exitSemaphore);
   1.226 +		}
   1.227 +	}
   1.228 +
   1.229 +void DBMLChannel::Dfc(TAny* ptr)
   1.230 +	{	
   1.231 +	DBMLChannel* lCh = (DBMLChannel*) ptr;
   1.232 +	BM_ASSERT(lCh->iPendingInterruptRequest);
   1.233 +	BM_ASSERT(lCh->iInterruptThread);
   1.234 +	NKern::ThreadRequestSignal(&lCh->iInterruptThread->iNThread);
   1.235 +	lCh->iPendingInterruptRequest = EFalse;
   1.236 +	}
   1.237 +
   1.238 +//
   1.239 +// Default DBMLChannel::iRequestInterrupt implementation
   1.240 +//
   1.241 +TInt DBMLChannel::RequestInterrupt()
   1.242 +	{
   1.243 +	if (!iStarted)
   1.244 +		{
   1.245 +		return KErrNotReady;
   1.246 +		}
   1.247 +	if (iPendingInterruptRequest) 
   1.248 +		{
   1.249 +		return KErrInUse;
   1.250 +		}
   1.251 +	iPendingInterruptRequest = ETrue;
   1.252 +	PChannel()->RequestInterrupt();
   1.253 +	return KErrNone;
   1.254 +	}
   1.255 +
   1.256 +//
   1.257 +// Default DBMLChannel::iResult implementation
   1.258 +//
   1.259 +TBMTicks DBMLChannel::Result()
   1.260 +	{
   1.261 +	return iTime;
   1.262 +	}
   1.263 +
   1.264 +void DBMLChannel::Isr(TBMTicks aNow)
   1.265 +	{
   1.266 +	//
   1.267 +	// Store the ISR entry time and queue a DFC.
   1.268 +	//
   1.269 +	iTime = aNow;
   1.270 +	iDfc.Add();
   1.271 +	}
   1.272 +
   1.273 +//
   1.274 +// "INTERRUPT LATENCY"
   1.275 +// 
   1.276 +// SCENARIO:
   1.277 +//
   1.278 +//		A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
   1.279 +//		(RBMChannel::Result()).
   1.280 +//		When the interrupt occurs DBMLChannel::InterruptLatencyIsr() stores the interrupt latency 
   1.281 +//		provided by LDD, in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc())
   1.282 +//		which in its turn signals the user thread.
   1.283 +//
   1.284 +
   1.285 +TInt DBMLChannel::StartInterruptLatency()
   1.286 +	{
   1.287 +	if (iStarted)
   1.288 +		{
   1.289 +		return KErrInUse;
   1.290 +		}
   1.291 +	TInt r = PChannel()->BindInterrupt((MBMInterruptLatencyIsr*) this);
   1.292 +	if (r != KErrNone)
   1.293 +		{
   1.294 +		return r;
   1.295 +		}
   1.296 +		// Use the default iRequestInterrupt() implmentation
   1.297 +	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
   1.298 +		// Use the default iResult() implmentation
   1.299 +	iResult = &DBMLChannel::Result;
   1.300 +	iInterruptThread = &Kern::CurrentThread();
   1.301 +	iStarted = ETrue;
   1.302 +	return KErrNone;
   1.303 +	}
   1.304 +
   1.305 +void DBMLChannel::InterruptLatencyIsr(TBMTicks aLatency)
   1.306 +	{
   1.307 +	iTime = aLatency;
   1.308 +	iDfc.Add();
   1.309 +	}
   1.310 +
   1.311 +//
   1.312 +// "KERNEL THREAD PREEMPTION LATENCY"
   1.313 +// 
   1.314 +// SCENARIO:
   1.315 +//
   1.316 +//		A new kernel thread is created at the beginning of a sequence of measurements 
   1.317 +//		(DBMLChannel::StartKernelPreemptionLatency()). The kernel thread waits at Kern::WaitForAnyRequest()
   1.318 +//		(DBMLChannel::KernelPreemptionLatencyThread()).
   1.319 +//		The user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
   1.320 +//		(RBMChannel::Result()).
   1.321 +//		When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time, provided by LDD 
   1.322 +//		in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which, in its turn,
   1.323 +//		signals the kernel thread.
   1.324 +//		The kernel thread, when awaken, calculates the latency as the difference between the ISR entry time 
   1.325 +//		and the current time and finally signals the user thread.
   1.326 +//
   1.327 +
   1.328 +TInt DBMLChannel::StartKernelPreemptionLatency()
   1.329 +	{
   1.330 +	if (iStarted)
   1.331 +		{
   1.332 +		return KErrInUse;
   1.333 +		}
   1.334 +	TInt r = PChannel()->BindInterrupt((MBMIsr*) this);
   1.335 +	if (r != KErrNone)
   1.336 +		{
   1.337 +		return r;
   1.338 +		}
   1.339 +	{
   1.340 +	SThreadCreateInfo info;
   1.341 +	info.iType = EThreadSupervisor;
   1.342 +	info.iFunction = DBMLChannel::KernelPreemptionLatencyThreadEntry;
   1.343 +	info.iPtr = this;
   1.344 +	info.iSupervisorStack = NULL;
   1.345 +	info.iSupervisorStackSize = 0;
   1.346 +	info.iInitialThreadPriority = KBMKernelThreadPriority;
   1.347 +	info.iName.Set(KBMLChannelLit);
   1.348 +	info.iTotalSize = sizeof(info);
   1.349 +	r = Kern::ThreadCreate(info);
   1.350 +	if (r != KErrNone)
   1.351 +		{
   1.352 +		return r;
   1.353 +		}
   1.354 +	iKernelThread = (DThread*) info.iHandle;
   1.355 +	}
   1.356 +
   1.357 +	iUserThread = &Kern::CurrentThread();
   1.358 +		// Use the default iRequestInterrupt() implmentation
   1.359 +	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
   1.360 +		// Use the default iResult() implmentation
   1.361 +	iResult = &DBMLChannel::Result;
   1.362 +	iInterruptThread = iKernelThread;
   1.363 +	iStarted = ETrue;
   1.364 +
   1.365 +	Kern::ThreadResume(*iKernelThread);
   1.366 +
   1.367 +	return KErrNone;
   1.368 +	}
   1.369 +
   1.370 +TInt DBMLChannel::KernelPreemptionLatencyThreadEntry(TAny* ptr)
   1.371 +	{
   1.372 +	DBMLChannel* lCh = (DBMLChannel*) ptr;
   1.373 +	lCh->KernelPreemptionLatencyThread();
   1.374 +	BM_ASSERT(0);
   1.375 +	return 0;
   1.376 +	}
   1.377 +
   1.378 +void DBMLChannel::KernelPreemptionLatencyThread()
   1.379 +	{
   1.380 +	for(;;)
   1.381 +		{
   1.382 +		NKern::WaitForAnyRequest();
   1.383 +
   1.384 +		if(iKernelThreadExitSemaphore)
   1.385 +			break;
   1.386 +
   1.387 +		TBMTicks now = PChannel()->TimerStamp();
   1.388 +		iTime = Delta(iTime, now);
   1.389 +		BM_ASSERT(iUserThread);
   1.390 +		NKern::ThreadRequestSignal(&iUserThread->iNThread);
   1.391 +		}
   1.392 +
   1.393 +	NKern::FSSignal(iKernelThreadExitSemaphore);
   1.394 +	Kern::Exit(0); 
   1.395 +	}
   1.396 +
   1.397 +
   1.398 +//
   1.399 +// "USER THREAD PREEMPTION LATENCY"
   1.400 +// 
   1.401 +// SCENARIO:
   1.402 +//
   1.403 +//		A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
   1.404 +//		(RBMChannel::Result()).
   1.405 +//		When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time provided by LDD, 
   1.406 +//		in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which in its turn
   1.407 +//		signals the user thread.
   1.408 +//		The user thread, when awaken, immediately re-enters in the LDD, and calculates the latency as 
   1.409 +//		the difference between the ISR entry time and the current time.
   1.410 +//
   1.411 +
   1.412 +TInt DBMLChannel::StartUserPreemptionLatency()
   1.413 +	{
   1.414 +	if (iStarted)
   1.415 +		{
   1.416 +		return KErrInUse;
   1.417 +		}
   1.418 +	TInt r = PChannel()->BindInterrupt((MBMIsr*) this);
   1.419 +	if (r != KErrNone)
   1.420 +		{
   1.421 +		return r;
   1.422 +		}
   1.423 +		// Default iRequestInterrupt() implmentation
   1.424 +	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
   1.425 +	iResult = &DBMLChannel::UserPreemptionLatencyResult;
   1.426 +	iInterruptThread = &Kern::CurrentThread();
   1.427 +	iStarted = ETrue;
   1.428 +	return KErrNone;
   1.429 +	}
   1.430 +
   1.431 +TBMTicks DBMLChannel::UserPreemptionLatencyResult()
   1.432 +	{
   1.433 +	TBMTicks now = PChannel()->TimerStamp();
   1.434 +	return Delta(iTime, now);
   1.435 +	}
   1.436 +
   1.437 +//
   1.438 +// "NTimer PERIOD JITTER"
   1.439 +// 
   1.440 +// SCENARIO:
   1.441 +//
   1.442 +//		One measuremnt is done by two consecutive NTimer callbacks. 
   1.443 +//		The first callback stores the current time and the second one calculate the actual period as 
   1.444 +//		the difference between its own current time and the time stored by the first callback.
   1.445 +//		The difference between this actual period and the theoretical period is considered as the jitter.
   1.446 +//
   1.447 +
   1.448 +TInt DBMLChannel::StartNTimerJitter()
   1.449 +	{
   1.450 +	if (iStarted)
   1.451 +		{
   1.452 +		return KErrInUse;
   1.453 +		}
   1.454 +	new (&iNTimer) NTimer(&NTimerJitterCallBack, this);
   1.455 +	iRequestInterrupt = &DBMLChannel::RequestNTimerJitterInterrupt;
   1.456 +		// Use the default iResult() implmentation
   1.457 +	iResult = &DBMLChannel::Result;
   1.458 +	iInterruptThread = &Kern::CurrentThread();
   1.459 +	iStarted = ETrue;
   1.460 +	return KErrNone;
   1.461 +	}
   1.462 +
   1.463 +TInt DBMLChannel::RequestNTimerJitterInterrupt()
   1.464 +	{
   1.465 +	if (!iStarted)
   1.466 +		{
   1.467 +		return KErrNotReady;
   1.468 +		}
   1.469 +	if (iPendingInterruptRequest) 
   1.470 +		{
   1.471 +		return KErrInUse;
   1.472 +		}
   1.473 +	iPendingInterruptRequest = ETrue;
   1.474 +	iNTimerShotCount = 0;
   1.475 +	iNTimer.OneShot(1);
   1.476 +	return KErrNone;
   1.477 +	}
   1.478 +
   1.479 +
   1.480 +void DBMLChannel::NTimerJitterCallBack(TAny* ptr)
   1.481 +	{
   1.482 +	DBMLChannel* lCh = (DBMLChannel*) ptr;
   1.483 +	TBMTicks now = lCh->PChannel()->TimerStamp();
   1.484 +	if (lCh->iNTimerShotCount++ == 0)
   1.485 +		{
   1.486 +		//
   1.487 +		// This is the first callback: store the time and request another one.
   1.488 +		//
   1.489 +		lCh->iTime = now;
   1.490 +		lCh->iNTimer.Again(1);
   1.491 +		}
   1.492 +	else 
   1.493 +		{
   1.494 +		//
   1.495 +		// This is the second callback: measure the jitter and schedule a DFC
   1.496 +		// which in its turn will signal the user thread.
   1.497 +		//
   1.498 +		lCh->iTime = lCh->Delta(lCh->iTime, now);
   1.499 +		lCh->iDfc.Add();
   1.500 +		}
   1.501 +	}
   1.502 +
   1.503 +//
   1.504 +// "TIMER OVERHEAD"
   1.505 +// 
   1.506 +// SCENARIO:
   1.507 +//		To measure the overhead of the high-precision timer read operation we get
   1.508 +//		two consecutive timestamps through DBMPChannel::TimerStamp() interface.
   1.509 +//		The difference beween this two values is considered as the measured overhead.
   1.510 +//
   1.511 +
   1.512 +TInt DBMLChannel::StartTimerStampOverhead()
   1.513 +	{
   1.514 +	if (iStarted)
   1.515 +		{
   1.516 +		return KErrInUse;
   1.517 +		}
   1.518 +	iRequestInterrupt = &DBMLChannel::RequestTimerStampOverhead;
   1.519 +		// Use the default iResult() implmentation
   1.520 +	iResult = &DBMLChannel::Result;
   1.521 +	iInterruptThread = &Kern::CurrentThread();
   1.522 +	iStarted = ETrue;
   1.523 +	return KErrNone;
   1.524 +	}
   1.525 +
   1.526 +TInt DBMLChannel::RequestTimerStampOverhead()
   1.527 +	{
   1.528 +	TBMTicks t1 = PChannel()->TimerStamp();
   1.529 +	TBMTicks t2 = PChannel()->TimerStamp();
   1.530 +	iTime = Delta(t1, t2);
   1.531 +	NKern::ThreadRequestSignal(&iInterruptThread->iNThread);
   1.532 +	return KErrNone;
   1.533 +	}
   1.534 +//
   1.535 +// END OF "GETTING TIMER OVERHEAD"
   1.536 +//
   1.537 +
   1.538 +//
   1.539 +// The implmentation of RBMDriver::SetAbsPrioirty() call.
   1.540 +//
   1.541 +TInt DBMLChannel::SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio)
   1.542 +	{
   1.543 +	NKern::LockSystem();
   1.544 +	//
   1.545 +	// Under the system lock find the DThread object and increment its ref-count (i.e Open()) 
   1.546 +	//
   1.547 +	DThread* thr = (DThread*) Kern::ObjectFromHandle(&Kern::CurrentThread(), aThreadHandle, EThread);
   1.548 +	TInt r;
   1.549 +	if (!thr)
   1.550 +		{
   1.551 +		r = EBadHandle;
   1.552 +		}
   1.553 +	else
   1.554 +		{
   1.555 +		r = thr->Open();
   1.556 +		}
   1.557 +	//
   1.558 +	// Now it's safe to release the system lock and to work with the object.
   1.559 +	//
   1.560 +	NKern::ThreadEnterCS();
   1.561 +	NKern::UnlockSystem();
   1.562 +	if (r != KErrNone)
   1.563 +		{
   1.564 +		NKern::ThreadLeaveCS();
   1.565 +		return r;
   1.566 +		}
   1.567 +	*aOldPrio = thr->iDefaultPriority;
   1.568 +	Kern::SetThreadPriority(aNewPrio, thr);
   1.569 +	//
   1.570 +	// Work is done - close the object.
   1.571 +	//	
   1.572 +	thr->Close(NULL);
   1.573 +	NKern::ThreadLeaveCS();
   1.574 +	return KErrNone;
   1.575 +	}
   1.576 +
   1.577 +_LIT(KBmDfcQName, "BmDfcQ");
   1.578 +
   1.579 +//
   1.580 +// Starts a new sequence of measurements.
   1.581 +//
   1.582 +// Only one sequence can be started for any particular DBMLChannel object during its life. 
   1.583 +// If more than one sequence is required a new DBMLChannel object must be created.
   1.584 +//
   1.585 +TInt DBMLChannel::Start(RBMChannel::TMode aMode)
   1.586 +	{
   1.587 +	TInt r;
   1.588 +	if (iDfcQ == NULL)
   1.589 +		{
   1.590 +		r = Kern::DynamicDfcQCreate(iDfcQ, KBMDfcQThreadPriority, KBmDfcQName);
   1.591 +		if (r != KErrNone)
   1.592 +			return r;
   1.593 +
   1.594 +		iDfc.SetDfcQ(iDfcQ);
   1.595 +		iDfc.SetFunction(Dfc);
   1.596 +		}
   1.597 +
   1.598 +	switch (aMode)
   1.599 +		{
   1.600 +	case RBMChannel::EInterruptLatency:
   1.601 +		r = StartInterruptLatency();
   1.602 +		break;
   1.603 +	case RBMChannel::EKernelPreemptionLatency:
   1.604 +		r = StartKernelPreemptionLatency();
   1.605 +		break;
   1.606 +	case RBMChannel::EUserPreemptionLatency:
   1.607 +		r = StartUserPreemptionLatency();
   1.608 +		break;
   1.609 +	case RBMChannel::ENTimerJitter:
   1.610 +		r = StartNTimerJitter();
   1.611 +		break;
   1.612 +	case RBMChannel::ETimerStampOverhead:
   1.613 +		r = StartTimerStampOverhead();
   1.614 +		break;
   1.615 +	default:
   1.616 +		r = KErrNotSupported;
   1.617 +		break;
   1.618 +		}
   1.619 +
   1.620 +	return r;
   1.621 +	}
   1.622 +
   1.623 +//
   1.624 +// Client requests.
   1.625 +//
   1.626 +TInt DBMLChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
   1.627 +	{
   1.628 +	TInt r = KErrNone;
   1.629 +	switch (aFunction)
   1.630 +		{
   1.631 +		case RBMChannel::EStart:
   1.632 +			{
   1.633 +			RBMChannel::TMode mode = (RBMChannel::TMode) (TInt) a1;
   1.634 +			Lock();
   1.635 +			r = Start(mode);
   1.636 +			Unlock();
   1.637 +			break;
   1.638 +			}
   1.639 +		case RBMChannel::ERequestInterrupt:
   1.640 +			{
   1.641 +			Lock();
   1.642 +			r = (this->*iRequestInterrupt)();
   1.643 +			Unlock();
   1.644 +			break;
   1.645 +			}
   1.646 +		case RBMChannel::EResult:
   1.647 +			{
   1.648 +			//
   1.649 +			// We don't acquire the lock because:
   1.650 +			//	(1) iResult() typically reads iTime which was written BEFORE to signal the current thread 
   1.651 +			//      and therefore BEFORE the current thread comes here. 
   1.652 +			//  (2) we really want if possible (i.e. correct!) to avoid the lock acquisition because it can
   1.653 +			//		increase the measurement overhead in the case when we are in a measured path (e.g. user
   1.654 +			//		preemption latency benchmark).
   1.655 +			//
   1.656 +			TBMTicks ticks = (this->*iResult)();
   1.657 +			umemput(a1, &ticks, sizeof(ticks));
   1.658 +			break;
   1.659 +			}
   1.660 +		//
   1.661 +		// All below requests do not access writable DBMChannel state and therefore do not require the lock
   1.662 +		//
   1.663 +		case RBMChannel::ETimerStamp:
   1.664 +			{
   1.665 +			TBMTicks ticks = PChannel()->TimerStamp();
   1.666 +			umemput(a1, &ticks, sizeof(ticks));
   1.667 +			break;
   1.668 +			}
   1.669 +		case RBMChannel::ETimerPeriod:
   1.670 +			{
   1.671 +			TBMTicks ticks = iTimerPeriod;
   1.672 +			umemput(a1, &ticks, sizeof(ticks));
   1.673 +			break;
   1.674 +			}
   1.675 +		case RBMChannel::ETimerTicksToNs:
   1.676 +			{
   1.677 +			TBMTicks ticks;
   1.678 +			umemget(&ticks, a1, sizeof(ticks));
   1.679 +			TBMNs ns = PChannel()->TimerTicksToNs(ticks);
   1.680 +			umemput(a2, &ns, sizeof(ns));
   1.681 +			break;
   1.682 +			}
   1.683 +		case RBMChannel::ETimerNsToTicks:
   1.684 +			{
   1.685 +			TBMNs ns;
   1.686 +			umemget(&ns, a1, sizeof(ns));
   1.687 +			TBMTicks ticks = PChannel()->TimerNsToTicks(ns);
   1.688 +			umemput(a2, &ticks, sizeof(ticks));
   1.689 +			break;
   1.690 +			}
   1.691 +		case RBMChannel::ESetAbsPriority:
   1.692 +			{
   1.693 +			TInt newPrio;
   1.694 +			TInt oldPrio;
   1.695 +			umemget(&newPrio, a2, sizeof(newPrio));
   1.696 +			r = SetAbsPrioirty((TInt) a1, newPrio, &oldPrio);
   1.697 +			umemput(a2, &oldPrio, sizeof(oldPrio));
   1.698 +			break;
   1.699 +			}
   1.700 +		default:
   1.701 +			r = KErrNotSupported;
   1.702 +			break;
   1.703 +		}
   1.704 +	return r;
   1.705 +	}
   1.706 +
   1.707 +