os/kernelhwsrv/kerneltest/e32test/benchmark/bm_ldd.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "k32bm.h"
sl@0
    17
sl@0
    18
const TUint8 KMutexOrder = 0xf0;
sl@0
    19
sl@0
    20
class DBMLDevice : public DLogicalDevice
sl@0
    21
	{
sl@0
    22
public:
sl@0
    23
	DBMLDevice();
sl@0
    24
	virtual TInt Install();
sl@0
    25
	virtual void GetCaps(TDes8& aDes) const;
sl@0
    26
	virtual TInt Create(DLogicalChannelBase*& aChannel);
sl@0
    27
	};
sl@0
    28
sl@0
    29
class DBMLChannel : public DLogicalChannelBase, public MBMIsr, public MBMInterruptLatencyIsr
sl@0
    30
	{
sl@0
    31
public:
sl@0
    32
	DBMLChannel();
sl@0
    33
	~DBMLChannel();
sl@0
    34
sl@0
    35
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
sl@0
    36
	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
sl@0
    37
sl@0
    38
	DBMPChannel* PChannel() { return (DBMPChannel*) iPdd; }
sl@0
    39
sl@0
    40
private:
sl@0
    41
	static const TInt	KBMDfcQThreadPriority;	
sl@0
    42
	static const TInt	KBMKernelThreadPriority;	
sl@0
    43
sl@0
    44
	static void Dfc(TAny*);
sl@0
    45
sl@0
    46
	virtual void Isr(TBMTicks now);
sl@0
    47
sl@0
    48
	TInt (DBMLChannel::*iRequestInterrupt)();	// Measurement specific RBMChannel::RequestInterrupt() implmentation 
sl@0
    49
	TInt RequestInterrupt();					// Default iRequestInterrupt() implementation
sl@0
    50
sl@0
    51
	TBMTicks (DBMLChannel::*iResult)();			// Measurement specific RBMChannel::Result() implmentation
sl@0
    52
	TBMTicks Result();							// Default iResult() implementation
sl@0
    53
sl@0
    54
	TInt Start(RBMChannel::TMode);
sl@0
    55
sl@0
    56
	TInt StartInterruptLatency();
sl@0
    57
	virtual void InterruptLatencyIsr(TBMTicks latency);
sl@0
    58
sl@0
    59
	TInt StartKernelPreemptionLatency();
sl@0
    60
	static TInt KernelPreemptionLatencyThreadEntry(TAny* ptr);
sl@0
    61
	void KernelPreemptionLatencyThread();
sl@0
    62
sl@0
    63
	TInt StartUserPreemptionLatency();
sl@0
    64
	TBMTicks UserPreemptionLatencyResult();		// iResult() implementation
sl@0
    65
sl@0
    66
	TInt StartNTimerJitter();
sl@0
    67
	TInt RequestNTimerJitterInterrupt();		// iRequestInterrupt() implementation
sl@0
    68
	static void NTimerJitterCallBack(TAny*);
sl@0
    69
sl@0
    70
	TInt StartTimerStampOverhead();
sl@0
    71
	TInt RequestTimerStampOverhead();			// iRequestInterrupt() implementation
sl@0
    72
sl@0
    73
	TInt SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio);
sl@0
    74
sl@0
    75
	DMutex*			iLock;	// Shall be acquired by anyone who access the object's writable state.
sl@0
    76
sl@0
    77
	TBool			iStarted;					// ETrue when a particular sequence of measurements has been started
sl@0
    78
	TBool			iPendingInterruptRequest;	// ETrue when an interrupt has been requested
sl@0
    79
sl@0
    80
	TDynamicDfcQue*	iDfcQ;
sl@0
    81
	TDfc			iDfc;
sl@0
    82
sl@0
    83
	DThread*		iKernelThread;		// the kernel thread created by some benchmarks
sl@0
    84
	DThread*		iUserThread;		// the user-side thread
sl@0
    85
	DThread*		iInterruptThread;	// the thread signaled by DFC; if non-NULL either iKernelThread or iUserThread
sl@0
    86
sl@0
    87
	NTimer			iNTimer;			// the timer used in "NTimer jitter" benchmark
sl@0
    88
	TBMTicks		iOneNTimerTick;		// number of high-resolution timer ticks in one NKern tick.
sl@0
    89
	TInt			iNTimerShotCount;	// used in "NTimer jitter" to distinguish between the first and the second shots 
sl@0
    90
sl@0
    91
	TBMTicks		iTime;
sl@0
    92
	TBMTicks		iTimerPeriod;		// period of high-resolution timer in ticks
sl@0
    93
sl@0
    94
	NFastSemaphore*	iKernelThreadExitSemaphore;
sl@0
    95
sl@0
    96
	void Lock()
sl@0
    97
		{
sl@0
    98
		NKern::ThreadEnterCS();
sl@0
    99
		Kern::MutexWait(*iLock);
sl@0
   100
		}
sl@0
   101
	void Unlock()
sl@0
   102
		{
sl@0
   103
		Kern::MutexSignal(*iLock);
sl@0
   104
		NKern::ThreadLeaveCS();
sl@0
   105
		}
sl@0
   106
	
sl@0
   107
	TBMTicks Delta(TBMTicks aT0, TBMTicks aT1)
sl@0
   108
		{
sl@0
   109
		return (aT0 <= aT1) ? (aT1 - aT0) : iTimerPeriod - (aT0 - aT1);
sl@0
   110
		}
sl@0
   111
	};
sl@0
   112
sl@0
   113
_LIT(KBMLChannelLit, "BMLChannel");
sl@0
   114
sl@0
   115
const TInt	DBMLChannel::KBMDfcQThreadPriority = KBMLDDHighPriority;
sl@0
   116
const TInt	DBMLChannel::KBMKernelThreadPriority = KBMLDDMidPriority;
sl@0
   117
sl@0
   118
sl@0
   119
sl@0
   120
DECLARE_STANDARD_LDD()
sl@0
   121
//
sl@0
   122
// Create a new device
sl@0
   123
//
sl@0
   124
	{
sl@0
   125
	__ASSERT_CRITICAL;
sl@0
   126
	return new DBMLDevice;
sl@0
   127
	}
sl@0
   128
sl@0
   129
DBMLDevice::DBMLDevice()
sl@0
   130
//
sl@0
   131
// Constructor
sl@0
   132
//
sl@0
   133
	{
sl@0
   134
	//iUnitsMask=0;
sl@0
   135
	iVersion = TVersion(1,0,1);
sl@0
   136
	iParseMask = KDeviceAllowPhysicalDevice;
sl@0
   137
	}
sl@0
   138
sl@0
   139
TInt DBMLDevice::Install()
sl@0
   140
//
sl@0
   141
// Install the device driver.
sl@0
   142
//
sl@0
   143
	{
sl@0
   144
	TInt r = SetName(&KBMLdName);
sl@0
   145
	return r;
sl@0
   146
	}
sl@0
   147
sl@0
   148
void DBMLDevice::GetCaps(TDes8&) const
sl@0
   149
//
sl@0
   150
// Return the Comm capabilities.
sl@0
   151
//
sl@0
   152
	{
sl@0
   153
	}
sl@0
   154
sl@0
   155
TInt DBMLDevice::Create(DLogicalChannelBase*& aChannel)
sl@0
   156
//
sl@0
   157
// Create a channel on the device.
sl@0
   158
//
sl@0
   159
	{
sl@0
   160
	__ASSERT_CRITICAL;
sl@0
   161
	aChannel = new DBMLChannel;
sl@0
   162
	return aChannel ? KErrNone : KErrNoMemory;
sl@0
   163
	}
sl@0
   164
sl@0
   165
DBMLChannel::DBMLChannel() : 
sl@0
   166
		iDfc(0, this, 0, 0),
sl@0
   167
		iNTimer(NULL, this)
sl@0
   168
	{
sl@0
   169
	// iDfcQueue = NULL;
sl@0
   170
	// iStarted = EFalse;
sl@0
   171
	// iPendingInterruptRequest = EFalse;
sl@0
   172
	// iKernelThread = NULL;
sl@0
   173
	}
sl@0
   174
sl@0
   175
TInt DBMLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer)
sl@0
   176
//
sl@0
   177
// Create the channel from the passed info.
sl@0
   178
//
sl@0
   179
	{
sl@0
   180
	__ASSERT_CRITICAL;
sl@0
   181
	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
sl@0
   182
		return KErrNotSupported;
sl@0
   183
	TInt r = Kern::MutexCreate(iLock, KBMLChannelLit, KMutexOrder);
sl@0
   184
	if (r != KErrNone)
sl@0
   185
		{
sl@0
   186
		return r;
sl@0
   187
		}
sl@0
   188
	iTimerPeriod = PChannel()->TimerPeriod();
sl@0
   189
		// Calculate the number of high-resolution timer ticks in one NKern tick
sl@0
   190
		// deviding the number of high-resolution timer ticks in one second by the
sl@0
   191
		// number of NKern ticks in one second.
sl@0
   192
		//
sl@0
   193
	iOneNTimerTick = PChannel()->TimerNsToTicks(BMSecondsToNs(1))/NKern::TimerTicks(1000);
sl@0
   194
	return KErrNone;
sl@0
   195
	}
sl@0
   196
sl@0
   197
DBMLChannel::~DBMLChannel()
sl@0
   198
// Called on a channel close. Note that if the PDD channel create failed 
sl@0
   199
// then the DoCreate() call will not have been made so don't assume anything 
sl@0
   200
// about non-ctor initialisation of members.
sl@0
   201
	{
sl@0
   202
	if (iLock) 
sl@0
   203
		iLock->Close(0);
sl@0
   204
sl@0
   205
	if (iPendingInterruptRequest)
sl@0
   206
		{
sl@0
   207
		PChannel()->CancelInterrupt();
sl@0
   208
		iDfc.Cancel();
sl@0
   209
		}
sl@0
   210
sl@0
   211
	if (iDfcQ)
sl@0
   212
		{
sl@0
   213
		iDfcQ->Destroy();
sl@0
   214
		}
sl@0
   215
sl@0
   216
	if (iKernelThread)
sl@0
   217
		{
sl@0
   218
		NFastSemaphore exitSemaphore;
sl@0
   219
		exitSemaphore.iOwningThread = NKern::CurrentThread();
sl@0
   220
		iKernelThreadExitSemaphore = &exitSemaphore;
sl@0
   221
		NKern::ThreadRequestSignal(&iKernelThread->iNThread);
sl@0
   222
		NKern::FSWait(&exitSemaphore);
sl@0
   223
		}
sl@0
   224
	}
sl@0
   225
sl@0
   226
void DBMLChannel::Dfc(TAny* ptr)
sl@0
   227
	{	
sl@0
   228
	DBMLChannel* lCh = (DBMLChannel*) ptr;
sl@0
   229
	BM_ASSERT(lCh->iPendingInterruptRequest);
sl@0
   230
	BM_ASSERT(lCh->iInterruptThread);
sl@0
   231
	NKern::ThreadRequestSignal(&lCh->iInterruptThread->iNThread);
sl@0
   232
	lCh->iPendingInterruptRequest = EFalse;
sl@0
   233
	}
sl@0
   234
sl@0
   235
//
sl@0
   236
// Default DBMLChannel::iRequestInterrupt implementation
sl@0
   237
//
sl@0
   238
TInt DBMLChannel::RequestInterrupt()
sl@0
   239
	{
sl@0
   240
	if (!iStarted)
sl@0
   241
		{
sl@0
   242
		return KErrNotReady;
sl@0
   243
		}
sl@0
   244
	if (iPendingInterruptRequest) 
sl@0
   245
		{
sl@0
   246
		return KErrInUse;
sl@0
   247
		}
sl@0
   248
	iPendingInterruptRequest = ETrue;
sl@0
   249
	PChannel()->RequestInterrupt();
sl@0
   250
	return KErrNone;
sl@0
   251
	}
sl@0
   252
sl@0
   253
//
sl@0
   254
// Default DBMLChannel::iResult implementation
sl@0
   255
//
sl@0
   256
TBMTicks DBMLChannel::Result()
sl@0
   257
	{
sl@0
   258
	return iTime;
sl@0
   259
	}
sl@0
   260
sl@0
   261
void DBMLChannel::Isr(TBMTicks aNow)
sl@0
   262
	{
sl@0
   263
	//
sl@0
   264
	// Store the ISR entry time and queue a DFC.
sl@0
   265
	//
sl@0
   266
	iTime = aNow;
sl@0
   267
	iDfc.Add();
sl@0
   268
	}
sl@0
   269
sl@0
   270
//
sl@0
   271
// "INTERRUPT LATENCY"
sl@0
   272
// 
sl@0
   273
// SCENARIO:
sl@0
   274
//
sl@0
   275
//		A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
sl@0
   276
//		(RBMChannel::Result()).
sl@0
   277
//		When the interrupt occurs DBMLChannel::InterruptLatencyIsr() stores the interrupt latency 
sl@0
   278
//		provided by LDD, in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc())
sl@0
   279
//		which in its turn signals the user thread.
sl@0
   280
//
sl@0
   281
sl@0
   282
TInt DBMLChannel::StartInterruptLatency()
sl@0
   283
	{
sl@0
   284
	if (iStarted)
sl@0
   285
		{
sl@0
   286
		return KErrInUse;
sl@0
   287
		}
sl@0
   288
	TInt r = PChannel()->BindInterrupt((MBMInterruptLatencyIsr*) this);
sl@0
   289
	if (r != KErrNone)
sl@0
   290
		{
sl@0
   291
		return r;
sl@0
   292
		}
sl@0
   293
		// Use the default iRequestInterrupt() implmentation
sl@0
   294
	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
sl@0
   295
		// Use the default iResult() implmentation
sl@0
   296
	iResult = &DBMLChannel::Result;
sl@0
   297
	iInterruptThread = &Kern::CurrentThread();
sl@0
   298
	iStarted = ETrue;
sl@0
   299
	return KErrNone;
sl@0
   300
	}
sl@0
   301
sl@0
   302
void DBMLChannel::InterruptLatencyIsr(TBMTicks aLatency)
sl@0
   303
	{
sl@0
   304
	iTime = aLatency;
sl@0
   305
	iDfc.Add();
sl@0
   306
	}
sl@0
   307
sl@0
   308
//
sl@0
   309
// "KERNEL THREAD PREEMPTION LATENCY"
sl@0
   310
// 
sl@0
   311
// SCENARIO:
sl@0
   312
//
sl@0
   313
//		A new kernel thread is created at the beginning of a sequence of measurements 
sl@0
   314
//		(DBMLChannel::StartKernelPreemptionLatency()). The kernel thread waits at Kern::WaitForAnyRequest()
sl@0
   315
//		(DBMLChannel::KernelPreemptionLatencyThread()).
sl@0
   316
//		The user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
sl@0
   317
//		(RBMChannel::Result()).
sl@0
   318
//		When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time, provided by LDD 
sl@0
   319
//		in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which, in its turn,
sl@0
   320
//		signals the kernel thread.
sl@0
   321
//		The kernel thread, when awaken, calculates the latency as the difference between the ISR entry time 
sl@0
   322
//		and the current time and finally signals the user thread.
sl@0
   323
//
sl@0
   324
sl@0
   325
TInt DBMLChannel::StartKernelPreemptionLatency()
sl@0
   326
	{
sl@0
   327
	if (iStarted)
sl@0
   328
		{
sl@0
   329
		return KErrInUse;
sl@0
   330
		}
sl@0
   331
	TInt r = PChannel()->BindInterrupt((MBMIsr*) this);
sl@0
   332
	if (r != KErrNone)
sl@0
   333
		{
sl@0
   334
		return r;
sl@0
   335
		}
sl@0
   336
	{
sl@0
   337
	SThreadCreateInfo info;
sl@0
   338
	info.iType = EThreadSupervisor;
sl@0
   339
	info.iFunction = DBMLChannel::KernelPreemptionLatencyThreadEntry;
sl@0
   340
	info.iPtr = this;
sl@0
   341
	info.iSupervisorStack = NULL;
sl@0
   342
	info.iSupervisorStackSize = 0;
sl@0
   343
	info.iInitialThreadPriority = KBMKernelThreadPriority;
sl@0
   344
	info.iName.Set(KBMLChannelLit);
sl@0
   345
	info.iTotalSize = sizeof(info);
sl@0
   346
	r = Kern::ThreadCreate(info);
sl@0
   347
	if (r != KErrNone)
sl@0
   348
		{
sl@0
   349
		return r;
sl@0
   350
		}
sl@0
   351
	iKernelThread = (DThread*) info.iHandle;
sl@0
   352
	}
sl@0
   353
sl@0
   354
	iUserThread = &Kern::CurrentThread();
sl@0
   355
		// Use the default iRequestInterrupt() implmentation
sl@0
   356
	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
sl@0
   357
		// Use the default iResult() implmentation
sl@0
   358
	iResult = &DBMLChannel::Result;
sl@0
   359
	iInterruptThread = iKernelThread;
sl@0
   360
	iStarted = ETrue;
sl@0
   361
sl@0
   362
	Kern::ThreadResume(*iKernelThread);
sl@0
   363
sl@0
   364
	return KErrNone;
sl@0
   365
	}
sl@0
   366
sl@0
   367
TInt DBMLChannel::KernelPreemptionLatencyThreadEntry(TAny* ptr)
sl@0
   368
	{
sl@0
   369
	DBMLChannel* lCh = (DBMLChannel*) ptr;
sl@0
   370
	lCh->KernelPreemptionLatencyThread();
sl@0
   371
	BM_ASSERT(0);
sl@0
   372
	return 0;
sl@0
   373
	}
sl@0
   374
sl@0
   375
void DBMLChannel::KernelPreemptionLatencyThread()
sl@0
   376
	{
sl@0
   377
	for(;;)
sl@0
   378
		{
sl@0
   379
		NKern::WaitForAnyRequest();
sl@0
   380
sl@0
   381
		if(iKernelThreadExitSemaphore)
sl@0
   382
			break;
sl@0
   383
sl@0
   384
		TBMTicks now = PChannel()->TimerStamp();
sl@0
   385
		iTime = Delta(iTime, now);
sl@0
   386
		BM_ASSERT(iUserThread);
sl@0
   387
		NKern::ThreadRequestSignal(&iUserThread->iNThread);
sl@0
   388
		}
sl@0
   389
sl@0
   390
	NKern::FSSignal(iKernelThreadExitSemaphore);
sl@0
   391
	Kern::Exit(0); 
sl@0
   392
	}
sl@0
   393
sl@0
   394
sl@0
   395
//
sl@0
   396
// "USER THREAD PREEMPTION LATENCY"
sl@0
   397
// 
sl@0
   398
// SCENARIO:
sl@0
   399
//
sl@0
   400
//		A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest()
sl@0
   401
//		(RBMChannel::Result()).
sl@0
   402
//		When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time provided by LDD, 
sl@0
   403
//		in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which in its turn
sl@0
   404
//		signals the user thread.
sl@0
   405
//		The user thread, when awaken, immediately re-enters in the LDD, and calculates the latency as 
sl@0
   406
//		the difference between the ISR entry time and the current time.
sl@0
   407
//
sl@0
   408
sl@0
   409
TInt DBMLChannel::StartUserPreemptionLatency()
sl@0
   410
	{
sl@0
   411
	if (iStarted)
sl@0
   412
		{
sl@0
   413
		return KErrInUse;
sl@0
   414
		}
sl@0
   415
	TInt r = PChannel()->BindInterrupt((MBMIsr*) this);
sl@0
   416
	if (r != KErrNone)
sl@0
   417
		{
sl@0
   418
		return r;
sl@0
   419
		}
sl@0
   420
		// Default iRequestInterrupt() implmentation
sl@0
   421
	iRequestInterrupt = &DBMLChannel::RequestInterrupt;
sl@0
   422
	iResult = &DBMLChannel::UserPreemptionLatencyResult;
sl@0
   423
	iInterruptThread = &Kern::CurrentThread();
sl@0
   424
	iStarted = ETrue;
sl@0
   425
	return KErrNone;
sl@0
   426
	}
sl@0
   427
sl@0
   428
TBMTicks DBMLChannel::UserPreemptionLatencyResult()
sl@0
   429
	{
sl@0
   430
	TBMTicks now = PChannel()->TimerStamp();
sl@0
   431
	return Delta(iTime, now);
sl@0
   432
	}
sl@0
   433
sl@0
   434
//
sl@0
   435
// "NTimer PERIOD JITTER"
sl@0
   436
// 
sl@0
   437
// SCENARIO:
sl@0
   438
//
sl@0
   439
//		One measuremnt is done by two consecutive NTimer callbacks. 
sl@0
   440
//		The first callback stores the current time and the second one calculate the actual period as 
sl@0
   441
//		the difference between its own current time and the time stored by the first callback.
sl@0
   442
//		The difference between this actual period and the theoretical period is considered as the jitter.
sl@0
   443
//
sl@0
   444
sl@0
   445
TInt DBMLChannel::StartNTimerJitter()
sl@0
   446
	{
sl@0
   447
	if (iStarted)
sl@0
   448
		{
sl@0
   449
		return KErrInUse;
sl@0
   450
		}
sl@0
   451
	new (&iNTimer) NTimer(&NTimerJitterCallBack, this);
sl@0
   452
	iRequestInterrupt = &DBMLChannel::RequestNTimerJitterInterrupt;
sl@0
   453
		// Use the default iResult() implmentation
sl@0
   454
	iResult = &DBMLChannel::Result;
sl@0
   455
	iInterruptThread = &Kern::CurrentThread();
sl@0
   456
	iStarted = ETrue;
sl@0
   457
	return KErrNone;
sl@0
   458
	}
sl@0
   459
sl@0
   460
TInt DBMLChannel::RequestNTimerJitterInterrupt()
sl@0
   461
	{
sl@0
   462
	if (!iStarted)
sl@0
   463
		{
sl@0
   464
		return KErrNotReady;
sl@0
   465
		}
sl@0
   466
	if (iPendingInterruptRequest) 
sl@0
   467
		{
sl@0
   468
		return KErrInUse;
sl@0
   469
		}
sl@0
   470
	iPendingInterruptRequest = ETrue;
sl@0
   471
	iNTimerShotCount = 0;
sl@0
   472
	iNTimer.OneShot(1);
sl@0
   473
	return KErrNone;
sl@0
   474
	}
sl@0
   475
sl@0
   476
sl@0
   477
void DBMLChannel::NTimerJitterCallBack(TAny* ptr)
sl@0
   478
	{
sl@0
   479
	DBMLChannel* lCh = (DBMLChannel*) ptr;
sl@0
   480
	TBMTicks now = lCh->PChannel()->TimerStamp();
sl@0
   481
	if (lCh->iNTimerShotCount++ == 0)
sl@0
   482
		{
sl@0
   483
		//
sl@0
   484
		// This is the first callback: store the time and request another one.
sl@0
   485
		//
sl@0
   486
		lCh->iTime = now;
sl@0
   487
		lCh->iNTimer.Again(1);
sl@0
   488
		}
sl@0
   489
	else 
sl@0
   490
		{
sl@0
   491
		//
sl@0
   492
		// This is the second callback: measure the jitter and schedule a DFC
sl@0
   493
		// which in its turn will signal the user thread.
sl@0
   494
		//
sl@0
   495
		lCh->iTime = lCh->Delta(lCh->iTime, now);
sl@0
   496
		lCh->iDfc.Add();
sl@0
   497
		}
sl@0
   498
	}
sl@0
   499
sl@0
   500
//
sl@0
   501
// "TIMER OVERHEAD"
sl@0
   502
// 
sl@0
   503
// SCENARIO:
sl@0
   504
//		To measure the overhead of the high-precision timer read operation we get
sl@0
   505
//		two consecutive timestamps through DBMPChannel::TimerStamp() interface.
sl@0
   506
//		The difference beween this two values is considered as the measured overhead.
sl@0
   507
//
sl@0
   508
sl@0
   509
TInt DBMLChannel::StartTimerStampOverhead()
sl@0
   510
	{
sl@0
   511
	if (iStarted)
sl@0
   512
		{
sl@0
   513
		return KErrInUse;
sl@0
   514
		}
sl@0
   515
	iRequestInterrupt = &DBMLChannel::RequestTimerStampOverhead;
sl@0
   516
		// Use the default iResult() implmentation
sl@0
   517
	iResult = &DBMLChannel::Result;
sl@0
   518
	iInterruptThread = &Kern::CurrentThread();
sl@0
   519
	iStarted = ETrue;
sl@0
   520
	return KErrNone;
sl@0
   521
	}
sl@0
   522
sl@0
   523
TInt DBMLChannel::RequestTimerStampOverhead()
sl@0
   524
	{
sl@0
   525
	TBMTicks t1 = PChannel()->TimerStamp();
sl@0
   526
	TBMTicks t2 = PChannel()->TimerStamp();
sl@0
   527
	iTime = Delta(t1, t2);
sl@0
   528
	NKern::ThreadRequestSignal(&iInterruptThread->iNThread);
sl@0
   529
	return KErrNone;
sl@0
   530
	}
sl@0
   531
//
sl@0
   532
// END OF "GETTING TIMER OVERHEAD"
sl@0
   533
//
sl@0
   534
sl@0
   535
//
sl@0
   536
// The implmentation of RBMDriver::SetAbsPrioirty() call.
sl@0
   537
//
sl@0
   538
TInt DBMLChannel::SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio)
sl@0
   539
	{
sl@0
   540
	NKern::LockSystem();
sl@0
   541
	//
sl@0
   542
	// Under the system lock find the DThread object and increment its ref-count (i.e Open()) 
sl@0
   543
	//
sl@0
   544
	DThread* thr = (DThread*) Kern::ObjectFromHandle(&Kern::CurrentThread(), aThreadHandle, EThread);
sl@0
   545
	TInt r;
sl@0
   546
	if (!thr)
sl@0
   547
		{
sl@0
   548
		r = EBadHandle;
sl@0
   549
		}
sl@0
   550
	else
sl@0
   551
		{
sl@0
   552
		r = thr->Open();
sl@0
   553
		}
sl@0
   554
	//
sl@0
   555
	// Now it's safe to release the system lock and to work with the object.
sl@0
   556
	//
sl@0
   557
	NKern::ThreadEnterCS();
sl@0
   558
	NKern::UnlockSystem();
sl@0
   559
	if (r != KErrNone)
sl@0
   560
		{
sl@0
   561
		NKern::ThreadLeaveCS();
sl@0
   562
		return r;
sl@0
   563
		}
sl@0
   564
	*aOldPrio = thr->iDefaultPriority;
sl@0
   565
	Kern::SetThreadPriority(aNewPrio, thr);
sl@0
   566
	//
sl@0
   567
	// Work is done - close the object.
sl@0
   568
	//	
sl@0
   569
	thr->Close(NULL);
sl@0
   570
	NKern::ThreadLeaveCS();
sl@0
   571
	return KErrNone;
sl@0
   572
	}
sl@0
   573
sl@0
   574
_LIT(KBmDfcQName, "BmDfcQ");
sl@0
   575
sl@0
   576
//
sl@0
   577
// Starts a new sequence of measurements.
sl@0
   578
//
sl@0
   579
// Only one sequence can be started for any particular DBMLChannel object during its life. 
sl@0
   580
// If more than one sequence is required a new DBMLChannel object must be created.
sl@0
   581
//
sl@0
   582
TInt DBMLChannel::Start(RBMChannel::TMode aMode)
sl@0
   583
	{
sl@0
   584
	TInt r;
sl@0
   585
	if (iDfcQ == NULL)
sl@0
   586
		{
sl@0
   587
		r = Kern::DynamicDfcQCreate(iDfcQ, KBMDfcQThreadPriority, KBmDfcQName);
sl@0
   588
		if (r != KErrNone)
sl@0
   589
			return r;
sl@0
   590
sl@0
   591
		iDfc.SetDfcQ(iDfcQ);
sl@0
   592
		iDfc.SetFunction(Dfc);
sl@0
   593
		}
sl@0
   594
sl@0
   595
	switch (aMode)
sl@0
   596
		{
sl@0
   597
	case RBMChannel::EInterruptLatency:
sl@0
   598
		r = StartInterruptLatency();
sl@0
   599
		break;
sl@0
   600
	case RBMChannel::EKernelPreemptionLatency:
sl@0
   601
		r = StartKernelPreemptionLatency();
sl@0
   602
		break;
sl@0
   603
	case RBMChannel::EUserPreemptionLatency:
sl@0
   604
		r = StartUserPreemptionLatency();
sl@0
   605
		break;
sl@0
   606
	case RBMChannel::ENTimerJitter:
sl@0
   607
		r = StartNTimerJitter();
sl@0
   608
		break;
sl@0
   609
	case RBMChannel::ETimerStampOverhead:
sl@0
   610
		r = StartTimerStampOverhead();
sl@0
   611
		break;
sl@0
   612
	default:
sl@0
   613
		r = KErrNotSupported;
sl@0
   614
		break;
sl@0
   615
		}
sl@0
   616
sl@0
   617
	return r;
sl@0
   618
	}
sl@0
   619
sl@0
   620
//
sl@0
   621
// Client requests.
sl@0
   622
//
sl@0
   623
TInt DBMLChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
sl@0
   624
	{
sl@0
   625
	TInt r = KErrNone;
sl@0
   626
	switch (aFunction)
sl@0
   627
		{
sl@0
   628
		case RBMChannel::EStart:
sl@0
   629
			{
sl@0
   630
			RBMChannel::TMode mode = (RBMChannel::TMode) (TInt) a1;
sl@0
   631
			Lock();
sl@0
   632
			r = Start(mode);
sl@0
   633
			Unlock();
sl@0
   634
			break;
sl@0
   635
			}
sl@0
   636
		case RBMChannel::ERequestInterrupt:
sl@0
   637
			{
sl@0
   638
			Lock();
sl@0
   639
			r = (this->*iRequestInterrupt)();
sl@0
   640
			Unlock();
sl@0
   641
			break;
sl@0
   642
			}
sl@0
   643
		case RBMChannel::EResult:
sl@0
   644
			{
sl@0
   645
			//
sl@0
   646
			// We don't acquire the lock because:
sl@0
   647
			//	(1) iResult() typically reads iTime which was written BEFORE to signal the current thread 
sl@0
   648
			//      and therefore BEFORE the current thread comes here. 
sl@0
   649
			//  (2) we really want if possible (i.e. correct!) to avoid the lock acquisition because it can
sl@0
   650
			//		increase the measurement overhead in the case when we are in a measured path (e.g. user
sl@0
   651
			//		preemption latency benchmark).
sl@0
   652
			//
sl@0
   653
			TBMTicks ticks = (this->*iResult)();
sl@0
   654
			umemput(a1, &ticks, sizeof(ticks));
sl@0
   655
			break;
sl@0
   656
			}
sl@0
   657
		//
sl@0
   658
		// All below requests do not access writable DBMChannel state and therefore do not require the lock
sl@0
   659
		//
sl@0
   660
		case RBMChannel::ETimerStamp:
sl@0
   661
			{
sl@0
   662
			TBMTicks ticks = PChannel()->TimerStamp();
sl@0
   663
			umemput(a1, &ticks, sizeof(ticks));
sl@0
   664
			break;
sl@0
   665
			}
sl@0
   666
		case RBMChannel::ETimerPeriod:
sl@0
   667
			{
sl@0
   668
			TBMTicks ticks = iTimerPeriod;
sl@0
   669
			umemput(a1, &ticks, sizeof(ticks));
sl@0
   670
			break;
sl@0
   671
			}
sl@0
   672
		case RBMChannel::ETimerTicksToNs:
sl@0
   673
			{
sl@0
   674
			TBMTicks ticks;
sl@0
   675
			umemget(&ticks, a1, sizeof(ticks));
sl@0
   676
			TBMNs ns = PChannel()->TimerTicksToNs(ticks);
sl@0
   677
			umemput(a2, &ns, sizeof(ns));
sl@0
   678
			break;
sl@0
   679
			}
sl@0
   680
		case RBMChannel::ETimerNsToTicks:
sl@0
   681
			{
sl@0
   682
			TBMNs ns;
sl@0
   683
			umemget(&ns, a1, sizeof(ns));
sl@0
   684
			TBMTicks ticks = PChannel()->TimerNsToTicks(ns);
sl@0
   685
			umemput(a2, &ticks, sizeof(ticks));
sl@0
   686
			break;
sl@0
   687
			}
sl@0
   688
		case RBMChannel::ESetAbsPriority:
sl@0
   689
			{
sl@0
   690
			TInt newPrio;
sl@0
   691
			TInt oldPrio;
sl@0
   692
			umemget(&newPrio, a2, sizeof(newPrio));
sl@0
   693
			r = SetAbsPrioirty((TInt) a1, newPrio, &oldPrio);
sl@0
   694
			umemput(a2, &oldPrio, sizeof(oldPrio));
sl@0
   695
			break;
sl@0
   696
			}
sl@0
   697
		default:
sl@0
   698
			r = KErrNotSupported;
sl@0
   699
			break;
sl@0
   700
		}
sl@0
   701
	return r;
sl@0
   702
	}
sl@0
   703
sl@0
   704