RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / bin / debug / profile / CallgrindProfileResult.cpp
blobeec6008f00040edd3f4aa0b88827e1845c704efa
1 /*
2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "CallgrindProfileResult.h"
9 #include <errno.h>
10 #include <sys/stat.h>
12 #include <algorithm>
13 #include <new>
15 #include "Options.h"
16 #include "ProfiledEntity.h"
19 // #pragma mark - CallgrindImageProfileResult
22 CallgrindImageProfileResult::CallgrindImageProfileResult(SharedImage* image,
23 image_id id)
25 ImageProfileResult(image, id),
26 fFunctions(NULL),
27 fOutputIndex(0)
32 CallgrindImageProfileResult::~CallgrindImageProfileResult()
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;
43 delete[] fFunctions;
47 status_t
48 CallgrindImageProfileResult::Init()
50 int32 symbolCount = fImage->SymbolCount();
51 fFunctions = new(std::nothrow) CallgrindFunction[symbolCount];
52 if (fFunctions == NULL)
53 return B_NO_MEMORY;
55 memset(fFunctions, 0, sizeof(CallgrindFunction) * symbolCount);
57 return B_OK;
61 void
62 CallgrindImageProfileResult::AddSymbolHit(int32 symbolIndex,
63 CallgrindImageProfileResult* calledImage, int32 calledSymbol)
66 fTotalHits++;
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;
77 calledFunction = calledFunction->next;
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;
87 calledFunction->next = function.calledFunctions;
88 function.calledFunctions = calledFunction;
91 calledFunction->hits++;
92 } else
93 function.hits++;
97 CallgrindFunction*
98 CallgrindImageProfileResult::Functions() const
100 return fFunctions;
104 int32
105 CallgrindImageProfileResult::OutputIndex() const
107 return fOutputIndex;
111 void
112 CallgrindImageProfileResult::SetOutputIndex(int32 index)
114 fOutputIndex = index;
118 // #pragma mark - CallgrindProfileResult
121 CallgrindProfileResult::CallgrindProfileResult()
123 fTotalTicks(0),
124 fUnkownTicks(0),
125 fDroppedTicks(0),
126 fNextImageOutputIndex(1),
127 fNextFunctionOutputIndex(1)
132 void
133 CallgrindProfileResult::AddSamples(ImageProfileResultContainer* container,
134 addr_t* samples, int32 sampleCount)
136 int32 unknownSamples = 0;
137 CallgrindImageProfileResult* previousImage = NULL;
138 int32 previousSymbol = -1;
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;
155 } else
156 unknownSamples++;
159 if (unknownSamples == sampleCount)
160 fUnkownTicks++;
162 fTotalTicks++;
166 void
167 CallgrindProfileResult::AddDroppedTicks(int32 dropped)
169 fDroppedTicks += dropped;
173 void
174 CallgrindProfileResult::PrintResults(ImageProfileResultContainer* container)
176 // create output file
178 // create output dir
179 mkdir(gOptions.callgrind_directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
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 = '-';
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);
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;
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");
209 fprintf(out, "positions: line\n");
210 fprintf(out, "events: Ticks Time\n");
211 fprintf(out, "summary: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval);
213 // get hit images
214 CallgrindImageProfileResult* images[container->CountImages()];
215 int32 imageCount = GetHitImages(container, images);
217 for (int32 i = 0; i < imageCount; i++) {
218 CallgrindImageProfileResult* image = images[i];
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;
227 fprintf(out, "\n");
228 _PrintFunction(out, image, k, false);
229 fprintf(out, "0 %lld %lld\n", function.hits,
230 function.hits * fInterval);
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;
244 // print pseudo-functions for unknown and dropped ticks
245 if (fUnkownTicks + fDroppedTicks > 0) {
246 fprintf(out, "\nob=<pseudo>\n");
248 if (fUnkownTicks > 0) {
249 fprintf(out, "\nfn=unknown\n");
250 fprintf(out, "0 %lld\n", fUnkownTicks);
253 if (fDroppedTicks > 0) {
254 fprintf(out, "\nfn=dropped\n");
255 fprintf(out, "0 %lld\n", fDroppedTicks);
259 fprintf(out, "\ntotals: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval);
261 fclose(out);
265 status_t
266 CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
267 ImageProfileResult*& _imageResult)
269 CallgrindImageProfileResult* result
270 = new(std::nothrow) CallgrindImageProfileResult(image, id);
271 if (result == NULL)
272 return B_NO_MEMORY;
274 status_t error = result->Init();
275 if (error != B_OK) {
276 delete result;
277 return error;
280 _imageResult = result;
281 return B_OK;
285 void
286 CallgrindProfileResult::_PrintFunction(FILE* out,
287 CallgrindImageProfileResult* image, int32 functionIndex, bool called)
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());
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);