xref: /haiku/src/bin/debug/profile/CallgrindProfileResult.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
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 "CallgrindProfileResult.h"
8 
9 #include <errno.h>
10 #include <sys/stat.h>
11 
12 #include <algorithm>
13 #include <new>
14 
15 #include "Options.h"
16 #include "ProfiledEntity.h"
17 
18 
19 // #pragma mark - CallgrindImageProfileResult
20 
21 
22 CallgrindImageProfileResult::CallgrindImageProfileResult(SharedImage* image,
23 	image_id id)
24 	:
25 	ImageProfileResult(image, id),
26 	fFunctions(NULL),
27 	fOutputIndex(0)
28 {
29 }
30 
31 
32 CallgrindImageProfileResult::~CallgrindImageProfileResult()
33 {
34 	int32 symbolCount = fImage->SymbolCount();
35 	for (int32 i = 0; i < symbolCount; i++) {
36 		while (CallgrindCalledFunction* calledFunction
37 				= fFunctions[i].calledFunctions) {
38 			fFunctions[i].calledFunctions = calledFunction->next;
39 			delete calledFunction;
40 		}
41 	}
42 
43 	delete[] fFunctions;
44 }
45 
46 
47 status_t
48 CallgrindImageProfileResult::Init()
49 {
50 	int32 symbolCount = fImage->SymbolCount();
51 	fFunctions = new(std::nothrow) CallgrindFunction[symbolCount];
52 	if (fFunctions == NULL)
53 		return B_NO_MEMORY;
54 
55 	memset(fFunctions, 0, sizeof(CallgrindFunction) * symbolCount);
56 
57 	return B_OK;
58 }
59 
60 
61 void
62 CallgrindImageProfileResult::AddSymbolHit(int32 symbolIndex,
63 	CallgrindImageProfileResult* calledImage, int32 calledSymbol)
64 
65 {
66 	fTotalHits++;
67 
68 	CallgrindFunction& function = fFunctions[symbolIndex];
69 	if (calledImage != NULL) {
70 		// check whether the called function is known already
71 		CallgrindCalledFunction* calledFunction = function.calledFunctions;
72 		while (calledFunction != NULL) {
73 			if (calledFunction->image == calledImage
74 				&& calledFunction->function == calledSymbol) {
75 				break;
76 			}
77 			calledFunction = calledFunction->next;
78 		}
79 
80 		// create a new CallgrindCalledFunction object, if not known
81 		if (calledFunction == NULL) {
82 			calledFunction = new(std::nothrow) CallgrindCalledFunction(
83 				calledImage, calledSymbol);
84 			if (calledFunction == NULL)
85 				return;
86 
87 			calledFunction->next = function.calledFunctions;
88 			function.calledFunctions = calledFunction;
89 		}
90 
91 		calledFunction->hits++;
92 	} else
93 		function.hits++;
94 }
95 
96 
97 CallgrindFunction*
98 CallgrindImageProfileResult::Functions() const
99 {
100 	return fFunctions;
101 }
102 
103 
104 int32
105 CallgrindImageProfileResult::OutputIndex() const
106 {
107 	return fOutputIndex;
108 }
109 
110 
111 void
112 CallgrindImageProfileResult::SetOutputIndex(int32 index)
113 {
114 	fOutputIndex = index;
115 }
116 
117 
118 // #pragma mark - CallgrindProfileResult
119 
120 
121 CallgrindProfileResult::CallgrindProfileResult()
122 	:
123 	fTotalTicks(0),
124 	fUnkownTicks(0),
125 	fDroppedTicks(0),
126 	fNextImageOutputIndex(1),
127 	fNextFunctionOutputIndex(1)
128 {
129 }
130 
131 
132 void
133 CallgrindProfileResult::AddSamples(ImageProfileResultContainer* container,
134 	addr_t* samples, int32 sampleCount)
135 {
136 	int32 unknownSamples = 0;
137 	CallgrindImageProfileResult* previousImage = NULL;
138 	int32 previousSymbol = -1;
139 
140 	// TODO: That probably doesn't work with recursive functions.
141 	for (int32 i = 0; i < sampleCount; i++) {
142 		addr_t address = samples[i];
143 		addr_t loadDelta;
144 		CallgrindImageProfileResult* image
145 			= static_cast<CallgrindImageProfileResult*>(
146 				container->FindImage(address, loadDelta));
147 		int32 symbol = -1;
148 		if (image != NULL) {
149 			symbol = image->GetImage()->FindSymbol(address - loadDelta);
150 			if (symbol >= 0) {
151 				image->AddSymbolHit(symbol, previousImage, previousSymbol);
152 				previousImage = image;
153 				previousSymbol = symbol;
154 			}
155 		} else
156 			unknownSamples++;
157 	}
158 
159 	if (unknownSamples == sampleCount)
160 		fUnkownTicks++;
161 
162 	fTotalTicks++;
163 }
164 
165 
166 void
167 CallgrindProfileResult::AddDroppedTicks(int32 dropped)
168 {
169 	fDroppedTicks += dropped;
170 }
171 
172 
173 void
174 CallgrindProfileResult::PrintResults(ImageProfileResultContainer* container)
175 {
176 	// create output file
177 
178 	// create output dir
179 	mkdir(gOptions.callgrind_directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
180 
181 	// get the entity name and replace slashes by hyphens
182 	char entityName[B_OS_NAME_LENGTH];
183 	strlcpy(entityName, fEntity->EntityName(), sizeof(entityName));
184 	char* slash = entityName;
185 	while ((slash = strchr(slash, '/')) != NULL)
186 		*slash = '-';
187 
188 	// create the file name
189 	char fileName[B_PATH_NAME_LENGTH];
190 	snprintf(fileName, sizeof(fileName), "%s/callgrind.out.%ld.%s.%lldms",
191 		gOptions.callgrind_directory, fEntity->EntityID(), entityName,
192 		fTotalTicks * fInterval);
193 
194 	// create the file
195 	FILE* out = fopen(fileName, "w+");
196 	if (out == NULL) {
197 		fprintf(stderr, "%s: Failed to open output file \"%s\": %s\n",
198 			kCommandName, fileName, strerror(errno));
199 		return;
200 	}
201 
202 	// write the header
203 	fprintf(out, "version: 1\n");
204 	fprintf(out, "creator: Haiku profile\n");
205 	fprintf(out, "pid: %ld\n", fEntity->EntityID());
206 	fprintf(out, "cmd: %s\n", fEntity->EntityName());
207 	fprintf(out, "part: 1\n\n");
208 
209 	fprintf(out, "positions: line\n");
210 	fprintf(out, "events: Ticks Time\n");
211 	fprintf(out, "summary: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval);
212 
213 	// get hit images
214 	CallgrindImageProfileResult* images[container->CountImages()];
215 	int32 imageCount = GetHitImages(container, images);
216 
217 	for (int32 i = 0; i < imageCount; i++) {
218 		CallgrindImageProfileResult* image = images[i];
219 
220 		CallgrindFunction* functions = image->Functions();
221 		int32 imageSymbolCount = image->GetImage()->SymbolCount();
222 		for (int32 k = 0; k < imageSymbolCount; k++) {
223 			CallgrindFunction& function = functions[k];
224 			if (function.hits == 0 && function.calledFunctions == NULL)
225 				continue;
226 
227 			fprintf(out, "\n");
228 			_PrintFunction(out, image, k, false);
229 			fprintf(out, "0 %lld %lld\n", function.hits,
230 				function.hits * fInterval);
231 
232 			CallgrindCalledFunction* calledFunction = function.calledFunctions;
233 			while (calledFunction != NULL) {
234 				_PrintFunction(out, calledFunction->image,
235 					calledFunction->function, true);
236 				fprintf(out, "calls=%lld 0\n", calledFunction->hits);
237 				fprintf(out, "0 %lld %lld\n", calledFunction->hits,
238 					calledFunction->hits * fInterval);
239 				calledFunction = calledFunction->next;
240 			}
241 		}
242 	}
243 
244 	// print pseudo-functions for unknown and dropped ticks
245 	if (fUnkownTicks + fDroppedTicks > 0) {
246 		fprintf(out, "\nob=<pseudo>\n");
247 
248 		if (fUnkownTicks > 0) {
249 			fprintf(out, "\nfn=unknown\n");
250 			fprintf(out, "0 %lld\n", fUnkownTicks);
251 		}
252 
253 		if (fDroppedTicks > 0) {
254 			fprintf(out, "\nfn=dropped\n");
255 			fprintf(out, "0 %lld\n", fDroppedTicks);
256 		}
257 	}
258 
259 	fprintf(out, "\ntotals: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval);
260 
261 	fclose(out);
262 }
263 
264 
265 status_t
266 CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
267 	ImageProfileResult*& _imageResult)
268 {
269 	CallgrindImageProfileResult* result
270 		= new(std::nothrow) CallgrindImageProfileResult(image, id);
271 	if (result == NULL)
272 		return B_NO_MEMORY;
273 
274 	status_t error = result->Init();
275 	if (error != B_OK) {
276 		delete result;
277 		return error;
278 	}
279 
280 	_imageResult = result;
281 	return B_OK;
282 }
283 
284 
285 void
286 CallgrindProfileResult::_PrintFunction(FILE* out,
287 	CallgrindImageProfileResult* image, int32 functionIndex, bool called)
288 {
289 	if (image->OutputIndex() == 0) {
290 		// need to print the image name
291 		int32 index = fNextImageOutputIndex++;
292 		image->SetOutputIndex(index);
293 		fprintf(out, "%sob=(%ld) %s:%ld\n", called ? "c" : "", index,
294 			image->GetImage()->Name(), image->ID());
295 	} else {
296 		// image is already known
297 		// TODO: We may not need to print it at all!
298 		fprintf(out, "%sob=(%ld)\n", called ? "c" : "", image->OutputIndex());
299 	}
300 
301 	CallgrindFunction& function = image->Functions()[functionIndex];
302 	if (function.outputIndex == 0) {
303 		// need to print the function name
304 		function.outputIndex = fNextFunctionOutputIndex++;
305 		fprintf(out, "%sfn=(%ld) %s\n", called ? "c" : "", function.outputIndex,
306 			image->GetImage()->Symbols()[functionIndex]->Name());
307 	} else {
308 		// function is already known
309 		fprintf(out, "%sfn=(%ld)\n", called ? "c" : "", function.outputIndex);
310 	}
311 }
312