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