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