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 "distribution.h" sl@0: #include "output.h" 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: #include sl@0: sl@0: // class Distribution sl@0: sl@0: namespace { sl@0: sl@0: int* BucketBox(int aSize) sl@0: { sl@0: int* buckets = new int[aSize]; sl@0: memset(buckets, 0, sizeof(int) * aSize); sl@0: return buckets; sl@0: } sl@0: sl@0: class BucketTotals sl@0: { sl@0: private: sl@0: class Generator sl@0: { sl@0: public: sl@0: inline Generator() sl@0: :iValue(0) sl@0: {} sl@0: inline int operator()() sl@0: {return iValue++;} sl@0: private: sl@0: int iValue; sl@0: }; sl@0: class Sorter sl@0: { sl@0: public: sl@0: inline Sorter(const int* aTotals) sl@0: :iTotals(aTotals) sl@0: {} sl@0: inline bool operator()(int aLhs, int aRhs) const sl@0: {return (iTotals[aLhs] > iTotals[aRhs]);} sl@0: private: sl@0: const int* iTotals; sl@0: }; sl@0: public: sl@0: BucketTotals(Distribution::Data& aData, int aSize); sl@0: ~BucketTotals(); sl@0: void Sort(); sl@0: // sl@0: inline int Total() const; sl@0: inline int Map(int aBucket) const; sl@0: inline int operator[](int aBucket) const; sl@0: inline Result Sample(int aSample) const; sl@0: private: sl@0: void Total(Distribution::Data& aData); sl@0: private: sl@0: int iSize; sl@0: int* iTotals; sl@0: int* iOrdering; sl@0: int iTotal; sl@0: }; sl@0: sl@0: BucketTotals::BucketTotals(Distribution::Data& aData, int aSize) sl@0: :iSize(aSize), iTotals(BucketBox(aSize)), iOrdering(BucketBox(aSize)) sl@0: { sl@0: Total(aData); sl@0: std::generate_n(iOrdering, iSize, Generator()); sl@0: } sl@0: sl@0: BucketTotals::~BucketTotals() sl@0: { sl@0: delete [] iTotals; sl@0: delete [] iOrdering; sl@0: } sl@0: sl@0: void BucketTotals::Total(Distribution::Data& aData) sl@0: { sl@0: int total = 0; sl@0: for (Distribution::Data::iterator p = aData.begin(), e = aData.end(); p != e; ++p) sl@0: { sl@0: const int* box = p->iBuckets; sl@0: int threadTotal = 0; sl@0: for (int j = p->iBucketsLength; --j >=0;) sl@0: { sl@0: threadTotal += box[j]; sl@0: iTotals[j] += box[j]; sl@0: } sl@0: p->iTotal = threadTotal; sl@0: total += threadTotal; sl@0: } sl@0: iTotal = total; sl@0: } sl@0: sl@0: void BucketTotals::Sort() sl@0: { sl@0: std::sort(iOrdering, iOrdering + iSize, Sorter(iTotals)); sl@0: } sl@0: sl@0: inline int BucketTotals::Total() const sl@0: {return iTotal;} sl@0: sl@0: inline int BucketTotals::Map(int aBucket) const sl@0: {return iOrdering[aBucket];} sl@0: sl@0: inline int BucketTotals::operator[](int aBucket) const sl@0: {return iTotals[iOrdering[aBucket]];} sl@0: sl@0: inline Result BucketTotals::Sample(int aSample) const sl@0: {return Result(aSample, iTotal);} sl@0: sl@0: }; sl@0: sl@0: inline Distribution::ThreadData::ThreadData(const Thread& aThread, int aSize) sl@0: :iThread(&aThread), iBuckets(BucketBox(aSize)), iTotal(0), iBucketsLength(aSize) sl@0: {} sl@0: sl@0: inline Distribution::ThreadData::ThreadData(int aCutoff) sl@0: :iTotal(aCutoff) sl@0: {} sl@0: sl@0: inline bool Distribution::ThreadData::operator<(const Distribution::ThreadData& aRhs) const sl@0: {return (iTotal > aRhs.iTotal);} sl@0: sl@0: Distribution::Distribution(CodeSpace& aCodeSpace, double aCutOff) sl@0: :iCodeSpace(aCodeSpace), iCutOff(aCutOff) sl@0: { sl@0: cout << "Profile distribution\n\n"; sl@0: } sl@0: sl@0: void Distribution::Sample(unsigned , const Thread& aThread, PC aPc) sl@0: // sl@0: // Collect the sample in the bucket as allocated by the code space sl@0: // sl@0: { sl@0: if (aThread.iIndex == iData.size()) sl@0: iData.push_back(ThreadData(aThread,iCodeSpace.Size())); sl@0: sl@0: /// sl@0: int bucket = iCodeSpace.Bucket(aPc); sl@0: if (bucket >= iData[aThread.iIndex].iBucketsLength) sl@0: { sl@0: int* new_buckets = new int[bucket+1]; sl@0: memset(new_buckets, 0, sizeof(int) * (bucket+1)); sl@0: memcpy(new_buckets, iData[aThread.iIndex].iBuckets, sizeof(int) * iData[aThread.iIndex].iBucketsLength); sl@0: delete [] iData[aThread.iIndex].iBuckets; sl@0: iData[aThread.iIndex].iBuckets = new_buckets; sl@0: iData[aThread.iIndex].iBucketsLength = bucket+1; sl@0: } sl@0: sl@0: ++iData[aThread.iIndex].iBuckets[bucket]; sl@0: } sl@0: sl@0: void Distribution::Complete(unsigned aTotal, unsigned aActive) sl@0: { sl@0: // accumulate thread and bucket totals sl@0: const int nbuckets = iCodeSpace.Size(); sl@0: BucketTotals totals(iData, nbuckets); sl@0: if (iCodeSpace.Ordering() == CodeSpace::ERandom) sl@0: totals.Sort(); sl@0: sl@0: int cutoff = int(iCutOff * totals.Total() * 0.01); sl@0: std::sort(iData.begin(), iData.end()); sl@0: iData.erase(std::upper_bound(iData.begin(), iData.end(), ThreadData(cutoff)), iData.end()); sl@0: // sl@0: cout.setf(ios::fixed, ios::floatfield); sl@0: cout.precision(2); sl@0: // sl@0: cout << "Samples: " << aTotal << '\n'; sl@0: cout << " Active: " << aActive << " (" << double(aActive*100)/aTotal << "%)\n"; sl@0: cout << "Counted: " << totals.Total() << " (" << double(totals.Total()*100)/aTotal << "%)\n\n"; sl@0: cout << setfill(' '); sl@0: // sl@0: Data::iterator p, e; sl@0: if (!Analyse::Option(Analyse::ETotalOnly)) sl@0: { sl@0: if (Analyse::Format() != Analyse::EExcel) sl@0: { sl@0: cout << "ID Thread name\n"; sl@0: char id = 'A'; sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << id++ << " " << *p->iThread << '\n'; sl@0: cout << '\n'; sl@0: sl@0: id = 'A'; sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << setw(4) << id++ << " "; sl@0: cout << " total\n\n"; sl@0: sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << totals.Sample(p->iTotal) << " "; sl@0: cout << " " << totals.Sample(totals.Total()) << " total\n\n"; sl@0: } sl@0: else sl@0: { sl@0: cout.precision(5); sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << '\t' << *p->iThread; sl@0: cout << "\ttotal\n"; sl@0: } sl@0: } sl@0: sl@0: if (cutoff == 0 && iCodeSpace.Ordering() != CodeSpace::ELinear) sl@0: cutoff = 1; sl@0: sl@0: for (int ix = 0; ix< nbuckets; ++ix) sl@0: { sl@0: int total = totals[ix]; sl@0: if (total >= cutoff) sl@0: { sl@0: int jx = totals.Map(ix); sl@0: if (jx == CodeSpace::KOtherBucket && Analyse::Option(Analyse::ENoOther)) sl@0: continue; sl@0: if (Analyse::Format() == Analyse::EExcel) sl@0: { sl@0: cout << iCodeSpace.Name(jx); sl@0: if (!Analyse::Option(Analyse::ETotalOnly)) sl@0: { sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << '\t' << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]); sl@0: } sl@0: cout << '\t' << totals.Sample(total) << '\n'; sl@0: } sl@0: else sl@0: { sl@0: if (!Analyse::Option(Analyse::ETotalOnly)) sl@0: { sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]) << " "; sl@0: cout << " "; sl@0: } sl@0: cout << totals.Sample(total) << " " << iCodeSpace.Name(jx) << '\n'; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (!Analyse::Option(Analyse::ETotalOnly)) sl@0: { sl@0: if (Analyse::Format() == Analyse::EExcel) sl@0: { sl@0: cout << "total"; sl@0: for (p = iData.begin(), e = iData.end(); p != e; ++p) sl@0: cout << '\t' << totals.Sample(p->iTotal); sl@0: cout << '\t' << totals.Sample(totals.Total()) << '\n'; sl@0: } sl@0: } sl@0: }