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