Migrated the writing fshell commands guide to the wiki.
// 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);
}
}
}