1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32utils/analyse/trace.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,393 @@
1.4 +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "analyse.h"
1.20 +#include "trace.h"
1.21 +#include "nonxip.h"
1.22 +#include <memory.h>
1.23 +#include <string.h>
1.24 +
1.25 +#ifdef __MSVCDOTNET__
1.26 +#include <strstream>
1.27 +#include <fstream>
1.28 +#else //!__MSVCDOTNET__
1.29 +#include <strstrea.h>
1.30 +#include <fstream.h>
1.31 +#endif //__MSVCDOTNET__
1.32 +
1.33 +namespace {
1.34 +
1.35 +template <class T>
1.36 +class Map
1.37 + {
1.38 + enum {KInitialSize = 16};
1.39 + typedef T* Entry;
1.40 +public:
1.41 + Map();
1.42 + T* Find(int aId) const;
1.43 + int Add(T& aT);
1.44 +private:
1.45 + static void Insert(Entry* aMap, int aSize, T& aT);
1.46 + void Rehash();
1.47 +private:
1.48 + Entry* iMap;
1.49 + int iSize;
1.50 + int iCount;
1.51 + int iThreshold;
1.52 + };
1.53 +
1.54 +template <class T>
1.55 +Map<T>::Map()
1.56 + :iMap(0), iSize(0), iCount(0), iThreshold(0)
1.57 + {}
1.58 +
1.59 +template <class T>
1.60 +T* Map<T>::Find(int aId) const
1.61 + {
1.62 + if (iSize == 0)
1.63 + return 0;
1.64 +
1.65 + unsigned hash = aId;
1.66 + for (;;)
1.67 + {
1.68 + hash &= (iSize-1);
1.69 + Entry x = iMap[hash];
1.70 + if (x == 0)
1.71 + return 0;
1.72 + if (x->iId == aId)
1.73 + return x;
1.74 + if (x->iId < aId)
1.75 + return 0;
1.76 + ++hash;
1.77 + }
1.78 + }
1.79 +
1.80 +template <class T>
1.81 +int Map<T>::Add(T& aT)
1.82 + {
1.83 + if (iCount == iThreshold)
1.84 + Rehash();
1.85 +
1.86 + Insert(iMap,iSize,aT);
1.87 + return iCount++;
1.88 + }
1.89 +
1.90 +template <class T>
1.91 +void Map<T>::Rehash()
1.92 + {
1.93 + if (iSize == 0)
1.94 + {
1.95 + iMap = new Entry[KInitialSize];
1.96 + memset(iMap,0,KInitialSize*sizeof(Entry));
1.97 + iSize = KInitialSize;
1.98 + }
1.99 + else
1.100 + {
1.101 + int size = iSize * 2;
1.102 + Entry* map = new Entry[size];
1.103 + memset(map,0,size*sizeof(Entry));
1.104 + for (Entry* p = iMap + iSize; --p >= iMap; )
1.105 + if (*p != 0)
1.106 + Insert(map, size, **p);
1.107 + delete [] iMap;
1.108 + iMap = map;
1.109 + iSize = size;
1.110 + }
1.111 + iThreshold = (iSize * 3) / 4; // 75%
1.112 + }
1.113 +
1.114 +template <class T>
1.115 +void Map<T>::Insert(typename Map<T>::Entry* aMap, int aSize, T& aT)
1.116 + {
1.117 + Entry e = &aT;
1.118 + unsigned hash = aT.iId;
1.119 + for (;;)
1.120 + {
1.121 + hash &= (aSize-1);
1.122 + Entry x = aMap[hash];
1.123 + if (x == 0)
1.124 + {
1.125 + aMap[hash] = e;
1.126 + return;
1.127 + }
1.128 + if (x->iId < e->iId)
1.129 + {
1.130 + aMap[hash] = e;
1.131 + e = x;
1.132 + }
1.133 + ++hash;
1.134 + }
1.135 + }
1.136 +
1.137 +}; // local namespace
1.138 +
1.139 +class Decoder
1.140 + {
1.141 +public:
1.142 + enum {ELazyIndexThread = -1, EFilteredThread = -2, ENullThread = -3};
1.143 + enum TValid {EOk, EBadFile, EBadVersion};
1.144 +public:
1.145 + Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample);
1.146 + TValid Validate();
1.147 + void DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP);
1.148 +private:
1.149 + int DecodeInt();
1.150 + unsigned DecodeUint();
1.151 + char* DecodeName();
1.152 + const Process* DecodeProcess();
1.153 + Thread* DecodeThread();
1.154 +private:
1.155 + unsigned iBegin;
1.156 + unsigned iEnd;
1.157 + const TraceData* iTrace;
1.158 + const TraceData* iLimit;
1.159 + Map<Process> iProcesses;
1.160 + Map<Thread> iThreads;
1.161 +public:
1.162 + unsigned iSamples;
1.163 + unsigned iActive;
1.164 + };
1.165 +
1.166 +Decoder::Decoder(const TraceData* aTrace, int aLength, unsigned aBeginSample, unsigned aEndSample)
1.167 + :iBegin(aBeginSample), iEnd(aEndSample),
1.168 + iTrace(aTrace), iLimit(aTrace + aLength),
1.169 + iSamples(0), iActive(0)
1.170 + {}
1.171 +
1.172 +int Decoder::DecodeInt()
1.173 + {
1.174 + int val = 0;
1.175 + int shift = 0;
1.176 + unsigned byte;
1.177 + do
1.178 + {
1.179 + byte = *iTrace++;
1.180 + val |= (byte & 0x7f) << shift;
1.181 + shift += 7;
1.182 + } while ((byte & 0x80) == 0);
1.183 + if (shift < 32)
1.184 + { // sign extend
1.185 + shift = 32 - shift;
1.186 + val = val << shift >> shift;
1.187 + }
1.188 + return val;
1.189 + }
1.190 +
1.191 +unsigned Decoder::DecodeUint()
1.192 + {
1.193 + unsigned val = 0;
1.194 + int shift = 0;
1.195 + unsigned byte;
1.196 + do
1.197 + {
1.198 + byte = *iTrace++;
1.199 + val |= (byte & 0x7f) << shift;
1.200 + shift += 7;
1.201 + } while ((byte & 0x80) == 0);
1.202 + return val;
1.203 + }
1.204 +
1.205 +char* Decoder::DecodeName()
1.206 + {
1.207 + int len = *iTrace++;
1.208 + char* name = new char[len+1];
1.209 + memcpy(name, iTrace, len);
1.210 + name[len] = '\0';
1.211 + iTrace += len;
1.212 + return name;
1.213 + }
1.214 +
1.215 +const Process* Decoder::DecodeProcess()
1.216 + {
1.217 + int pid = DecodeUint();
1.218 + const Process* p = iProcesses.Find(pid);
1.219 + if (p)
1.220 + return p;
1.221 +
1.222 + Process* np = new Process;
1.223 + np->iId = pid;
1.224 + np->iName = DecodeName();
1.225 + iProcesses.Add(*np);
1.226 + return np;
1.227 + }
1.228 +
1.229 +Thread* Decoder::DecodeThread()
1.230 + {
1.231 + int tid = DecodeUint();
1.232 + Thread* t = iThreads.Find(tid);
1.233 + if (t)
1.234 + return t;
1.235 +
1.236 + const Process* p = DecodeProcess();
1.237 + char* name = DecodeName();
1.238 + Thread* nt = new Thread;
1.239 + nt->iId = tid;
1.240 + nt->iName = name;
1.241 + nt->iProcess = p;
1.242 + iThreads.Add(*nt);
1.243 + if (!Analyse::Option(Analyse::ENull) && stricmp(name,"NULL") == 0)
1.244 + {
1.245 + nt->iIndex = ENullThread;
1.246 + return nt;
1.247 + }
1.248 + else
1.249 + {
1.250 + strstream s;
1.251 + s << p->iName << "::" << name << '\0';
1.252 + if (Analyse::Match(s.str(), Analyse::sThread))
1.253 + nt->iIndex = ELazyIndexThread;
1.254 + else
1.255 + nt->iIndex = EFilteredThread;
1.256 + }
1.257 + return nt;
1.258 + }
1.259 +
1.260 +Decoder::TValid Decoder::Validate()
1.261 +//
1.262 +// Check the trace header
1.263 +//
1.264 + {
1.265 + char* tag = DecodeName();
1.266 + int check = strcmp(tag, "profile");
1.267 + delete [] tag;
1.268 + if (check != 0)
1.269 + return EBadFile;
1.270 + int ver = DecodeUint();
1.271 + if (ver != MajorVersion)
1.272 + return EBadVersion;
1.273 + return EOk;
1.274 + }
1.275 +
1.276 +void Decoder::DecodeTrace(Sampler& aSampler, NonXIP* aNonXIP)
1.277 + {
1.278 + PC pc = 0;
1.279 + Thread* thread = 0;
1.280 + int sample = 0;
1.281 + int threadIndexer = 0;
1.282 + while (iTrace < iLimit && sample < iEnd)
1.283 + {
1.284 + int count = 1;
1.285 + int diff = DecodeInt();
1.286 + if (diff & 1)
1.287 + {
1.288 + diff &= ~1;
1.289 + thread = DecodeThread();
1.290 + }
1.291 + else if (diff == 0)
1.292 + {
1.293 + unsigned int next = DecodeUint();
1.294 + if (next != 0)
1.295 + count = next;
1.296 + else // non-XIP
1.297 + {
1.298 + next = DecodeUint();
1.299 + if (next == 0) // footer
1.300 + {
1.301 + aNonXIP->iRowBufferErrors = DecodeUint();
1.302 + aNonXIP->iCookBufferErrors = DecodeUint();
1.303 + aNonXIP->iReportMask = DecodeUint();
1.304 + }
1.305 + else if (next & 1) // segment deletion
1.306 + {
1.307 + PC address = next & ~1;
1.308 + aNonXIP->DeleteSegment(address);
1.309 + }
1.310 + else // segment creation
1.311 + {
1.312 + PC address = next;
1.313 + PC seg_size = DecodeUint();
1.314 + char * seg_name = DecodeName();
1.315 + aNonXIP->AddSegment(address, seg_size, seg_name + 3);
1.316 + }
1.317 + continue;
1.318 + }
1.319 + }
1.320 + pc += diff;
1.321 + while (--count >= 0)
1.322 + {
1.323 + if (sample >= iBegin)
1.324 + {
1.325 + ++iSamples;
1.326 + if (thread->iIndex != ENullThread)
1.327 + ++iActive;
1.328 + if (thread->iIndex >= ELazyIndexThread)
1.329 + {
1.330 + if (thread->iIndex == ELazyIndexThread)
1.331 + thread->iIndex = threadIndexer++;
1.332 + aSampler.Sample(sample, *thread, pc);
1.333 + }
1.334 + }
1.335 + if (++sample >= iEnd)
1.336 + break;
1.337 + }
1.338 + }
1.339 + }
1.340 +
1.341 +Trace::Trace()
1.342 + :iTrace(0), iLength(0), iDecoder(0)
1.343 + {}
1.344 +
1.345 +Trace::~Trace()
1.346 + {
1.347 + delete [] iTrace;
1.348 + delete iDecoder;
1.349 + }
1.350 +
1.351 +void Trace::Load(const char* aTraceFile, unsigned aBegin, unsigned aEnd)
1.352 + {
1.353 + ifstream file;
1.354 +#ifdef __MSVCDOTNET__
1.355 + file.open(aTraceFile, ios::binary);
1.356 +#else //!__MSVCDOTNET__
1.357 + file.open(aTraceFile, ios::nocreate | ios::binary);
1.358 +#endif //__MSVCDOTNET__
1.359 + if (!file)
1.360 + {
1.361 + cerr << "Unable to open trace file '" << aTraceFile << '\'' << endl;
1.362 + Analyse::Abort();
1.363 + }
1.364 +//
1.365 + file.seekg(0, ios::end);
1.366 + iLength = file.tellg();
1.367 +//
1.368 + iTrace = new TraceData[iLength];
1.369 + file.seekg(0, ios::beg);
1.370 + file.read(reinterpret_cast<char *>(iTrace), iLength);
1.371 +//
1.372 + file.close();
1.373 +//
1.374 + iDecoder = new Decoder(iTrace, iLength, aBegin, aEnd);
1.375 + switch (iDecoder->Validate())
1.376 + {
1.377 + case Decoder::EOk:
1.378 + break;
1.379 + case Decoder::EBadFile:
1.380 + cerr << "'" << aTraceFile << "' is not a valid trace file" << endl;
1.381 + Analyse::Abort();
1.382 + break;
1.383 + case Decoder::EBadVersion:
1.384 + Analyse::Abort("Trace file version not supported");
1.385 + break;
1.386 + }
1.387 + }
1.388 +
1.389 +void Trace::Decode(Sampler& aSampler, NonXIP* aNonXIP)
1.390 + {
1.391 + iDecoder->DecodeTrace(aSampler, aNonXIP);
1.392 + aSampler.Complete(iDecoder->iSamples, iDecoder->iActive);
1.393 + }
1.394 +
1.395 +
1.396 +