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