--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/btrace_parser/src/btrace_cpuusage.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,344 @@
+// btrace_cpuusage.cpp
+//
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include "btrace_parser.h"
+
+MBtraceCpuUsageObserver::TCpuUsage::TCpuUsage(const TBtraceThreadId& aId)
+ : iId(aId), iNumFastTicks(0)
+ {
+ }
+
+MBtraceCpuUsageObserver::TCpuUsage::TCpuUsage(const TBtraceThreadId& aId, const TBtraceTickCount& aTickCount)
+ : iId(aId), iNumFastTicks(0), iSwitchedInAt(aTickCount)
+ {
+ }
+
+EXPORT_C CBtraceCpuUsage* CBtraceCpuUsage::NewL(CBtraceReader& aReader, CBtraceContext& aContext)
+ {
+ CBtraceCpuUsage* self = new(ELeave) CBtraceCpuUsage(aReader, aContext);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CBtraceCpuUsage::~CBtraceCpuUsage()
+ {
+ while (iCpuUsageNotifs.Count())
+ {
+ iCpuUsageNotifs[0].Close();
+ iCpuUsageNotifs.Remove(0);
+ }
+ iCpuUsageNotifs.Close();
+ iContextSwitchNotifs.Close();
+ iThreadIdleNotifs.Close();
+ iReader.RemoveObserver(BTrace::ECpuUsage, *this);
+ iReader.RemoveObserver(KAmTraceCategory, *this);
+ }
+
+EXPORT_C void CBtraceCpuUsage::NotifyCpuUsageL(TUint32 aNanoTickCount, TTimeIntervalMicroSeconds32 aPeriod, MBtraceCpuUsageObserver& aObserver)
+ {
+ NotifyCpuUsageL(aNanoTickCount, aPeriod, aObserver, ENotificationOneShot);
+ }
+
+EXPORT_C void CBtraceCpuUsage::NotifyCpuUsageL(TUint32 aNanoTickCount, TTimeIntervalMicroSeconds32 aPeriod, MBtraceCpuUsageObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+ {
+ RCpuUsageNotif notif(aNanoTickCount, TBtraceUtils::MicroSecondsToNanoTicks(aPeriod), aObserver, aPersistence);
+ User::LeaveIfError(iCpuUsageNotifs.Append(notif));
+ }
+
+EXPORT_C void CBtraceCpuUsage::NotifyContextSwitchL(const TBtraceThreadId& aId, MBtraceCpuUsageObserver& aObserver)
+ {
+ TContextSwitchNotif notif(aId, aObserver);
+ User::LeaveIfError(iContextSwitchNotifs.InsertInUnsignedKeyOrderAllowRepeats(notif));
+ }
+
+EXPORT_C void CBtraceCpuUsage::NotifyThreadIdleL(const TBtraceThreadId& aId, const TBtraceTickCount& aFromTickCount, TTimeIntervalMicroSeconds32 aPeriod, MBtraceCpuUsageObserver& aObserver)
+ {
+ NotifyThreadIdleL(aId, aFromTickCount, aPeriod, aObserver, ENotificationOneShot);
+ }
+
+EXPORT_C void CBtraceCpuUsage::NotifyThreadIdleL(const TBtraceThreadId& aId, const TBtraceTickCount& aFromTickCount, TTimeIntervalMicroSeconds32 aPeriod, MBtraceCpuUsageObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+ {
+ TThreadIdleNotif notif(aId, aFromTickCount, TBtraceUtils::MicroSecondsToNanoTicks(aPeriod), aObserver, aPersistence);
+ User::LeaveIfError(iThreadIdleNotifs.InsertInUnsignedKeyOrderAllowRepeats(notif));
+ }
+
+EXPORT_C void CBtraceCpuUsage::CancelNotifyThreadIdle(MBtraceCpuUsageObserver& aObserver)
+ {
+ for (TInt i = iThreadIdleNotifs.Count()-1; i>=0; --i)
+ {
+ if (iThreadIdleNotifs[i].iObserver == &aObserver)
+ {
+ iThreadIdleNotifs.Remove(i);
+ }
+ }
+ }
+
+CBtraceCpuUsage::CBtraceCpuUsage(CBtraceReader& aReader, CBtraceContext& aContext)
+ : iReader(aReader), iContext(aContext)
+ {
+ }
+
+void CBtraceCpuUsage::ConstructL()
+ {
+ iReader.AddObserverL(BTrace::ECpuUsage, *this);
+ iReader.AddObserverL(KAmTraceCategory, *this); // To ensure we get heartbeat and sync frames, which are needed to flush through and force TestThreadIdlenessL to be called
+ }
+
+void CBtraceCpuUsage::HandleBtraceFrameL(const TBtraceFrame& aFrame)
+ {
+ if (aFrame.iCategory == BTrace::ECpuUsage)
+ {
+ switch (aFrame.iSubCategory)
+ {
+ case BTrace::ENewThreadContext:
+ {
+ ++iNumProcessedFrames;
+ const TBtraceThreadId* btraceThreadId = iContext.FindThread(aFrame.iThreadContext);
+// __ASSERT_ALWAYS(btraceThreadId, Panic(EBtpPanicUnknownCpuContext));
+ if (btraceThreadId)
+ {
+ HandleContextSwitchL(aFrame.iTickCount, *btraceThreadId);
+ }
+ else
+ {
+ iReader.Log(_L("BTrace::ENewThreadContext: Unknown thread context 0x%08x\r\n"), aFrame.iThreadContext);
+ }
+ break;
+ }
+ default:
+ {
+ // Ignore anything we don't know about.
+ ++iNumIgnoredFrames;
+ break;
+ }
+ }
+ }
+
+ TestCpuUsagePeriodL(aFrame.iTickCount);
+ TestThreadIdlenessL(aFrame.iTickCount);
+ }
+
+CBtraceCpuUsage::RCpuUsageNotif::RCpuUsageNotif(TUint32 aStartTickCount, TUint32 aNumNanoTicks, MBtraceCpuUsageObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+ : iStartTickCount(aStartTickCount), iNumNanoTicks(aNumNanoTicks), iObserver(&aObserver), iPersistence(aPersistence)
+ {
+ }
+
+void CBtraceCpuUsage::RCpuUsageNotif::RCpuUsageNotif::Close()
+ {
+ iUsage.Close();
+ }
+
+CBtraceCpuUsage::TContextSwitchNotif::TContextSwitchNotif(const TBtraceThreadId& aId)
+ : iId(aId), iObserver(NULL)
+ {
+ }
+
+CBtraceCpuUsage::TContextSwitchNotif::TContextSwitchNotif(const TBtraceThreadId& aId, MBtraceCpuUsageObserver& aObserver)
+ : iId(aId), iObserver(&aObserver)
+ {
+ }
+
+CBtraceCpuUsage::TThreadIdleNotif::TThreadIdleNotif(const TBtraceThreadId& aId)
+ : iId(aId), iNumNanoTicks(0), iObserver(NULL), iEverScheduled(EFalse), iPersistence(ENotificationOneShot)
+ {
+ }
+
+CBtraceCpuUsage::TThreadIdleNotif::TThreadIdleNotif(const TBtraceThreadId& aId, const TBtraceTickCount& aFromTickCount, TUint aNumNanoTicks, MBtraceCpuUsageObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+ : iId(aId), iNumNanoTicks(aNumNanoTicks), iObserver(&aObserver), iLastSwitchedOut(aFromTickCount), iEverScheduled(EFalse), iPersistence(aPersistence)
+ {
+ }
+
+void CBtraceCpuUsage::HandleContextSwitchL(const TBtraceTickCount& aTickCount, const TBtraceThreadId& aNewBtraceThreadId)
+ {
+ TBool relevant(EFalse);
+
+ if (iLastBtractThreadId.Value() != 0)
+ {
+ // Update CPU usage notifications for the thread that has been switched out.
+ for (TInt i = (iCpuUsageNotifs.Count() - 1); i >= 0; --i)
+ {
+ RCpuUsageNotif& notif = iCpuUsageNotifs[i];
+ TInt pos = notif.iUsage.FindInUnsignedKeyOrder(MBtraceCpuUsageObserver::TCpuUsage(iLastBtractThreadId));
+ if (pos >= 0)
+ {
+ MBtraceCpuUsageObserver::TCpuUsage& usage = notif.iUsage[pos];
+ usage.iNumFastTicks += aTickCount.IntervalInFastTicks(usage.iSwitchedInAt);
+ relevant = ETrue;
+ }
+ }
+ }
+
+ // Update CPU usage notifications to store this tick count at which this thread was switched in.
+ for (TInt i = (iCpuUsageNotifs.Count() - 1); i >= 0; --i)
+ {
+ relevant = ETrue;
+ RCpuUsageNotif& notif = iCpuUsageNotifs[i];
+ TInt pos = notif.iUsage.FindInUnsignedKeyOrder(aNewBtraceThreadId);
+ if (pos == KErrNotFound)
+ {
+ MBtraceCpuUsageObserver::TCpuUsage cpuUsage(aNewBtraceThreadId, aTickCount);
+ TInt err = notif.iUsage.InsertInUnsignedKeyOrder(cpuUsage);
+ __ASSERT_ALWAYS(err == KErrNone, Panic(EBtpPanicFailedToInsertCpuUsageObject));
+ }
+ else
+ {
+ notif.iUsage[pos].iSwitchedInAt = aTickCount;
+ }
+ }
+
+ // Inform context switch observers that are interested in switches from the previous thread.
+ TInt pos = iContextSwitchNotifs.SpecificFindInUnsignedKeyOrder(TContextSwitchNotif(iLastBtractThreadId), EArrayFindMode_First);
+ if (pos >= 0)
+ {
+ const TInt numNotifs = iContextSwitchNotifs.Count();
+ for (TInt i = 0; i < numNotifs; ++i)
+ {
+ const TContextSwitchNotif& thisNotif = iContextSwitchNotifs[i];
+ if (thisNotif.iId == iLastBtractThreadId)
+ {
+ relevant = ETrue;
+ thisNotif.iObserver->HandleContextSwitchL(aTickCount, iLastBtractThreadId, MBtraceCpuUsageObserver::EFromThisThread);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ // Inform context switch observers that are interested in switches to this new thread.
+ pos = iContextSwitchNotifs.SpecificFindInUnsignedKeyOrder(TContextSwitchNotif(aNewBtraceThreadId), EArrayFindMode_First);
+ if (pos >= 0)
+ {
+ const TInt numNotifs = iContextSwitchNotifs.Count();
+ for (TInt i = pos; i < numNotifs; ++i)
+ {
+ const TContextSwitchNotif& thisNotif = iContextSwitchNotifs[i];
+ if (thisNotif.iId == aNewBtraceThreadId)
+ {
+ relevant = ETrue;
+ thisNotif.iObserver->HandleContextSwitchL(aTickCount, aNewBtraceThreadId, MBtraceCpuUsageObserver::EToThisThread);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ // Update thread idle notifications' last switched out time.
+ pos = iThreadIdleNotifs.SpecificFindInUnsignedKeyOrder(TThreadIdleNotif(iLastBtractThreadId), EArrayFindMode_First);
+ if (pos >= 0)
+ {
+ const TInt numNotifs = iThreadIdleNotifs.Count();
+ for (TInt i = pos; i < numNotifs; ++i)
+ {
+ TThreadIdleNotif& thisNotif = iThreadIdleNotifs[i];
+ if (thisNotif.iId == iLastBtractThreadId)
+ {
+ relevant = ETrue;
+ thisNotif.iLastSwitchedOut = aTickCount;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ // Update thread idle notifications' ever scheduled.
+ pos = iThreadIdleNotifs.SpecificFindInUnsignedKeyOrder(TThreadIdleNotif(aNewBtraceThreadId), EArrayFindMode_First);
+ if (pos >= 0)
+ {
+ const TInt numNotifs = iThreadIdleNotifs.Count();
+ for (TInt i = pos; i < numNotifs; ++i)
+ {
+ TThreadIdleNotif& thisNotif = iThreadIdleNotifs[i];
+ if (thisNotif.iId == aNewBtraceThreadId)
+ {
+ relevant = ETrue;
+ thisNotif.iEverScheduled = ETrue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ iLastBtractThreadId = aNewBtraceThreadId;
+
+ if (relevant)
+ {
+ ++iNumRelevantFrames;
+ }
+ }
+
+TInt CompareUsage(const MBtraceCpuUsageObserver::TCpuUsage& aFirst,const MBtraceCpuUsageObserver::TCpuUsage& aSecond)
+ {
+ if (aFirst.iNumFastTicks > aSecond.iNumFastTicks)
+ {
+ return -1;
+ }
+ else if (aFirst.iNumFastTicks < aSecond.iNumFastTicks)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+void CBtraceCpuUsage::TestCpuUsagePeriodL(const TBtraceTickCount& aTickCount)
+ {
+ for (TInt i = (iCpuUsageNotifs.Count() - 1); i >= 0; --i)
+ {
+ RCpuUsageNotif& thisNotif = iCpuUsageNotifs[i];
+ if ((aTickCount.iNano - thisNotif.iStartTickCount) >= thisNotif.iNumNanoTicks)
+ {
+ thisNotif.iUsage.Sort(TLinearOrder<MBtraceCpuUsageObserver::TCpuUsage>(CompareUsage));
+ TArray<MBtraceCpuUsageObserver::TCpuUsage> array(thisNotif.iUsage.Array());
+ thisNotif.iObserver->HandleCpuUsageL(aTickCount, array);
+ if (thisNotif.iPersistence == ENotificationOneShot)
+ {
+ thisNotif.Close();
+ iCpuUsageNotifs.Remove(i);
+ }
+ }
+ }
+ }
+
+void CBtraceCpuUsage::TestThreadIdlenessL(const TBtraceTickCount& aTickCount)
+ {
+ for (TInt i = (iThreadIdleNotifs.Count() - 1); i >= 0; --i)
+ {
+ const TThreadIdleNotif& thisNotif = iThreadIdleNotifs[i];
+ //iReader.Log(_L("CBtraceCpuUsage::TestThreadIdlenessL: now %d, lastswitch %d, remaining %d\r\n"), aTickCount.iNano, thisNotif.iLastSwitchedOut.iNano, thisNotif.iNumNanoTicks - (aTickCount.iNano - thisNotif.iLastSwitchedOut.iNano));
+ if ((aTickCount.iNano > thisNotif.iLastSwitchedOut.iNano) && ((aTickCount.iNano - thisNotif.iLastSwitchedOut.iNano) >= thisNotif.iNumNanoTicks))
+ {
+ MBtraceCpuUsageObserver* observer = thisNotif.iObserver;
+ TBtraceTickCount lastSwitchedOut = thisNotif.iLastSwitchedOut;
+ TBtraceThreadId threadId = thisNotif.iId;
+ MBtraceCpuUsageObserver::TIdleType idleType = thisNotif.iEverScheduled ? MBtraceCpuUsageObserver::EScheduledAtLeastOnce : MBtraceCpuUsageObserver::ENeverScheduled;
+
+ if (thisNotif.iPersistence == ENotificationOneShot)
+ {
+ iThreadIdleNotifs.Remove(i);
+ }
+
+ observer->HandleThreadIdleL(lastSwitchedOut, threadId, idleType);
+ }
+ }
+ }