kerneltest/e32utils/analyse/trace.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "analyse.h"
       
    17 #include "trace.h"
       
    18 #include "nonxip.h"
       
    19 #include <memory.h>
       
    20 #include <string.h>
       
    21 
       
    22 #ifdef __MSVCDOTNET__
       
    23 #include <strstream>
       
    24 #include <fstream>
       
    25 #else //!__MSVCDOTNET__
       
    26 #include <strstrea.h>
       
    27 #include <fstream.h>
       
    28 #endif //__MSVCDOTNET__
       
    29 
       
    30 namespace {
       
    31 
       
    32 template <class T>
       
    33 class Map
       
    34 	{
       
    35 	enum {KInitialSize = 16};
       
    36 	typedef T* Entry;
       
    37 public:
       
    38 	Map();
       
    39 	T* Find(int aId) const;
       
    40 	int Add(T& aT);
       
    41 private:
       
    42 	static void Insert(Entry* aMap, int aSize, T& aT);
       
    43 	void Rehash();
       
    44 private:
       
    45 	Entry* iMap;
       
    46 	int iSize;
       
    47 	int iCount;
       
    48 	int iThreshold;
       
    49 	};
       
    50 
       
    51 template <class T>
       
    52 Map<T>::Map()
       
    53 	:iMap(0), iSize(0), iCount(0), iThreshold(0)
       
    54 	{}
       
    55 
       
    56 template <class T>
       
    57 T* Map<T>::Find(int aId) const
       
    58 	{
       
    59 	if (iSize == 0)
       
    60 		return 0;
       
    61 
       
    62 	unsigned hash = aId;
       
    63 	for (;;)
       
    64 		{
       
    65 		hash &= (iSize-1);
       
    66 		Entry x = iMap[hash];
       
    67 		if (x == 0)
       
    68 			return 0;
       
    69 		if (x->iId == aId)
       
    70 			return x;
       
    71 		if (x->iId < aId)
       
    72 			return 0;
       
    73 		++hash;
       
    74 		}
       
    75 	}
       
    76 
       
    77 template <class T>
       
    78 int Map<T>::Add(T& aT)
       
    79 	{
       
    80 	if (iCount == iThreshold)
       
    81 		Rehash();
       
    82 
       
    83 	Insert(iMap,iSize,aT);
       
    84 	return iCount++;
       
    85 	}
       
    86 
       
    87 template <class T>
       
    88 void Map<T>::Rehash()
       
    89 	{
       
    90 	if (iSize == 0)
       
    91 		{
       
    92 		iMap = new Entry[KInitialSize];
       
    93 		memset(iMap,0,KInitialSize*sizeof(Entry));
       
    94 		iSize = KInitialSize;
       
    95 		}
       
    96 	else
       
    97 		{
       
    98 		int size = iSize * 2;
       
    99 		Entry* map = new Entry[size];
       
   100 		memset(map,0,size*sizeof(Entry));
       
   101 		for (Entry* p = iMap + iSize; --p >= iMap; )
       
   102 			if (*p != 0)
       
   103 				Insert(map, size, **p);
       
   104 		delete [] iMap;
       
   105 		iMap = map;
       
   106 		iSize = size;
       
   107 		}
       
   108 	iThreshold = (iSize * 3) / 4;	// 75%
       
   109 	}
       
   110 
       
   111 template <class T>
       
   112 void Map<T>::Insert(typename Map<T>::Entry* aMap, int aSize, T& aT)
       
   113 	{
       
   114 	Entry e = &aT;
       
   115 	unsigned hash = aT.iId;
       
   116 	for (;;)
       
   117 		{
       
   118 		hash &= (aSize-1);
       
   119 		Entry x = aMap[hash];
       
   120 		if (x == 0)
       
   121 			{
       
   122 			aMap[hash] = e;
       
   123 			return;
       
   124 			}
       
   125 		if (x->iId < e->iId)
       
   126 			{
       
   127 			aMap[hash] = e;
       
   128 			e = x;
       
   129 			}
       
   130 		++hash;
       
   131 		}
       
   132 	}
       
   133 
       
   134 };	// local namespace
       
   135 
       
   136 class Decoder
       
   137 	{
       
   138 public:
       
   139 	enum {ELazyIndexThread = -1, EFilteredThread = -2, ENullThread = -3};
       
   140 	enum TValid {EOk, EBadFile, EBadVersion};
       
   141 public:
       
   142 	Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample);
       
   143 	TValid Validate();
       
   144 	void DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP);
       
   145 private:
       
   146 	int DecodeInt();
       
   147 	unsigned DecodeUint();
       
   148 	char* DecodeName();
       
   149 	const Process* DecodeProcess();
       
   150 	Thread* DecodeThread();
       
   151 private:
       
   152 	unsigned iBegin;
       
   153 	unsigned iEnd;
       
   154 	const TraceData* iTrace;
       
   155 	const TraceData* iLimit;
       
   156 	Map<Process> iProcesses;
       
   157 	Map<Thread> iThreads;
       
   158 public:
       
   159 	unsigned iSamples;
       
   160 	unsigned iActive;
       
   161 	};
       
   162 
       
   163 Decoder::Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample)
       
   164 	:iBegin(aBeginSample), iEnd(aEndSample),
       
   165 	iTrace(aTrace), iLimit(aTrace + aLength),
       
   166 	iSamples(0), iActive(0)
       
   167 	{}
       
   168 
       
   169 int Decoder::DecodeInt()
       
   170 	{
       
   171 	int val = 0;
       
   172 	int shift = 0;
       
   173 	unsigned byte;
       
   174 	do
       
   175 		{
       
   176 		byte = *iTrace++;
       
   177 		val |= (byte & 0x7f) << shift;
       
   178 		shift += 7;
       
   179 		} while ((byte & 0x80) == 0);
       
   180 	if (shift < 32)
       
   181 		{	// sign extend
       
   182 		shift = 32 - shift;
       
   183 		val = val << shift >> shift;
       
   184 		}
       
   185 	return val;
       
   186 	}
       
   187 
       
   188 unsigned Decoder::DecodeUint()
       
   189 	{
       
   190 	unsigned val = 0;
       
   191 	int shift = 0;
       
   192 	unsigned byte;
       
   193 	do
       
   194 		{
       
   195 		byte = *iTrace++;
       
   196 		val |= (byte & 0x7f) << shift;
       
   197 		shift += 7;
       
   198 		} while ((byte & 0x80) == 0);
       
   199 	return val;
       
   200 	}
       
   201 
       
   202 char* Decoder::DecodeName()
       
   203 	{
       
   204 	int len = *iTrace++;
       
   205 	char* name = new char[len+1];
       
   206 	memcpy(name, iTrace, len);
       
   207 	name[len] = '\0';
       
   208 	iTrace += len;
       
   209 	return name;
       
   210 	}
       
   211 
       
   212 const Process* Decoder::DecodeProcess()
       
   213 	{
       
   214 	int pid = DecodeUint();
       
   215 	const Process* p = iProcesses.Find(pid);
       
   216 	if (p)
       
   217 		return p;
       
   218 
       
   219 	Process* np = new Process;
       
   220 	np->iId = pid;
       
   221 	np->iName = DecodeName();
       
   222 	iProcesses.Add(*np);
       
   223 	return np;
       
   224 	}
       
   225 
       
   226 Thread* Decoder::DecodeThread()
       
   227 	{
       
   228 	int tid = DecodeUint();
       
   229 	Thread* t = iThreads.Find(tid);
       
   230 	if (t)
       
   231 		return t;
       
   232 
       
   233 	const Process* p = DecodeProcess();
       
   234 	char* name = DecodeName();
       
   235 	Thread* nt = new Thread;
       
   236 	nt->iId = tid;
       
   237 	nt->iName = name;
       
   238 	nt->iProcess = p;
       
   239 	iThreads.Add(*nt);
       
   240 	if (!Analyse::Option(Analyse::ENull) && stricmp(name,"NULL") == 0)
       
   241 		{
       
   242 		nt->iIndex = ENullThread;
       
   243 		return nt;
       
   244 		}
       
   245 	else
       
   246 		{
       
   247 		strstream s;
       
   248 		s << p->iName << "::" << name << '\0';
       
   249 		if (Analyse::Match(s.str(), Analyse::sThread))
       
   250 			nt->iIndex = ELazyIndexThread;
       
   251 		else
       
   252 			nt->iIndex = EFilteredThread;
       
   253 		}
       
   254 	return nt;
       
   255 	}
       
   256 	
       
   257 Decoder::TValid Decoder::Validate()
       
   258 //
       
   259 // Check the trace header
       
   260 //
       
   261 	{
       
   262 	char* tag = DecodeName();
       
   263 	int check = strcmp(tag, "profile");
       
   264 	delete [] tag;
       
   265 	if (check != 0)
       
   266 		return EBadFile;
       
   267 	int ver = DecodeUint();
       
   268 	if (ver != MajorVersion)
       
   269 		return EBadVersion;
       
   270 	return EOk;
       
   271 	}
       
   272 
       
   273 void Decoder::DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP)
       
   274 	{
       
   275 	PC pc = 0;
       
   276 	Thread* thread = 0;
       
   277 	int sample = 0;
       
   278 	int threadIndexer = 0;
       
   279 	while (iTrace < iLimit && sample < iEnd)
       
   280 		{
       
   281 		int count = 1;
       
   282 		int diff = DecodeInt();
       
   283 		if (diff & 1)
       
   284 			{
       
   285 			diff &= ~1;
       
   286 			thread = DecodeThread();
       
   287 			}
       
   288 		else if (diff == 0)
       
   289 			{
       
   290 			unsigned int next = DecodeUint();
       
   291 			if (next != 0) 
       
   292 				count = next;
       
   293 			else	// non-XIP
       
   294 				{
       
   295 				next = DecodeUint();
       
   296 				if (next == 0) // footer
       
   297 					{
       
   298 					aNonXIP->iRowBufferErrors = DecodeUint();
       
   299 					aNonXIP->iCookBufferErrors = DecodeUint();
       
   300 					aNonXIP->iReportMask = DecodeUint();
       
   301 					}
       
   302 				else if (next & 1) // segment deletion
       
   303 					{
       
   304 					PC address = next & ~1;
       
   305 					aNonXIP->DeleteSegment(address);
       
   306 					}
       
   307 				else	// segment creation
       
   308 					{
       
   309 					PC address = next;
       
   310 					PC seg_size = DecodeUint();
       
   311 					char * seg_name = DecodeName();
       
   312 					aNonXIP->AddSegment(address, seg_size, seg_name + 3);
       
   313 					}
       
   314 				continue;
       
   315 				}
       
   316 			}
       
   317 		pc += diff;
       
   318 		while (--count >= 0)
       
   319 			{
       
   320 			if (sample >= iBegin)
       
   321 				{
       
   322 				++iSamples;
       
   323 				if (thread->iIndex != ENullThread)
       
   324 					++iActive;
       
   325 				if (thread->iIndex >= ELazyIndexThread)
       
   326 					{
       
   327 					if (thread->iIndex == ELazyIndexThread)
       
   328 						thread->iIndex = threadIndexer++;
       
   329 					aSampler.Sample(sample, *thread, pc);
       
   330 					}
       
   331 				}
       
   332 			if (++sample >= iEnd)
       
   333 				break;
       
   334 			}
       
   335 		}
       
   336 	}
       
   337 
       
   338 Trace::Trace()
       
   339 	:iTrace(0), iLength(0), iDecoder(0)
       
   340 	{}
       
   341 
       
   342 Trace::~Trace()
       
   343 	{
       
   344 	delete [] iTrace;
       
   345 	delete iDecoder;
       
   346 	}
       
   347 
       
   348 void Trace::Load(const char* aTraceFile, unsigned aBegin, unsigned aEnd)
       
   349 	{
       
   350 	ifstream file;
       
   351 #ifdef __MSVCDOTNET__
       
   352 	file.open(aTraceFile, ios::binary);
       
   353 #else //!__MSVCDOTNET__
       
   354 	file.open(aTraceFile, ios::nocreate | ios::binary);
       
   355 #endif //__MSVCDOTNET__
       
   356 	if (!file)
       
   357 		{
       
   358 		cerr << "Unable to open trace file '" << aTraceFile << '\'' << endl;
       
   359 		Analyse::Abort();
       
   360 		}
       
   361 //
       
   362 	file.seekg(0, ios::end);
       
   363 	iLength = file.tellg();
       
   364 //
       
   365 	iTrace = new TraceData[iLength];
       
   366 	file.seekg(0, ios::beg);
       
   367 	file.read(reinterpret_cast<char *>(iTrace), iLength);
       
   368 //
       
   369 	file.close();
       
   370 //
       
   371 	iDecoder = new Decoder(iTrace, iLength, aBegin, aEnd);
       
   372 	switch (iDecoder->Validate())
       
   373 		{
       
   374 	case Decoder::EOk:
       
   375 		break;
       
   376 	case Decoder::EBadFile:
       
   377 		cerr << "'" << aTraceFile << "' is not a valid trace file" << endl;
       
   378 		Analyse::Abort();
       
   379 		break;
       
   380 	case Decoder::EBadVersion:
       
   381 		Analyse::Abort("Trace file version not supported");
       
   382 		break;
       
   383 		}
       
   384 	}
       
   385 
       
   386 void Trace::Decode(Sampler& aSampler, NonXIP* aNonXIP)
       
   387 	{
       
   388 	iDecoder->DecodeTrace(aSampler, aNonXIP);
       
   389 	aSampler.Complete(iDecoder->iSamples, iDecoder->iActive);
       
   390 	}
       
   391 
       
   392 
       
   393