libraries/extrabtrace/src/sampler.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/extrabtrace/src/sampler.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,144 @@
+// sampler.cpp
+// 
+// Copyright (c) 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 "sampler.h"
+#include <fshell/btrace_parser_defs.h>
+#include <fshell/common.mmh>
+
+// Please note this code is NOT SMP-safe. The whole mechanism of using an interrupt doesn't work under SMP so there's no point adding TSpinLocks or similar
+#ifdef __SMP__
+#error "Sampler doesn't work under SMP!"
+#endif
+
+TUint IntStackPtr();
+TUint IDFCRunning();
+
+DCpuSampler::DCpuSampler()
+	: iTimer(NTimer(&Sample, this))
+	{
+#if defined(__MARM__)
+	iIntStackTop=(TUint*)IntStackPtr();
+#endif
+	}
+
+DCpuSampler::~DCpuSampler()
+	{
+	iTimer.Cancel();
+	}
+
+void DCpuSampler::Sample(TAny* aPtr)
+	{
+	static_cast<DCpuSampler*>(aPtr)->DoSample();
+	}
+
+void DCpuSampler::DoSample()
+	{
+	TInt err = iTimer.Again(1);
+	if (err == KErrArgument)
+		{
+		// Missed a tick, oh well
+		iTimer.OneShot(1);
+		}
+
+	NThread* thread = NKern::CurrentThread();
+	if (iCpuUsageCallbackFn)
+		{
+		// Not used by anything in fshell pkg
+		(*iCpuUsageCallbackFn)(iContext, thread);
+		}
+
+	if (iProfiling)
+		{
+		Usample(thread);
+		}
+	iContext = thread;
+	}
+
+TBool DCpuSampler::ShouldRun() const
+	{
+	return iProfiling || iCpuUsageCallbackFn != NULL;
+	}
+
+void DCpuSampler::SettingsChanged()
+	{
+	// Call with interrupts disabled
+	if (ShouldRun())
+		{
+#if FSHELL_PLATFORM_SYMTB >= 92
+		if (!iTimer.IsPending())
+#else
+		if (iTimer.iState == NTimer::EIdle)
+#endif
+			{
+			iContext = NULL;
+			iTimerHeartbeat = 0;
+			iTimer.OneShot(1);
+			}
+		}
+	else
+		{
+		iTimer.Cancel();
+		}
+	}
+
+void DCpuSampler::SetCpuUsageSampling(MExtraBtrace::TCpuUsageCallback aCallbackFn)
+	{
+	TUint irq = NKern::DisableAllInterrupts();
+	iCpuUsageCallbackFn = aCallbackFn;
+	SettingsChanged();
+	NKern::RestoreInterrupts(irq);
+	}
+
+
+void DCpuSampler::SetProfilingSampling(TBool aEnabled)
+	{
+	TUint irq = NKern::DisableAllInterrupts();
+	iProfiling = aEnabled;
+	SettingsChanged();
+	NKern::RestoreInterrupts(irq);
+	}
+
+void DCpuSampler::Usample(NThread* pN)
+	{
+	if (Kern::NThreadToDThread(pN)!=NULL)
+		{
+#if defined(__MARM__)
+		TBool idfcRunning = IDFCRunning();
+		TLinAddr pC=((iIntStackTop)[-1]) & ~1; //clear LSB bit (in case of Jazelle code)
+#else
+		// Can't get this info if we don't have the .cia functions
+		TBool idfcRunning = EFalse;
+		TLinAddr pC = 0;
+#endif
+
+		if (idfcRunning)
+			{
+			//no useful thread context
+			BTrace4(BTrace::EProfiling,BTrace::ECpuIdfcSample,pC);
+			}
+		else
+		    {
+			if (iContext!=pN)
+				{
+				BTrace8(BTrace::EProfiling,BTrace::ECpuFullSample,pC,pN);
+				}
+			else
+				{
+				//optimisation - context of previous sample is assumed
+				BTrace4(BTrace::EProfiling,BTrace::ECpuOptimisedSample,pC);
+				}
+ 		    }
+		}
+	else
+		{
+		BTrace0(BTrace::EProfiling,BTrace::ECpuNonSymbianThreadSample);
+		}
+	}