xref: /haiku/src/bin/debug/profile/BasicProfileResult.cpp (revision 342a1b221b5bb385410f758df2c625b70cafdd03)
1 /*
2  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "BasicProfileResult.h"
8 
9 #if __GNUC__ > 2
10 #include <cxxabi.h>
11 #endif
12 #include <stdio.h>
13 
14 #include <algorithm>
15 #include <new>
16 
17 #include "Options.h"
18 #include "ProfiledEntity.h"
19 
20 
21 struct HitSymbol {
22 	int64		hits;
23 	Symbol*		symbol;
24 	image_id	imageID;
25 
26 	inline bool operator<(const HitSymbol& other) const
27 	{
28 		return hits > other.hits;
29 	}
30 };
31 
32 
33 // #pragma mark - BasicImageProfileResult
34 
35 
36 BasicImageProfileResult::BasicImageProfileResult(SharedImage* image,
37 	image_id id)
38 	:
39 	ImageProfileResult(image, id),
40 	fSymbolHits(NULL),
41 	fUnknownHits(0)
42 {
43 }
44 
45 
46 BasicImageProfileResult::~BasicImageProfileResult()
47 {
48 }
49 
50 
51 status_t
52 BasicImageProfileResult::Init()
53 {
54 	int32 symbolCount = fImage->SymbolCount();
55 	fSymbolHits = new(std::nothrow) int64[symbolCount];
56 	if (fSymbolHits == NULL)
57 		return B_NO_MEMORY;
58 
59 	memset(fSymbolHits, 0, 8 * symbolCount);
60 
61 	return B_OK;
62 }
63 
64 
65 bool
66 BasicImageProfileResult::AddHit(addr_t address)
67 {
68 	int32 symbolIndex = fImage->FindSymbol(address);
69 	if (symbolIndex < 0)
70 		return false;
71 
72 	fSymbolHits[symbolIndex]++;
73 	fTotalHits++;
74 
75 	return true;
76 }
77 
78 
79 void
80 BasicImageProfileResult::AddUnknownHit()
81 {
82 	fUnknownHits++;
83 	fTotalHits++;
84 }
85 
86 
87 void
88 BasicImageProfileResult::AddSymbolHit(int32 symbolIndex)
89 {
90 	fSymbolHits[symbolIndex]++;
91 }
92 
93 
94 void
95 BasicImageProfileResult::AddImageHit()
96 {
97 	fTotalHits++;
98 }
99 
100 
101 const int64*
102 BasicImageProfileResult::SymbolHits() const
103 {
104 	return fSymbolHits;
105 }
106 
107 
108 int64
109 BasicImageProfileResult::UnknownHits() const
110 {
111 	return fUnknownHits;
112 }
113 
114 
115 // #pragma mark - BasicProfileResult
116 
117 
118 BasicProfileResult::BasicProfileResult()
119 	:
120 	fTotalTicks(0),
121 	fUnkownTicks(0),
122 	fExpectedTicks(0),
123 	fDroppedTicks(0),
124 	fTotalSampleCount(0)
125 {
126 }
127 
128 
129 void
130 BasicProfileResult::AddExpectedTicks(int32 expected)
131 {
132 	fExpectedTicks += expected;
133 }
134 
135 
136 void
137 BasicProfileResult::AddDroppedTicks(int32 dropped)
138 {
139 	fDroppedTicks += dropped;
140 }
141 
142 
143 void
144 BasicProfileResult::PrintResults(ImageProfileResultContainer* container)
145 {
146 	// get hit images
147 	BasicImageProfileResult* images[container->CountImages()];
148 	int32 imageCount = GetHitImages(container, images);
149 
150 	// count symbols
151 	int32 symbolCount = 0;
152 	for (int32 k = 0; k < imageCount; k++) {
153 		BasicImageProfileResult* image = images[k];
154 		if (image->TotalHits() > image->UnknownHits())
155 			symbolCount += image->GetImage()->SymbolCount();
156 	}
157 
158 	// find and sort the hit symbols
159 	HitSymbol hitSymbols[symbolCount];
160 	int32 hitSymbolCount = 0;
161 
162 	for (int32 k = 0; k < imageCount; k++) {
163 		BasicImageProfileResult* image = images[k];
164 		if (image->TotalHits() > image->UnknownHits()) {
165 			Symbol** symbols = image->GetImage()->Symbols();
166 			const int64* symbolHits = image->SymbolHits();
167 			int32 imageSymbolCount = image->GetImage()->SymbolCount();
168 			for (int32 i = 0; i < imageSymbolCount; i++) {
169 				if (symbolHits[i] > 0) {
170 					HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++];
171 					hitSymbol.hits = symbolHits[i];
172 					hitSymbol.symbol = symbols[i];
173 					hitSymbol.imageID = image->ID();
174 				}
175 			}
176 		}
177 	}
178 
179 	if (hitSymbolCount > 1)
180 		std::sort(hitSymbols, hitSymbols + hitSymbolCount);
181 
182 	int64 totalTicks = fTotalTicks;
183 	const int64 missedTicks = fExpectedTicks - fTotalTicks;
184 
185 	fprintf(gOptions.output, "\nprofiling results for %s \"%s\" "
186 		"(%" B_PRId32 "):\n", fEntity->EntityType(), fEntity->EntityName(),
187 		fEntity->EntityID());
188 	fprintf(gOptions.output, "  tick interval:  %" B_PRIdBIGTIME " us\n",
189 		fInterval);
190 	fprintf(gOptions.output,
191 		"  total ticks:    %" B_PRId64 " (%" B_PRId64 " us)\n",
192 		totalTicks, totalTicks * fInterval);
193 	if (fExpectedTicks != 0) {
194 		fprintf(gOptions.output,
195 			"  expected ticks: %" B_PRId64 " (missed %" B_PRId64 ")\n",
196 			fExpectedTicks, missedTicks);
197 	}
198 	if (totalTicks == 0)
199 		totalTicks = 1;
200 
201 	fprintf(gOptions.output,
202 		"  unknown ticks:  %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n",
203 		fUnkownTicks, fUnkownTicks * fInterval,
204 		100.0 * fUnkownTicks / totalTicks);
205 	fprintf(gOptions.output,
206 		"  dropped ticks:  %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n",
207 		fDroppedTicks, fDroppedTicks * fInterval,
208 		100.0 * fDroppedTicks / totalTicks);
209 	if (gOptions.analyze_full_stack) {
210 		fprintf(gOptions.output, "  samples/tick:   %.1f\n",
211 			(double)fTotalSampleCount / totalTicks);
212 	}
213 
214 	if (imageCount > 0) {
215 		fprintf(gOptions.output, "\n");
216 		fprintf(gOptions.output, "        hits     unknown    image\n");
217 		fprintf(gOptions.output, "  ---------------------------------------"
218 			"---------------------------------------\n");
219 		for (int32 k = 0; k < imageCount; k++) {
220 			BasicImageProfileResult* image = images[k];
221 			fprintf(gOptions.output,
222 				"  %10" B_PRId64 "  %10" B_PRId64 "  %7" B_PRId32 " %s\n",
223 				image->TotalHits(), image->UnknownHits(),
224 				image->ID(), image->GetImage()->Name());
225 		}
226 	}
227 
228 	if (hitSymbolCount > 0) {
229 		fprintf(gOptions.output, "\n");
230 		fprintf(gOptions.output, "        hits       in us    in %%   "
231 			"image  function\n");
232 		fprintf(gOptions.output, "  ---------------------------------------"
233 			"---------------------------------------\n");
234 		for (int32 i = 0; i < hitSymbolCount; i++) {
235 			const HitSymbol& hitSymbol = hitSymbols[i];
236 			const Symbol* symbol = hitSymbol.symbol;
237 #if __GNUC__ > 2
238 			int status;
239 			const char* symbolName = __cxxabiv1::__cxa_demangle(symbol->Name(),
240 				NULL, NULL, &status);
241 			if (symbolName == NULL)
242 				symbolName = symbol->Name();
243 #else
244 			const char* symbolName = symbol->Name();
245 #endif
246 			fprintf(gOptions.output,
247 				"  %10" B_PRId64 "  %10" B_PRId64 "  %6.2f  %6" B_PRId32
248 				"  %s\n", hitSymbol.hits, hitSymbol.hits * fInterval,
249 				100.0 * hitSymbol.hits / totalTicks, hitSymbol.imageID,
250 				symbolName);
251 #if __GNUC__ > 2
252 			if (status == 0)
253 				free(const_cast<char*>(symbolName));
254 #endif
255 		}
256 	} else
257 		fprintf(gOptions.output, "  no functions were hit\n");
258 }
259 
260 
261 status_t
262 BasicProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
263 	ImageProfileResult*& _imageResult)
264 {
265 	BasicImageProfileResult* result
266 		= new(std::nothrow) BasicImageProfileResult(image, id);
267 	if (result == NULL)
268 		return B_NO_MEMORY;
269 
270 	status_t error = result->Init();
271 	if (error != B_OK) {
272 		delete result;
273 		return error;
274 	}
275 
276 	_imageResult = result;
277 	return B_OK;
278 }
279 
280 
281 // #pragma mark - InclusiveProfileResult
282 
283 
284 void
285 InclusiveProfileResult::AddSamples(ImageProfileResultContainer* container,
286 	addr_t* samples, int32 sampleCount)
287 {
288 	// Sort the samples. This way hits of the same symbol are
289 	// successive and we can avoid incrementing the hit count of the
290 	// same symbol twice. Same for images.
291 	std::sort(samples, samples + sampleCount);
292 
293 	int32 unknownSamples = 0;
294 	BasicImageProfileResult* previousImage = NULL;
295 	int32 previousSymbol = -1;
296 
297 	for (int32 i = 0; i < sampleCount; i++) {
298 		addr_t address = samples[i];
299 		addr_t loadDelta;
300 		BasicImageProfileResult* image = static_cast<BasicImageProfileResult*>(
301 			container->FindImage(address, loadDelta));
302 		int32 symbol = -1;
303 		if (image != NULL) {
304 			symbol = image->GetImage()->FindSymbol(address - loadDelta);
305 			if (image != previousImage || symbol != previousSymbol) {
306 				if (symbol < 0)
307 					image->AddUnknownHit();
308 				else
309 					image->AddSymbolHit(symbol);
310 			}
311 
312 			if (image != previousImage)
313 				image->AddImageHit();
314 		} else
315 			unknownSamples++;
316 
317 		previousImage = image;
318 		previousSymbol = symbol;
319 	}
320 
321 	if (unknownSamples == sampleCount)
322 		fUnkownTicks++;
323 
324 	fTotalTicks++;
325 	fTotalSampleCount += sampleCount;
326 }
327 
328 
329 // #pragma mark - ExclusiveProfileResult
330 
331 
332 void
333 ExclusiveProfileResult::AddSamples(ImageProfileResultContainer* container,
334 	addr_t* samples, int32 sampleCount)
335 {
336 	BasicImageProfileResult* image = NULL;
337 		// the image in which we hit a symbol
338 	BasicImageProfileResult* firstImage = NULL;
339 		// the first image we hit, != image if no symbol was hit
340 
341 	for (int32 k = 0; k < sampleCount; k++) {
342 		addr_t address = samples[k];
343 		addr_t loadDelta;
344 		image = static_cast<BasicImageProfileResult*>(
345 			container->FindImage(address, loadDelta));
346 		if (image != NULL) {
347 			if (image->AddHit(address - loadDelta))
348 				break;
349 			if (firstImage == NULL)
350 				firstImage = image;
351 		}
352 	}
353 
354 	if (image == NULL) {
355 		if (firstImage != NULL)
356 			firstImage->AddUnknownHit();
357 		else
358 			fUnkownTicks++;
359 	}
360 
361 	fTotalTicks++;
362 	fTotalSampleCount += sampleCount;
363 }
364