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 +