|
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 "distribution.h" |
|
18 #include "output.h" |
|
19 |
|
20 #ifdef __MSVCDOTNET__ |
|
21 #include <ostream> |
|
22 #include <iomanip> |
|
23 #else //!__MSVCDOTNET__ |
|
24 #include <ostream.h> |
|
25 #include <iomanip.h> |
|
26 #endif //__MSVCDOTNET__ |
|
27 |
|
28 #include <algorithm> |
|
29 |
|
30 // class Distribution |
|
31 |
|
32 namespace { |
|
33 |
|
34 int* BucketBox(int aSize) |
|
35 { |
|
36 int* buckets = new int[aSize]; |
|
37 memset(buckets, 0, sizeof(int) * aSize); |
|
38 return buckets; |
|
39 } |
|
40 |
|
41 class BucketTotals |
|
42 { |
|
43 private: |
|
44 class Generator |
|
45 { |
|
46 public: |
|
47 inline Generator() |
|
48 :iValue(0) |
|
49 {} |
|
50 inline int operator()() |
|
51 {return iValue++;} |
|
52 private: |
|
53 int iValue; |
|
54 }; |
|
55 class Sorter |
|
56 { |
|
57 public: |
|
58 inline Sorter(const int* aTotals) |
|
59 :iTotals(aTotals) |
|
60 {} |
|
61 inline bool operator()(int aLhs, int aRhs) const |
|
62 {return (iTotals[aLhs] > iTotals[aRhs]);} |
|
63 private: |
|
64 const int* iTotals; |
|
65 }; |
|
66 public: |
|
67 BucketTotals(Distribution::Data& aData, int aSize); |
|
68 ~BucketTotals(); |
|
69 void Sort(); |
|
70 // |
|
71 inline int Total() const; |
|
72 inline int Map(int aBucket) const; |
|
73 inline int operator[](int aBucket) const; |
|
74 inline Result Sample(int aSample) const; |
|
75 private: |
|
76 void Total(Distribution::Data& aData); |
|
77 private: |
|
78 int iSize; |
|
79 int* iTotals; |
|
80 int* iOrdering; |
|
81 int iTotal; |
|
82 }; |
|
83 |
|
84 BucketTotals::BucketTotals(Distribution::Data& aData, int aSize) |
|
85 :iSize(aSize), iTotals(BucketBox(aSize)), iOrdering(BucketBox(aSize)) |
|
86 { |
|
87 Total(aData); |
|
88 std::generate_n(iOrdering, iSize, Generator()); |
|
89 } |
|
90 |
|
91 BucketTotals::~BucketTotals() |
|
92 { |
|
93 delete [] iTotals; |
|
94 delete [] iOrdering; |
|
95 } |
|
96 |
|
97 void BucketTotals::Total(Distribution::Data& aData) |
|
98 { |
|
99 int total = 0; |
|
100 for (Distribution::Data::iterator p = aData.begin(), e = aData.end(); p != e; ++p) |
|
101 { |
|
102 const int* box = p->iBuckets; |
|
103 int threadTotal = 0; |
|
104 for (int j = p->iBucketsLength; --j >=0;) |
|
105 { |
|
106 threadTotal += box[j]; |
|
107 iTotals[j] += box[j]; |
|
108 } |
|
109 p->iTotal = threadTotal; |
|
110 total += threadTotal; |
|
111 } |
|
112 iTotal = total; |
|
113 } |
|
114 |
|
115 void BucketTotals::Sort() |
|
116 { |
|
117 std::sort(iOrdering, iOrdering + iSize, Sorter(iTotals)); |
|
118 } |
|
119 |
|
120 inline int BucketTotals::Total() const |
|
121 {return iTotal;} |
|
122 |
|
123 inline int BucketTotals::Map(int aBucket) const |
|
124 {return iOrdering[aBucket];} |
|
125 |
|
126 inline int BucketTotals::operator[](int aBucket) const |
|
127 {return iTotals[iOrdering[aBucket]];} |
|
128 |
|
129 inline Result BucketTotals::Sample(int aSample) const |
|
130 {return Result(aSample, iTotal);} |
|
131 |
|
132 }; |
|
133 |
|
134 inline Distribution::ThreadData::ThreadData(const Thread& aThread, int aSize) |
|
135 :iThread(&aThread), iBuckets(BucketBox(aSize)), iTotal(0), iBucketsLength(aSize) |
|
136 {} |
|
137 |
|
138 inline Distribution::ThreadData::ThreadData(int aCutoff) |
|
139 :iTotal(aCutoff) |
|
140 {} |
|
141 |
|
142 inline bool Distribution::ThreadData::operator<(const Distribution::ThreadData& aRhs) const |
|
143 {return (iTotal > aRhs.iTotal);} |
|
144 |
|
145 Distribution::Distribution(CodeSpace& aCodeSpace, double aCutOff) |
|
146 :iCodeSpace(aCodeSpace), iCutOff(aCutOff) |
|
147 { |
|
148 cout << "Profile distribution\n\n"; |
|
149 } |
|
150 |
|
151 void Distribution::Sample(unsigned , const Thread& aThread, PC aPc) |
|
152 // |
|
153 // Collect the sample in the bucket as allocated by the code space |
|
154 // |
|
155 { |
|
156 if (aThread.iIndex == iData.size()) |
|
157 iData.push_back(ThreadData(aThread,iCodeSpace.Size())); |
|
158 |
|
159 /// |
|
160 int bucket = iCodeSpace.Bucket(aPc); |
|
161 if (bucket >= iData[aThread.iIndex].iBucketsLength) |
|
162 { |
|
163 int* new_buckets = new int[bucket+1]; |
|
164 memset(new_buckets, 0, sizeof(int) * (bucket+1)); |
|
165 memcpy(new_buckets, iData[aThread.iIndex].iBuckets, sizeof(int) * iData[aThread.iIndex].iBucketsLength); |
|
166 delete [] iData[aThread.iIndex].iBuckets; |
|
167 iData[aThread.iIndex].iBuckets = new_buckets; |
|
168 iData[aThread.iIndex].iBucketsLength = bucket+1; |
|
169 } |
|
170 |
|
171 ++iData[aThread.iIndex].iBuckets[bucket]; |
|
172 } |
|
173 |
|
174 void Distribution::Complete(unsigned aTotal, unsigned aActive) |
|
175 { |
|
176 // accumulate thread and bucket totals |
|
177 const int nbuckets = iCodeSpace.Size(); |
|
178 BucketTotals totals(iData, nbuckets); |
|
179 if (iCodeSpace.Ordering() == CodeSpace::ERandom) |
|
180 totals.Sort(); |
|
181 |
|
182 int cutoff = int(iCutOff * totals.Total() * 0.01); |
|
183 std::sort(iData.begin(), iData.end()); |
|
184 iData.erase(std::upper_bound(iData.begin(), iData.end(), ThreadData(cutoff)), iData.end()); |
|
185 // |
|
186 cout.setf(ios::fixed, ios::floatfield); |
|
187 cout.precision(2); |
|
188 // |
|
189 cout << "Samples: " << aTotal << '\n'; |
|
190 cout << " Active: " << aActive << " (" << double(aActive*100)/aTotal << "%)\n"; |
|
191 cout << "Counted: " << totals.Total() << " (" << double(totals.Total()*100)/aTotal << "%)\n\n"; |
|
192 cout << setfill(' '); |
|
193 // |
|
194 Data::iterator p, e; |
|
195 if (!Analyse::Option(Analyse::ETotalOnly)) |
|
196 { |
|
197 if (Analyse::Format() != Analyse::EExcel) |
|
198 { |
|
199 cout << "ID Thread name\n"; |
|
200 char id = 'A'; |
|
201 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
202 cout << id++ << " " << *p->iThread << '\n'; |
|
203 cout << '\n'; |
|
204 |
|
205 id = 'A'; |
|
206 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
207 cout << setw(4) << id++ << " "; |
|
208 cout << " total\n\n"; |
|
209 |
|
210 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
211 cout << totals.Sample(p->iTotal) << " "; |
|
212 cout << " " << totals.Sample(totals.Total()) << " total\n\n"; |
|
213 } |
|
214 else |
|
215 { |
|
216 cout.precision(5); |
|
217 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
218 cout << '\t' << *p->iThread; |
|
219 cout << "\ttotal\n"; |
|
220 } |
|
221 } |
|
222 |
|
223 if (cutoff == 0 && iCodeSpace.Ordering() != CodeSpace::ELinear) |
|
224 cutoff = 1; |
|
225 |
|
226 for (int ix = 0; ix< nbuckets; ++ix) |
|
227 { |
|
228 int total = totals[ix]; |
|
229 if (total >= cutoff) |
|
230 { |
|
231 int jx = totals.Map(ix); |
|
232 if (jx == CodeSpace::KOtherBucket && Analyse::Option(Analyse::ENoOther)) |
|
233 continue; |
|
234 if (Analyse::Format() == Analyse::EExcel) |
|
235 { |
|
236 cout << iCodeSpace.Name(jx); |
|
237 if (!Analyse::Option(Analyse::ETotalOnly)) |
|
238 { |
|
239 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
240 cout << '\t' << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]); |
|
241 } |
|
242 cout << '\t' << totals.Sample(total) << '\n'; |
|
243 } |
|
244 else |
|
245 { |
|
246 if (!Analyse::Option(Analyse::ETotalOnly)) |
|
247 { |
|
248 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
249 cout << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]) << " "; |
|
250 cout << " "; |
|
251 } |
|
252 cout << totals.Sample(total) << " " << iCodeSpace.Name(jx) << '\n'; |
|
253 } |
|
254 } |
|
255 } |
|
256 |
|
257 if (!Analyse::Option(Analyse::ETotalOnly)) |
|
258 { |
|
259 if (Analyse::Format() == Analyse::EExcel) |
|
260 { |
|
261 cout << "total"; |
|
262 for (p = iData.begin(), e = iData.end(); p != e; ++p) |
|
263 cout << '\t' << totals.Sample(p->iTotal); |
|
264 cout << '\t' << totals.Sample(totals.Total()) << '\n'; |
|
265 } |
|
266 } |
|
267 } |