kerneltest/e32utils/analyse/trace.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32utils/analyse/trace.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,393 @@
+// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "analyse.h"
+#include "trace.h"
+#include "nonxip.h"
+#include <memory.h>
+#include <string.h>
+
+#ifdef __MSVCDOTNET__
+#include <strstream>
+#include <fstream>
+#else //!__MSVCDOTNET__
+#include <strstrea.h>
+#include <fstream.h>
+#endif //__MSVCDOTNET__
+
+namespace {
+
+template <class T>
+class Map
+	{
+	enum {KInitialSize = 16};
+	typedef T* Entry;
+public:
+	Map();
+	T* Find(int aId) const;
+	int Add(T& aT);
+private:
+	static void Insert(Entry* aMap, int aSize, T& aT);
+	void Rehash();
+private:
+	Entry* iMap;
+	int iSize;
+	int iCount;
+	int iThreshold;
+	};
+
+template <class T>
+Map<T>::Map()
+	:iMap(0), iSize(0), iCount(0), iThreshold(0)
+	{}
+
+template <class T>
+T* Map<T>::Find(int aId) const
+	{
+	if (iSize == 0)
+		return 0;
+
+	unsigned hash = aId;
+	for (;;)
+		{
+		hash &= (iSize-1);
+		Entry x = iMap[hash];
+		if (x == 0)
+			return 0;
+		if (x->iId == aId)
+			return x;
+		if (x->iId < aId)
+			return 0;
+		++hash;
+		}
+	}
+
+template <class T>
+int Map<T>::Add(T& aT)
+	{
+	if (iCount == iThreshold)
+		Rehash();
+
+	Insert(iMap,iSize,aT);
+	return iCount++;
+	}
+
+template <class T>
+void Map<T>::Rehash()
+	{
+	if (iSize == 0)
+		{
+		iMap = new Entry[KInitialSize];
+		memset(iMap,0,KInitialSize*sizeof(Entry));
+		iSize = KInitialSize;
+		}
+	else
+		{
+		int size = iSize * 2;
+		Entry* map = new Entry[size];
+		memset(map,0,size*sizeof(Entry));
+		for (Entry* p = iMap + iSize; --p >= iMap; )
+			if (*p != 0)
+				Insert(map, size, **p);
+		delete [] iMap;
+		iMap = map;
+		iSize = size;
+		}
+	iThreshold = (iSize * 3) / 4;	// 75%
+	}
+
+template <class T>
+void Map<T>::Insert(typename Map<T>::Entry* aMap, int aSize, T& aT)
+	{
+	Entry e = &aT;
+	unsigned hash = aT.iId;
+	for (;;)
+		{
+		hash &= (aSize-1);
+		Entry x = aMap[hash];
+		if (x == 0)
+			{
+			aMap[hash] = e;
+			return;
+			}
+		if (x->iId < e->iId)
+			{
+			aMap[hash] = e;
+			e = x;
+			}
+		++hash;
+		}
+	}
+
+};	// local namespace
+
+class Decoder
+	{
+public:
+	enum {ELazyIndexThread = -1, EFilteredThread = -2, ENullThread = -3};
+	enum TValid {EOk, EBadFile, EBadVersion};
+public:
+	Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample);
+	TValid Validate();
+	void DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP);
+private:
+	int DecodeInt();
+	unsigned DecodeUint();
+	char* DecodeName();
+	const Process* DecodeProcess();
+	Thread* DecodeThread();
+private:
+	unsigned iBegin;
+	unsigned iEnd;
+	const TraceData* iTrace;
+	const TraceData* iLimit;
+	Map<Process> iProcesses;
+	Map<Thread> iThreads;
+public:
+	unsigned iSamples;
+	unsigned iActive;
+	};
+
+Decoder::Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample)
+	:iBegin(aBeginSample), iEnd(aEndSample),
+	iTrace(aTrace), iLimit(aTrace + aLength),
+	iSamples(0), iActive(0)
+	{}
+
+int Decoder::DecodeInt()
+	{
+	int val = 0;
+	int shift = 0;
+	unsigned byte;
+	do
+		{
+		byte = *iTrace++;
+		val |= (byte & 0x7f) << shift;
+		shift += 7;
+		} while ((byte & 0x80) == 0);
+	if (shift < 32)
+		{	// sign extend
+		shift = 32 - shift;
+		val = val << shift >> shift;
+		}
+	return val;
+	}
+
+unsigned Decoder::DecodeUint()
+	{
+	unsigned val = 0;
+	int shift = 0;
+	unsigned byte;
+	do
+		{
+		byte = *iTrace++;
+		val |= (byte & 0x7f) << shift;
+		shift += 7;
+		} while ((byte & 0x80) == 0);
+	return val;
+	}
+
+char* Decoder::DecodeName()
+	{
+	int len = *iTrace++;
+	char* name = new char[len+1];
+	memcpy(name, iTrace, len);
+	name[len] = '\0';
+	iTrace += len;
+	return name;
+	}
+
+const Process* Decoder::DecodeProcess()
+	{
+	int pid = DecodeUint();
+	const Process* p = iProcesses.Find(pid);
+	if (p)
+		return p;
+
+	Process* np = new Process;
+	np->iId = pid;
+	np->iName = DecodeName();
+	iProcesses.Add(*np);
+	return np;
+	}
+
+Thread* Decoder::DecodeThread()
+	{
+	int tid = DecodeUint();
+	Thread* t = iThreads.Find(tid);
+	if (t)
+		return t;
+
+	const Process* p = DecodeProcess();
+	char* name = DecodeName();
+	Thread* nt = new Thread;
+	nt->iId = tid;
+	nt->iName = name;
+	nt->iProcess = p;
+	iThreads.Add(*nt);
+	if (!Analyse::Option(Analyse::ENull) && stricmp(name,"NULL") == 0)
+		{
+		nt->iIndex = ENullThread;
+		return nt;
+		}
+	else
+		{
+		strstream s;
+		s << p->iName << "::" << name << '\0';
+		if (Analyse::Match(s.str(), Analyse::sThread))
+			nt->iIndex = ELazyIndexThread;
+		else
+			nt->iIndex = EFilteredThread;
+		}
+	return nt;
+	}
+	
+Decoder::TValid Decoder::Validate()
+//
+// Check the trace header
+//
+	{
+	char* tag = DecodeName();
+	int check = strcmp(tag, "profile");
+	delete [] tag;
+	if (check != 0)
+		return EBadFile;
+	int ver = DecodeUint();
+	if (ver != MajorVersion)
+		return EBadVersion;
+	return EOk;
+	}
+
+void Decoder::DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP)
+	{
+	PC pc = 0;
+	Thread* thread = 0;
+	int sample = 0;
+	int threadIndexer = 0;
+	while (iTrace < iLimit && sample < iEnd)
+		{
+		int count = 1;
+		int diff = DecodeInt();
+		if (diff & 1)
+			{
+			diff &= ~1;
+			thread = DecodeThread();
+			}
+		else if (diff == 0)
+			{
+			unsigned int next = DecodeUint();
+			if (next != 0) 
+				count = next;
+			else	// non-XIP
+				{
+				next = DecodeUint();
+				if (next == 0) // footer
+					{
+					aNonXIP->iRowBufferErrors = DecodeUint();
+					aNonXIP->iCookBufferErrors = DecodeUint();
+					aNonXIP->iReportMask = DecodeUint();
+					}
+				else if (next & 1) // segment deletion
+					{
+					PC address = next & ~1;
+					aNonXIP->DeleteSegment(address);
+					}
+				else	// segment creation
+					{
+					PC address = next;
+					PC seg_size = DecodeUint();
+					char * seg_name = DecodeName();
+					aNonXIP->AddSegment(address, seg_size, seg_name + 3);
+					}
+				continue;
+				}
+			}
+		pc += diff;
+		while (--count >= 0)
+			{
+			if (sample >= iBegin)
+				{
+				++iSamples;
+				if (thread->iIndex != ENullThread)
+					++iActive;
+				if (thread->iIndex >= ELazyIndexThread)
+					{
+					if (thread->iIndex == ELazyIndexThread)
+						thread->iIndex = threadIndexer++;
+					aSampler.Sample(sample, *thread, pc);
+					}
+				}
+			if (++sample >= iEnd)
+				break;
+			}
+		}
+	}
+
+Trace::Trace()
+	:iTrace(0), iLength(0), iDecoder(0)
+	{}
+
+Trace::~Trace()
+	{
+	delete [] iTrace;
+	delete iDecoder;
+	}
+
+void Trace::Load(const char* aTraceFile, unsigned aBegin, unsigned aEnd)
+	{
+	ifstream file;
+#ifdef __MSVCDOTNET__
+	file.open(aTraceFile, ios::binary);
+#else //!__MSVCDOTNET__
+	file.open(aTraceFile, ios::nocreate | ios::binary);
+#endif //__MSVCDOTNET__
+	if (!file)
+		{
+		cerr << "Unable to open trace file '" << aTraceFile << '\'' << endl;
+		Analyse::Abort();
+		}
+//
+	file.seekg(0, ios::end);
+	iLength = file.tellg();
+//
+	iTrace = new TraceData[iLength];
+	file.seekg(0, ios::beg);
+	file.read(reinterpret_cast<char *>(iTrace), iLength);
+//
+	file.close();
+//
+	iDecoder = new Decoder(iTrace, iLength, aBegin, aEnd);
+	switch (iDecoder->Validate())
+		{
+	case Decoder::EOk:
+		break;
+	case Decoder::EBadFile:
+		cerr << "'" << aTraceFile << "' is not a valid trace file" << endl;
+		Analyse::Abort();
+		break;
+	case Decoder::EBadVersion:
+		Analyse::Abort("Trace file version not supported");
+		break;
+		}
+	}
+
+void Trace::Decode(Sampler& aSampler, NonXIP* aNonXIP)
+	{
+	iDecoder->DecodeTrace(aSampler, aNonXIP);
+	aSampler.Complete(iDecoder->iSamples, iDecoder->iActive);
+	}
+
+
+