commands/memsampler/memsamplerdd.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/memsampler/memsamplerdd.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,342 @@
+// memsamplerdd.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 <fshell/extrabtrace.h>
+#include <platform.h>
+#include <kern_priv.h>
+#include "memsamplerdd.h"
+#include <fshell/common.mmh>
+
+const TInt KMinRate = 10;
+const TInt KMaxRate = 10000;
+const TInt KMajorVersionNumber = 1;
+const TInt KMinorVersionNumber = 0;
+const TInt KBuildVersionNumber = 0;
+const TInt KArrayGranularity = 32;
+const TInt KDfcThreadPriority = 26;
+_LIT(KDfcThreadName, "MemSamplerDD");
+
+class DDeviceMemSampler : public DLogicalDevice
+	{
+public:
+	DDeviceMemSampler();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+class TChunkInfo
+	{
+public:
+	TChunkInfo(DChunk& aChunk);
+	TBool operator==(const TChunkInfo& aChunkInfo);
+public:
+	DChunk* iAddress;
+	TInt iSize;
+	TInt iHighWaterMark;
+	TBool iSeen;
+	};
+
+TChunkInfo::TChunkInfo(DChunk& aChunk)
+	: iAddress(&aChunk), iSize(aChunk.Size()), iHighWaterMark(aChunk.Size()), iSeen(ETrue)
+	{
+	}
+
+TBool TChunkInfo::operator==(const TChunkInfo& aChunkInfo)
+	{
+	return (iSize == aChunkInfo.iSize);
+	}
+
+class DMemSamplerChannel : public DLogicalChannel
+	{
+public:
+	DMemSamplerChannel();
+	~DMemSamplerChannel();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual void HandleMsg(TMessageBase* aMsg);
+private:
+	TInt StartSampling(TInt aRate);
+	TInt StopSampling();
+	TInt ResetSampling();
+	TInt ReadChunks();
+	void TraceNewChunk(const TChunkInfo& aChunkInfo) const;
+	void TraceChangedChunk(const TChunkInfo& aChunkInfo) const;
+	void TraceDeletedChunk(const TChunkInfo& aChunkInfo) const;
+	void TraceNewSample() const;
+#if FSHELL_PLATFORM_SYMTB >= 92
+	inline TBool Running()
+		{return iTimer.IsPending();}
+#else
+	inline TBool Running()
+		{return iTimer.iState!=NTimer::EIdle;}
+#endif
+private:
+	static void Sample(TAny*);
+	static void DoSample(TAny*);
+	static void ExitDfcThread(TAny*);
+private:
+	RArray<TChunkInfo> iChunkInfo;
+	NTimer iTimer;
+	TInt iPeriod;
+	TInt iPeriodNumber;
+	TDfcQue iPrivateDfcQ;
+	TDfc iDoSampleDfc;
+	TDfc iExitDfc;
+	DThread* iClient;
+	mutable TBool iNewSampleTraced;
+	};
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DDeviceMemSampler;
+	}
+
+DDeviceMemSampler::DDeviceMemSampler()
+	{
+	iVersion=TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber);
+	}
+
+TInt DDeviceMemSampler::Install()
+	{
+	TInt r = SetName(&KMemSamplerName);
+	return r;
+	}
+
+void DDeviceMemSampler::GetCaps(TDes8&) const
+	{
+	}
+
+TInt DDeviceMemSampler::Create(DLogicalChannelBase*& aChannel)
+	{
+	aChannel = new DMemSamplerChannel;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+DMemSamplerChannel::DMemSamplerChannel()
+	: iChunkInfo(KArrayGranularity, _FOFF(TChunkInfo, iAddress)), iTimer(Sample, this), iPeriodNumber(-1), iDoSampleDfc(DoSample, this, 1), iExitDfc(ExitDfcThread, this, 0), iNewSampleTraced(EFalse)
+	{
+	}
+
+DMemSamplerChannel::~DMemSamplerChannel()
+	{
+	Kern::SafeClose((DObject*&)iClient, NULL);
+	iExitDfc.Enque(); 
+	}
+
+void DMemSamplerChannel::ExitDfcThread(TAny*)
+	{
+	Kern::Exit(KErrNone);
+	} 
+
+TInt DMemSamplerChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+	{
+	if (!Kern::QueryVersionSupported(TVersion(1,0,0),aVer))
+		{
+		return KErrNotSupported;
+		}
+	iClient=&Kern::CurrentThread();
+	iClient->Open();
+	TInt err = Kern::DfcQInit(&iPrivateDfcQ, KDfcThreadPriority, &KDfcThreadName);
+	if (err == KErrNone)
+		{
+    	SetDfcQ(&iPrivateDfcQ);
+		iDoSampleDfc.SetDfcQ(&iPrivateDfcQ);
+		iExitDfc.SetDfcQ(&iPrivateDfcQ);
+    	iMsgQ.Receive();		
+		}
+	
+	return err;
+	}
+
+TInt DMemSamplerChannel::StartSampling(TInt aRate)
+	{
+	DEBUG_MEMSAMPLER(Kern::Printf("START");)
+	ReadChunks();
+	aRate = Min(KMaxRate, Max(KMinRate, aRate));
+	iPeriod = NKern::TimerTicks(aRate);
+	if (!Running())
+		{
+		iTimer.OneShot(iPeriod, EFalse);
+		}
+	DEBUG_MEMSAMPLER(Kern::Printf("START end");)
+	return KErrNone;
+	}
+
+TInt DMemSamplerChannel::StopSampling()
+	{
+	DEBUG_MEMSAMPLER(Kern::Printf("STOP");)
+	if (Running())
+		{
+		iTimer.Cancel();
+		}
+	DEBUG_MEMSAMPLER(Kern::Printf("STOP end");)
+	return KErrNone;
+	}
+
+TInt DMemSamplerChannel::ResetSampling()
+	{
+	DEBUG_MEMSAMPLER(Kern::Printf("RESET");)
+	iChunkInfo.Reset();
+	DEBUG_MEMSAMPLER(Kern::Printf("RESET end");)
+	return KErrNone;
+	}
+
+TInt DMemSamplerChannel::ReadChunks()
+	{
+	++iPeriodNumber;
+	iNewSampleTraced = EFalse;
+
+	for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
+		{
+		iChunkInfo[i].iSeen = EFalse;
+		}
+
+	DObjectCon* const * containers = Kern::Containers();
+	DObjectCon& container = *containers[EChunk];
+	container.Wait();
+
+	for (TInt i = (container.Count() - 1); i >= 0; --i)
+		{
+		TChunkInfo thisChunk(*(DChunk*)container[i]);
+		TInt pos;
+		TInt err = iChunkInfo.FindInUnsignedKeyOrder(thisChunk, pos);
+		if (err == KErrNotFound)
+			{
+			if (pos < iChunkInfo.Count())
+				{
+				iChunkInfo.Insert(thisChunk, pos);
+				}
+			else
+				{
+				TInt err = iChunkInfo.Append(thisChunk);
+				if (err)
+					{
+					container.Signal();
+					return err;
+					}
+				}
+			TraceNewChunk(thisChunk);
+			}
+		else
+			{
+			if (thisChunk == iChunkInfo[pos])
+				{
+				// Chunk size hasn't changed - ignore.
+				iChunkInfo[pos].iSeen = ETrue;
+				}
+			else
+				{
+				TChunkInfo& c = iChunkInfo[pos];
+				if (thisChunk.iSize > c.iHighWaterMark)
+					{
+					c.iHighWaterMark = thisChunk.iSize;
+					}
+				c.iSize = thisChunk.iSize;
+				c.iSeen = ETrue;
+				TraceChangedChunk(c);
+				}
+			}
+		}
+
+	container.Signal();
+
+	for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
+		{
+		const TChunkInfo& chunkInfo = iChunkInfo[i];
+		if (!chunkInfo.iSeen)
+			{
+			TraceDeletedChunk(chunkInfo);
+			iChunkInfo.Remove(i);
+			}
+		}
+
+	return KErrNone;
+	}
+
+void DMemSamplerChannel::TraceNewChunk(const TChunkInfo& aChunkInfo) const
+	{
+	TraceNewSample();
+	TFullName nameBuf;
+	aChunkInfo.iAddress->FullName(nameBuf);				
+	BTraceN(RMemSampler::EBtraceCategory, RMemSampler::ENewChunk, aChunkInfo.iAddress, aChunkInfo.iAddress->MaxSize(), nameBuf.Ptr(), nameBuf.Size());
+	TraceChangedChunk(aChunkInfo);
+	}
+
+void DMemSamplerChannel::TraceChangedChunk(const TChunkInfo& aChunkInfo) const
+	{
+	TraceNewSample();
+	BTraceContext12(RMemSampler::EBtraceCategory, RMemSampler::EChangedChunk, aChunkInfo.iAddress, aChunkInfo.iSize, aChunkInfo.iHighWaterMark);
+	}
+
+void DMemSamplerChannel::TraceDeletedChunk(const TChunkInfo& aChunkInfo) const
+	{
+	TraceNewSample();
+	BTraceContext4(RMemSampler::EBtraceCategory, RMemSampler::EDeletedChunk, aChunkInfo.iAddress);
+	}
+
+void DMemSamplerChannel::TraceNewSample() const
+	{
+	if (!iNewSampleTraced)
+		{
+		iNewSampleTraced = ETrue;
+		BTraceContext8(RMemSampler::EBtraceCategory, RMemSampler::ENewSample, iPeriod, iPeriodNumber);
+		}
+	}
+
+void DMemSamplerChannel::HandleMsg(TMessageBase* aMsg)
+	{
+	TInt r=KErrNone;
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+	TInt id=m.iValue;
+	if (id==(TInt)ECloseMsg)
+		{
+		DEBUG_MEMSAMPLER(Kern::Printf("CLOSE");)
+		iTimer.Cancel();
+		m.Complete(KErrNone,EFalse);
+		iMsgQ.CompleteAll(KErrServerTerminated);
+		DEBUG_MEMSAMPLER(Kern::Printf("CLOSE end");)
+		return;
+		}
+	else
+		{
+		switch(id)
+			{
+			case RMemSampler::EControlStartProfile:
+				r = StartSampling(m.Int0());
+				break;
+			case RMemSampler::EControlStopProfile:
+				r = StopSampling();
+				break;
+			case RMemSampler::EControlResetProfile:
+				r = ResetSampling();
+				break;
+			default:
+				r = KErrNotSupported;
+				break;
+			}
+		}
+	m.Complete(r,ETrue);
+	}
+
+void DMemSamplerChannel::Sample(TAny* aPtr)
+	{
+	DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
+	d.iTimer.Again(d.iPeriod);
+	d.iDoSampleDfc.Add(); 
+	}
+
+void DMemSamplerChannel::DoSample(TAny* aPtr)
+	{
+	DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
+	d.ReadChunks();
+	}