clang specific define in Runtime.cc
[deliverable/titan.core.git] / core / ProfilerTools.cc
CommitLineData
d44e3c4f 1/******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Balasko, Jeno
10 * Baranyi, Botond
11 *
12 ******************************************************************************/
3abe9331 13
14#include "ProfilerTools.hh"
15#include "JSON_Tokenizer.hh"
16#include "memory.h"
17#include <string.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21
22namespace Profiler_Tools {
23
24 ////////////////////////////////////
25 //////// timeval operations ////////
26 ////////////////////////////////////
27
28 timeval string2timeval(const char* str)
29 {
30 // read and store the first part (atoi will read until the decimal dot)
31 long int sec = atoi(str);
32 timeval tv;
33 tv.tv_sec = sec;
34
35 do {
36 // step over each digit
37 sec /= 10;
38 ++str;
39 }
40 while (sec > 9);
41
42 // step over the decimal dot and read the second part of the number
43 tv.tv_usec = atoi(str + 1);
44 return tv;
45 }
46
47 char* timeval2string(timeval tv)
48 {
49 // convert the first part and set the second part to all zeros
50 char* str = mprintf("%ld.000000", tv.tv_sec);
51
52 // go through each digit of the second part and add them to the zeros in the string
53 size_t pos = mstrlen(str) - 1;
54 while (tv.tv_usec > 0) {
55 str[pos] += tv.tv_usec % 10;
56 tv.tv_usec /= 10;
57 --pos;
58 }
59 return str;
60 }
61
62 timeval add_timeval(const timeval operand1, const timeval operand2)
63 {
64 timeval tv;
65 tv.tv_usec = operand1.tv_usec + operand2.tv_usec;
66 tv.tv_sec = operand1.tv_sec + operand2.tv_sec;
67 if (tv.tv_usec >= 1000000) {
68 ++tv.tv_sec;
69 tv.tv_usec -= 1000000;
70 }
71 return tv;
72 }
73
74 timeval subtract_timeval(const timeval operand1, const timeval operand2)
75 {
76 timeval tv;
77 tv.tv_usec = operand1.tv_usec - operand2.tv_usec;
78 tv.tv_sec = operand1.tv_sec - operand2.tv_sec;
79 if (tv.tv_usec < 0) {
80 --tv.tv_sec;
81 tv.tv_usec += 1000000;
82 }
83 return tv;
84 }
85
86 ////////////////////////////////////
87 ///// profiler data operations /////
88 ////////////////////////////////////
89
90 int get_function(const profiler_db_t& p_db, int p_element, int p_lineno)
91 {
92 for (size_t i = 0; i < p_db[p_element].functions.size(); ++i) {
93 if (p_db[p_element].functions[i].lineno == p_lineno) {
94 return i;
95 }
96 }
97 return -1;
98 }
99
100 void create_function(profiler_db_t& p_db, int p_element, int p_lineno,
101 const char* p_function_name)
102 {
103 profiler_db_item_t::profiler_function_data_t func_data;
104 func_data.lineno = p_lineno;
105 func_data.total_time.tv_sec = 0;
106 func_data.total_time.tv_usec = 0;
107 func_data.exec_count = 0;
108 func_data.name = mcopystr(p_function_name);
109 p_db[p_element].functions.push_back(func_data);
110 }
111
112 int get_line(const profiler_db_t& p_db, int p_element, int p_lineno)
113 {
114 for (size_t i = 0; i < p_db[p_element].lines.size(); ++i) {
115 if (p_db[p_element].lines[i].lineno == p_lineno) {
116 return i;
117 }
118 }
119 return -1;
120 }
121
122 void create_line(profiler_db_t& p_db, int p_element, int p_lineno)
123 {
124 profiler_db_item_t::profiler_line_data_t line_data;
125 line_data.lineno = p_lineno;
126 line_data.total_time.tv_sec = 0;
127 line_data.total_time.tv_usec = 0;
128 line_data.exec_count = 0;
129 p_db[p_element].lines.push_back(line_data);
130 }
131
132#define IMPORT_FORMAT_ERROR(cond) \
133 if (cond) { \
134 p_error_function("Failed to load profiling and/or code coverage database. Invalid format."); \
135 return; \
136 }
137
d44e3c4f 138 void import_data(profiler_db_t& p_db, const char* p_filename,
3abe9331 139 void (*p_error_function)(const char*, ...))
140 {
141 // open the file, if it exists
3abe9331 142 FILE* file = fopen(p_filename, "r");
d44e3c4f 143 if (NULL == file) {
144 p_error_function("Profiler database file '%s' does not exist.", p_filename);
145 return;
3abe9331 146 }
d44e3c4f 147
148 // get the file size
149 fseek(file, 0, SEEK_END);
150 int file_size = ftell(file);
3abe9331 151 rewind(file);
152
153 // read the entire file into a character buffer
154 char* buffer = (char*)Malloc(file_size);
155 int bytes_read = fread(buffer, 1, file_size, file);
156 fclose(file);
157 if (bytes_read != file_size) {
158 p_error_function("Error reading database file.");
159 return;
160 }
161
162 // initialize a JSON tokenizer with the buffer
163 JSON_Tokenizer json(buffer, file_size);
164 Free(buffer);
165
166 // attempt to read tokens from the buffer
167 // if the format is invalid, abort the importing process
168 json_token_t token = JSON_TOKEN_NONE;
169 char* value = NULL;
170 size_t value_len = 0;
171
172 // start of main array
173 json.get_next_token(&token, NULL, NULL);
174 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
175
176 // read objects (one for each TTCN-3 file), until the main array end mark is reached
177 json.get_next_token(&token, NULL, NULL);
178 while (JSON_TOKEN_OBJECT_START == token) {
179 size_t file_index = 0;
180
181 // file name:
182 json.get_next_token(&token, &value, &value_len);
183 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 ||
184 0 != strncmp(value, "file", value_len));
185
186 // read the file name and see if its record already exists
187 json.get_next_token(&token, &value, &value_len);
188 IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token);
189 for (file_index = 0; file_index < p_db.size(); ++file_index) {
190 if (strlen(p_db[file_index].filename) == value_len - 2 &&
191 0 == strncmp(p_db[file_index].filename, value + 1, value_len - 2)) {
192 break;
193 }
194 }
195
196 // insert a new element if the file was not found
197 if (p_db.size() == file_index) {
198 profiler_db_item_t item;
199 item.filename = mcopystrn(value + 1, value_len - 2);
200 p_db.push_back(item);
201 }
202
203 // functions:
204 json.get_next_token(&token, &value, &value_len);
205 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 9 ||
206 0 != strncmp(value, "functions", value_len));
207
208 // read and store the functions (an array of objects, same as before)
209 json.get_next_token(&token, NULL, NULL);
210 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
211 json.get_next_token(&token, NULL, NULL);
212 while (JSON_TOKEN_OBJECT_START == token) {
213 size_t function_index = 0;
214
215 // function name:
216 json.get_next_token(&token, &value, &value_len);
217 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 ||
218 0 != strncmp(value, "name", value_len));
219
220 // read the function name, it will be checked later
221 json.get_next_token(&token, &value, &value_len);
222 IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token);
223 char* function_name = mcopystrn(value + 1, value_len - 2);
224
225 // function start line:
226 json.get_next_token(&token, &value, &value_len);
227 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
228 0 != strncmp(value, "start line", value_len));
229
230 // read the start line and check if the function already exists
231 json.get_next_token(&token, &value, &value_len);
232 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
233 int start_line = atoi(value);
234 for (function_index = 0; function_index < p_db[file_index].functions.size(); ++function_index) {
235 if (p_db[file_index].functions[function_index].lineno == start_line &&
236 0 == strcmp(p_db[file_index].functions[function_index].name, function_name)) {
237 break;
238 }
239 }
240
241 // insert a new element if the function was not found
242 if (p_db[file_index].functions.size() == function_index) {
243 profiler_db_item_t::profiler_function_data_t func_data;
244 func_data.name = function_name;
245 func_data.lineno = start_line;
246 func_data.exec_count = 0;
247 func_data.total_time.tv_sec = 0;
248 func_data.total_time.tv_usec = 0;
249 p_db[file_index].functions.push_back(func_data);
250 }
251
252 // function execution count:
253 json.get_next_token(&token, &value, &value_len);
254 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 ||
255 0 != strncmp(value, "execution count", value_len));
256
257 // read the execution count and add it to the current data
258 json.get_next_token(&token, &value, &value_len);
259 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
260 p_db[file_index].functions[function_index].exec_count += atoi(value);
261
262 // total function execution time:
263 json.get_next_token(&token, &value, &value_len);
264 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
265 0 != strncmp(value, "total time", value_len));
266
267 // read the total time and add it to the current data
268 // note: the database contains a real number, this needs to be split into 2 integers
269 json.get_next_token(&token, &value, &value_len);
270 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
271 p_db[file_index].functions[function_index].total_time = add_timeval(
272 p_db[file_index].functions[function_index].total_time, string2timeval(value));
273
274 // end of the function's object
275 json.get_next_token(&token, NULL, NULL);
276 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
277
278 // read the next token (either the start of another object or the function array end)
279 json.get_next_token(&token, NULL, NULL);
280 }
281
282 // function array end
283 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
284
285 // lines:
286 json.get_next_token(&token, &value, &value_len);
287 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 5 ||
288 0 != strncmp(value, "lines", value_len));
289
290 // read and store the lines (an array of objects, same as before)
291 json.get_next_token(&token, NULL, NULL);
292 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
293 json.get_next_token(&token, NULL, NULL);
294 while (JSON_TOKEN_OBJECT_START == token) {
295 int line_index = 0;
296
297 // line number:
298 json.get_next_token(&token, &value, &value_len);
299 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 6 ||
300 0 != strncmp(value, "number", value_len));
301
302 // read the line number and check if the line already exists
303 json.get_next_token(&token, &value, &value_len);
304 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
305 int lineno = atoi(value);
306 IMPORT_FORMAT_ERROR(lineno < 0);
307 line_index = get_line(p_db, file_index, lineno);
308 if (-1 == line_index) {
309 create_line(p_db, file_index, lineno);
310 line_index = p_db[file_index].lines.size() - 1;
311 }
312
313 // line execution count:
314 json.get_next_token(&token, &value, &value_len);
315 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 ||
316 0 != strncmp(value, "execution count", value_len));
317
318 // read the execution count and add it to the current data
319 json.get_next_token(&token, &value, &value_len);
320 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
321 p_db[file_index].lines[line_index].exec_count += atoi(value);
322
323 // total line execution time:
324 json.get_next_token(&token, &value, &value_len);
325 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
326 0 != strncmp(value, "total time", value_len));
327
328 // read the total time and add it to the current data
329 json.get_next_token(&token, &value, &value_len);
330 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
331 p_db[file_index].lines[line_index].total_time = add_timeval(
332 p_db[file_index].lines[line_index].total_time, string2timeval(value));
333
334 // end of the line's object
335 json.get_next_token(&token, NULL, NULL);
336 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
337
338 // read the next token (either the start of another object or the line array end)
339 json.get_next_token(&token, NULL, NULL);
340 }
341
342 // line array end
343 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
344
345 // end of the file's object
346 json.get_next_token(&token, NULL, NULL);
347 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
348
349 // read the next token (either the start of another object or the main array end)
350 json.get_next_token(&token, NULL, NULL);
351 }
352
353 // main array end
354 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
355 }
356
357 void export_data(profiler_db_t& p_db, const char* p_filename,
358 boolean p_disable_profiler, boolean p_disable_coverage,
359 void (*p_error_function)(const char*, ...))
360 {
361 // check whether the file can be opened for writing
362 FILE* file = fopen(p_filename, "w");
363 if (NULL == file) {
364 p_error_function("Could not open file '%s' for writing. Profiling and/or code coverage "
365 "data will not be saved.", p_filename);
366 return;
367 }
368
369 // use the JSON tokenizer to create a JSON document from the database
370 JSON_Tokenizer json(true);
371
372 // main array, contains an element for each file
373 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
374 for (size_t i = 0; i < p_db.size(); ++i) {
375
376 // each file's data is stored in an object
377 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
378
379 // store the file name
380 json.put_next_token(JSON_TOKEN_NAME, "file");
381 char* p_filename_str = mprintf("\"%s\"", p_db[i].filename);
382 json.put_next_token(JSON_TOKEN_STRING, p_filename_str);
383 Free(p_filename_str);
384
385 // store the function data in an array (one element for each function)
386 json.put_next_token(JSON_TOKEN_NAME, "functions");
387 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
388 for (size_t j = 0; j < p_db[i].functions.size(); ++j) {
389
390 // the data is stored in an object for each function
391 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
392
393 // store the function name
394 json.put_next_token(JSON_TOKEN_NAME, "name");
395 char* func_name_str = mprintf("\"%s\"", p_db[i].functions[j].name);
396 json.put_next_token(JSON_TOKEN_STRING, func_name_str);
397 Free(func_name_str);
398
399 // store the function start line
400 json.put_next_token(JSON_TOKEN_NAME, "start line");
401 char* start_line_str = mprintf("%d", p_db[i].functions[j].lineno);
402 json.put_next_token(JSON_TOKEN_NUMBER, start_line_str);
403 Free(start_line_str);
404
405 // store the function execution count
406 json.put_next_token(JSON_TOKEN_NAME, "execution count");
407 char* exec_count_str = mprintf("%d", p_disable_coverage ? 0 :
408 p_db[i].functions[j].exec_count);
409 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
410 Free(exec_count_str);
411
412 // store the function's total execution time
413 json.put_next_token(JSON_TOKEN_NAME, "total time");
414 if (p_disable_profiler) {
415 json.put_next_token(JSON_TOKEN_NUMBER, "0.000000");
416 }
417 else {
418 char* total_time_str = timeval2string(p_db[i].functions[j].total_time);
419 json.put_next_token(JSON_TOKEN_NUMBER, total_time_str);
420 Free(total_time_str);
421 }
422
423 // end of function object
424 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
425 }
426
427 // end of function data array
428 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
429
430 // store the line data in an array (one element for each line with useful data)
431 json.put_next_token(JSON_TOKEN_NAME, "lines");
432 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
433 for (size_t j = 0; j < p_db[i].lines.size(); ++j) {
434
435 // store line data in an object
436 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
437
438 // store the line number
439 json.put_next_token(JSON_TOKEN_NAME, "number");
440 char* line_number_str = mprintf("%d", p_db[i].lines[j].lineno);
441 json.put_next_token(JSON_TOKEN_NUMBER, line_number_str);
442 Free(line_number_str);
443
444 // store the line execution count
445 json.put_next_token(JSON_TOKEN_NAME, "execution count");
446 char* exec_count_str = mprintf("%d", p_disable_coverage ? 0 :
447 p_db[i].lines[j].exec_count);
448 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
449 Free(exec_count_str);
450
451 // store the line's total execution time
452 json.put_next_token(JSON_TOKEN_NAME, "total time");
453 if (p_disable_profiler) {
454 json.put_next_token(JSON_TOKEN_NUMBER, "0.000000");
455 }
456 else {
457 char* total_time_str = timeval2string(p_db[i].lines[j].total_time);
458 json.put_next_token(JSON_TOKEN_NUMBER, total_time_str);
459 Free(total_time_str);
460 }
461
462 // end of this line's object
463 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
464 }
465
466 // end of line data array
467 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
468
469 // end of this file's object
470 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
471 }
472
473 // end of main array
474 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
475
476 // write the JSON document into the file
477 fprintf(file, "%s\n", json.get_buffer());
478 fclose(file);
479 }
480
481 // Structure for one code line or function, used by print_stats for sorting
482 struct stats_data_t {
483 const char* filename; // not owned
484 const char* funcname; // not owned, NULL for code lines that don't start a function
485 int lineno;
486 timeval total_time;
487 int exec_count;
488 };
489
490 // Compare function for sorting stats data based on total execution time (descending)
491 int stats_data_cmp_time(const void* p_left, const void* p_right) {
492 const stats_data_t* p_left_data = (stats_data_t*)p_left;
493 const stats_data_t* p_right_data = (stats_data_t*)p_right;
494 if (p_left_data->total_time.tv_sec > p_right_data->total_time.tv_sec) return -1;
495 if (p_left_data->total_time.tv_sec < p_right_data->total_time.tv_sec) return 1;
496 if (p_left_data->total_time.tv_usec > p_right_data->total_time.tv_usec) return -1;
497 if (p_left_data->total_time.tv_usec < p_right_data->total_time.tv_usec) return 1;
498 return 0;
499 }
500
501 // Compare function for sorting stats data based on execution count (descending)
502 int stats_data_cmp_count(const void* p_left, const void* p_right) {
503 return ((stats_data_t*)p_right)->exec_count - ((stats_data_t*)p_left)->exec_count;
504 }
505
506 // Compare function for sorting stats data based on total time per execution count (descending)
507 int stats_data_cmp_avg(const void* p_left, const void* p_right) {
508 const stats_data_t* p_left_data = (stats_data_t*)p_left;
509 const stats_data_t* p_right_data = (stats_data_t*)p_right;
510 double left_time = p_left_data->total_time.tv_sec + p_left_data->total_time.tv_usec / 1000000.0;
511 double right_time = p_right_data->total_time.tv_sec + p_right_data->total_time.tv_usec / 1000000.0;
512 double diff = (right_time / p_right_data->exec_count) - (left_time / p_left_data->exec_count);
513 if (diff < 0) return -1;
514 if (diff > 0) return 1;
515 return 0;
516 }
517
518 void print_stats(profiler_db_t& p_db, const char* p_filename,
519 boolean p_disable_profiler, boolean p_disable_coverage,
520 unsigned int p_flags, void (*p_error_function)(const char*, ...))
521 {
522 // title
523 char* title_str = mprintf(
524 "##################################################\n"
525 "%s## TTCN-3 %s%s%sstatistics ##%s\n"
526 "##################################################\n\n\n"
527 , p_disable_profiler ? "#######" : (p_disable_coverage ? "#########" : "")
528 , p_disable_profiler ? "" : "profiler "
529 , (p_disable_profiler || p_disable_coverage) ? "" : "and "
530 , p_disable_coverage ? "" : "code coverage "
531 , p_disable_profiler ? "######" : (p_disable_coverage ? "#########" : ""));
532
533 char* line_func_count_str = NULL;
534 if (p_flags & STATS_NUMBER_OF_LINES) {
535 line_func_count_str = mcopystr(
536 "--------------------------------------\n"
537 "- Number of code lines and functions -\n"
538 "--------------------------------------\n");
539 }
540
541 // line data
542 char* line_data_str = NULL;
543 if (p_flags & STATS_LINE_DATA_RAW) {
544 line_data_str = mprintf(
545 "-------------------------------------------------\n"
546 "%s- Code line data (%s%s%s) -%s\n"
547 "-------------------------------------------------\n"
548 , p_disable_profiler ? "-------" : (p_disable_coverage ? "---------" : "")
549 , p_disable_profiler ? "" : "total time"
550 , (p_disable_profiler || p_disable_coverage) ? "" : " / "
551 , p_disable_coverage ? "" : "execution count"
552 , p_disable_profiler ? "------" : (p_disable_coverage ? "---------" : ""));
553 }
554
555 // average time / exec count for lines
556 char* line_avg_str = NULL;
557 if (!p_disable_coverage && !p_disable_profiler && (p_flags & STATS_LINE_AVG_RAW)) {
558 line_avg_str = mcopystr(
559 "-------------------------------------------\n"
560 "- Average time / execution for code lines -\n"
561 "-------------------------------------------\n");
562 }
563
564 // function data
565 char* func_data_str = NULL;
566 if (p_flags & STATS_FUNC_DATA_RAW) {
567 func_data_str = mprintf(
568 "------------------------------------------------\n"
569 "%s- Function data (%s%s%s) -%s\n"
570 "------------------------------------------------\n"
571 , p_disable_profiler ? "-------" : (p_disable_coverage ? "---------" : "")
572 , p_disable_profiler ? "" : "total time"
573 , (p_disable_profiler || p_disable_coverage) ? "" : " / "
574 , p_disable_coverage ? "" : "execution count"
575 , p_disable_profiler ? "------" : (p_disable_coverage ? "---------" : ""));
576 }
577
578 // average time / exec count for functions
579 char* func_avg_str = NULL;
580 if (!p_disable_coverage && !p_disable_profiler && (p_flags & STATS_FUNC_AVG_RAW)) {
581 func_avg_str = mcopystr(
582 "------------------------------------------\n"
583 "- Average time / execution for functions -\n"
584 "------------------------------------------\n");
585 }
586
587 char* line_time_sorted_mod_str = NULL;
588 if (!p_disable_profiler && (p_flags & STATS_LINE_TIMES_SORTED_BY_MOD)) {
589 line_time_sorted_mod_str = mcopystr(
590 "------------------------------------------------\n"
591 "- Total time of code lines, sorted, per module -\n"
592 "------------------------------------------------\n");
593 }
594
595 char* line_count_sorted_mod_str = NULL;
596 if (!p_disable_coverage && (p_flags & STATS_LINE_COUNT_SORTED_BY_MOD)) {
597 line_count_sorted_mod_str = mcopystr(
598 "-----------------------------------------------------\n"
599 "- Execution count of code lines, sorted, per module -\n"
600 "-----------------------------------------------------\n");
601 }
602
603 char* line_avg_sorted_mod_str = NULL;
604 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_LINE_AVG_SORTED_BY_MOD)) {
605 line_avg_sorted_mod_str = mcopystr(
606 "--------------------------------------------------------------\n"
607 "- Average time / execution of code lines, sorted, per module -\n"
608 "--------------------------------------------------------------\n");
609 }
610
611 char* line_time_sorted_tot_str = NULL;
612 if (!p_disable_profiler && (p_flags & STATS_LINE_TIMES_SORTED_TOTAL)) {
613 line_time_sorted_tot_str = mcopystr(
614 "-------------------------------------------\n"
615 "- Total time of code lines, sorted, total -\n"
616 "-------------------------------------------\n");
617 }
618
619 char* line_count_sorted_tot_str = NULL;
620 if (!p_disable_coverage && (p_flags & STATS_LINE_COUNT_SORTED_TOTAL)) {
621 line_count_sorted_tot_str = mcopystr(
622 "------------------------------------------------\n"
623 "- Execution count of code lines, sorted, total -\n"
624 "------------------------------------------------\n");
625 }
626
627 char* line_avg_sorted_tot_str = NULL;
628 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_LINE_AVG_SORTED_TOTAL)) {
629 line_avg_sorted_tot_str = mcopystr(
630 "---------------------------------------------------------\n"
631 "- Average time / execution of code lines, sorted, total -\n"
632 "---------------------------------------------------------\n");
633 }
634
635 char* func_time_sorted_mod_str = NULL;
636 if (!p_disable_profiler && (p_flags & STATS_FUNC_TIMES_SORTED_BY_MOD)) {
637 func_time_sorted_mod_str = mcopystr(
638 "-----------------------------------------------\n"
639 "- Total time of functions, sorted, per module -\n"
640 "-----------------------------------------------\n");
641 }
642
643 char* func_count_sorted_mod_str = NULL;
644 if (!p_disable_coverage && (p_flags & STATS_FUNC_COUNT_SORTED_BY_MOD)) {
645 func_count_sorted_mod_str = mcopystr(
646 "----------------------------------------------------\n"
647 "- Execution count of functions, sorted, per module -\n"
648 "----------------------------------------------------\n");
649 }
650
651 char* func_avg_sorted_mod_str = NULL;
652 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_FUNC_AVG_SORTED_BY_MOD)) {
653 func_avg_sorted_mod_str = mcopystr(
654 "-------------------------------------------------------------\n"
655 "- Average time / execution of functions, sorted, per module -\n"
656 "-------------------------------------------------------------\n");
657 }
658
659 char* func_time_sorted_tot_str = NULL;
660 if (!p_disable_profiler && (p_flags & STATS_FUNC_TIMES_SORTED_TOTAL)) {
661 func_time_sorted_tot_str = mcopystr(
662 "------------------------------------------\n"
663 "- Total time of functions, sorted, total -\n"
664 "------------------------------------------\n");
665 }
666
667 char* func_count_sorted_tot_str = NULL;
668 if (!p_disable_coverage && (p_flags & STATS_FUNC_COUNT_SORTED_TOTAL)) {
669 func_count_sorted_tot_str = mcopystr(
670 "-----------------------------------------------\n"
671 "- Execution count of functions, sorted, total -\n"
672 "-----------------------------------------------\n");
673 }
674
675 char* func_avg_sorted_tot_str = NULL;
676 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_FUNC_AVG_SORTED_TOTAL)) {
677 func_avg_sorted_tot_str = mcopystr(
678 "--------------------------------------------------------\n"
679 "- Average time / execution of functions, sorted, total -\n"
680 "--------------------------------------------------------\n");
681 }
682
683 char* line_time_sorted_top10_str = NULL;
684 if (!p_disable_profiler && (p_flags & STATS_TOP10_LINE_TIMES)) {
685 line_time_sorted_top10_str = mcopystr(
686 "------------------------------------\n"
687 "- Total time of code lines, top 10 -\n"
688 "------------------------------------\n");
689 }
690
691 char* line_count_sorted_top10_str = NULL;
692 if (!p_disable_coverage && (p_flags & STATS_TOP10_LINE_COUNT)) {
693 line_count_sorted_top10_str = mcopystr(
694 "-----------------------------------------\n"
695 "- Execution count of code lines, top 10 -\n"
696 "-----------------------------------------\n");
697 }
698
699 char* line_avg_sorted_top10_str = NULL;
700 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_TOP10_LINE_AVG)) {
701 line_avg_sorted_top10_str = mcopystr(
702 "--------------------------------------------------\n"
703 "- Average time / execution of code lines, top 10 -\n"
704 "--------------------------------------------------\n");
705 }
706
707 char* func_time_sorted_top10_str = NULL;
708 if (!p_disable_profiler && (p_flags & STATS_TOP10_FUNC_TIMES)) {
709 func_time_sorted_top10_str = mcopystr(
710 "-----------------------------------\n"
711 "- Total time of functions, top 10 -\n"
712 "-----------------------------------\n");
713 }
714
715 char* func_count_sorted_top10_str = NULL;
716 if (!p_disable_coverage && (p_flags & STATS_TOP10_FUNC_COUNT)) {
717 func_count_sorted_top10_str = mcopystr(
718 "----------------------------------------\n"
719 "- Execution count of functions, top 10 -\n"
720 "----------------------------------------\n");
721 }
722
723 char* func_avg_sorted_top10_str = NULL;
724 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_TOP10_FUNC_AVG)) {
725 func_avg_sorted_top10_str = mcopystr(
726 "-------------------------------------------------\n"
727 "- Average time / execution of functions, top 10 -\n"
728 "-------------------------------------------------\n");
729 }
730
731 char* unused_lines_str = NULL;
732 char* unused_func_str = NULL;
733 if (!p_disable_coverage && (p_flags & STATS_UNUSED_LINES)) {
734 unused_lines_str = mcopystr(
735 "---------------------\n"
736 "- Unused code lines -\n"
737 "---------------------\n");
738 }
739 if (!p_disable_coverage && (p_flags & STATS_UNUSED_FUNC)) {
740 unused_func_str = mcopystr(
741 "--------------------\n"
742 "- Unused functions -\n"
743 "--------------------\n");
744 }
745
746 // variables for counting totals, and for determining the amount of unused lines/functions
747 size_t total_code_lines = 0;
748 size_t total_functions = 0;
749 size_t used_code_lines = 0;
750 size_t used_functions = 0;
751
752 // cached sizes of statistics data segments, needed to determine whether a separator
753 // is needed or not
754 size_t line_data_str_len = mstrlen(line_data_str);
755 size_t func_data_str_len = mstrlen(func_data_str);
756 size_t unused_lines_str_len = mstrlen(unused_lines_str);
757 size_t unused_func_str_len = mstrlen(unused_func_str);
758 size_t line_avg_str_len = mstrlen(line_avg_str);
759 size_t func_avg_str_len = mstrlen(func_avg_str);
760
761 // cycle through the database and gather the necessary data
762 for (size_t i = 0; i < p_db.size(); ++i) {
763 if (i > 0) {
764 // add separators between files (only add them if the previous file actually added something)
765 if ((p_flags & STATS_LINE_DATA_RAW) && line_data_str_len != mstrlen(line_data_str)) {
766 line_data_str = mputstr(line_data_str, "-------------------------------------------------\n");
767 line_data_str_len = mstrlen(line_data_str);
768 }
769 if ((p_flags & STATS_FUNC_DATA_RAW) && func_data_str_len != mstrlen(func_data_str)) {
770 func_data_str = mputstr(func_data_str, "------------------------------------------------\n");
771 func_data_str_len = mstrlen(func_data_str);
772 }
773 if (!p_disable_coverage) {
774 if ((p_flags & STATS_UNUSED_LINES) && unused_lines_str_len != mstrlen(unused_lines_str)) {
775 unused_lines_str = mputstr(unused_lines_str, "---------------------\n");
776 unused_lines_str_len = mstrlen(unused_lines_str);
777 }
778 if ((p_flags & STATS_UNUSED_FUNC) && unused_func_str_len != mstrlen(unused_func_str)) {
779 unused_func_str = mputstr(unused_func_str, "--------------------\n");
780 unused_func_str_len = mstrlen(unused_func_str);
781 }
782 if (!p_disable_profiler) {
783 if ((p_flags & STATS_LINE_AVG_RAW) && line_avg_str_len != mstrlen(line_avg_str)) {
784 line_avg_str = mputstr(line_avg_str, "-------------------------------------------\n");
785 line_avg_str_len = mstrlen(line_avg_str);
786 }
787 if ((p_flags & STATS_FUNC_AVG_RAW) && func_avg_str_len != mstrlen(func_avg_str)) {
788 func_avg_str = mputstr(func_avg_str, "------------------------------------------\n");
789 func_avg_str_len = mstrlen(func_avg_str);
790 }
791 }
792 }
793 }
794
795 // lines
796 for (size_t j = 0; j < p_db[i].lines.size(); ++j) {
797 // line specification (including function name for the function's start line)
798 char* line_spec_str = mprintf("%s:%d", p_db[i].filename,
799 p_db[i].lines[j].lineno);
800 int func = get_function(p_db, i, p_db[i].lines[j].lineno);
801 if (-1 != func) {
802 line_spec_str = mputprintf(line_spec_str, " [%s]", p_db[i].functions[func].name);
803 }
804 line_spec_str = mputstrn(line_spec_str, "\n", 1);
805
806 if (p_disable_coverage || 0 != p_db[i].lines[j].exec_count) {
807 if (!p_disable_profiler) {
808 if (p_flags & STATS_LINE_DATA_RAW) {
809 char* total_time_str = timeval2string(p_db[i].lines[j].total_time);
810 line_data_str = mputprintf(line_data_str, "%ss", total_time_str);
811 Free(total_time_str);
812 }
813 if (!p_disable_coverage) {
814 if (p_flags & STATS_LINE_DATA_RAW) {
815 line_data_str = mputstrn(line_data_str, "\t/\t", 3);
816 }
817 if (p_flags & STATS_LINE_AVG_RAW) {
818 double avg = (p_db[i].lines[j].total_time.tv_sec +
819 p_db[i].lines[j].total_time.tv_usec / 1000000.0) /
820 p_db[i].lines[j].exec_count;
821 char* total_time_str = timeval2string(p_db[i].lines[j].total_time);
822 line_avg_str = mputprintf(line_avg_str, "%.6lfs\t(%ss / %d)",
823 avg, total_time_str, p_db[i].lines[j].exec_count);
824 Free(total_time_str);
825 }
826 }
827 }
828 if (!p_disable_coverage && (p_flags & STATS_LINE_DATA_RAW)) {
829 line_data_str = mputprintf(line_data_str, "%d", p_db[i].lines[j].exec_count);
830 }
831
832 // add the line spec string to the other strings
833 if (p_flags & STATS_LINE_DATA_RAW) {
834 line_data_str = mputprintf(line_data_str, "\t%s", line_spec_str);
835 }
836 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_LINE_AVG_RAW)) {
837 line_avg_str = mputprintf(line_avg_str, "\t%s", line_spec_str);
838 }
839 ++used_code_lines;
840 }
841 else if (p_flags & STATS_UNUSED_LINES) {
842 // unused line
843 unused_lines_str = mputstr(unused_lines_str, line_spec_str);
844 }
845 Free(line_spec_str);
846 }
847
848 // functions
849 for (size_t j = 0; j < p_db[i].functions.size(); ++j) {
850 // functions specification
851 char* func_spec_str = mprintf("%s:%d [%s]\n", p_db[i].filename,
852 p_db[i].functions[j].lineno, p_db[i].functions[j].name);
853
854 if (p_disable_coverage || 0 != p_db[i].functions[j].exec_count) {
855 if (!p_disable_profiler) {
856 if (p_flags & STATS_FUNC_DATA_RAW) {
857 char* total_time_str = timeval2string(p_db[i].functions[j].total_time);
858 func_data_str = mputprintf(func_data_str, "%ss", total_time_str);
859 Free(total_time_str);
860 }
861 if (!p_disable_coverage) {
862 if (p_flags & STATS_FUNC_DATA_RAW) {
863 func_data_str = mputstrn(func_data_str, "\t/\t", 3);
864 }
865 if (p_flags & STATS_FUNC_AVG_RAW) {
866 double avg = (p_db[i].functions[j].total_time.tv_sec +
867 p_db[i].functions[j].total_time.tv_usec / 1000000.0) /
868 p_db[i].functions[j].exec_count;
869 char* total_time_str = timeval2string(p_db[i].functions[j].total_time);
870 func_avg_str = mputprintf(func_avg_str, "%.6lfs\t(%ss / %d)",
871 avg, total_time_str, p_db[i].functions[j].exec_count);
872 Free(total_time_str);
873 }
874 }
875 }
876 if (!p_disable_coverage && (p_flags & STATS_FUNC_DATA_RAW)) {
877 func_data_str = mputprintf(func_data_str, "%d", p_db[i].functions[j].exec_count);
878 }
879
880 // add the line spec string to the other strings
881 if (p_flags & STATS_FUNC_DATA_RAW) {
882 func_data_str = mputprintf(func_data_str, "\t%s", func_spec_str);
883 }
884 if (!p_disable_profiler && !p_disable_coverage && (p_flags & STATS_FUNC_AVG_RAW)) {
885 func_avg_str = mputprintf(func_avg_str, "\t%s", func_spec_str);
886 }
887
888 ++used_functions;
889 }
890 else if (p_flags & STATS_UNUSED_FUNC) {
891 // unused function
892 unused_func_str = mputstr(unused_func_str, func_spec_str);
893 }
894 Free(func_spec_str);
895 }
896
897 // number of lines and functions
898 if (p_flags & STATS_NUMBER_OF_LINES) {
61025621 899 line_func_count_str = mputprintf(line_func_count_str, "%s:\t%lu lines,\t%lu functions\n",
900 p_db[i].filename, (unsigned long)(p_db[i].lines.size()), (unsigned long)(p_db[i].functions.size()));
3abe9331 901 }
902 total_code_lines += p_db[i].lines.size();
903 total_functions += p_db[i].functions.size();
904 }
905 if (p_flags & STATS_NUMBER_OF_LINES) {
906 line_func_count_str = mputprintf(line_func_count_str,
907 "--------------------------------------\n"
61025621 908 "Total:\t%lu lines,\t%lu functions\n", (unsigned long)total_code_lines, (unsigned long)total_functions);
3abe9331 909 }
910
911 if (p_flags & (STATS_TOP10_ALL_DATA | STATS_ALL_DATA_SORTED)) {
912 // copy code line and function info into stats_data_t containers for sorting
913 stats_data_t* code_line_stats = (stats_data_t*)Malloc(used_code_lines * sizeof(stats_data_t));
914 stats_data_t* function_stats = (stats_data_t*)Malloc(used_functions * sizeof(stats_data_t));
915 int line_index = 0;
916 int func_index = 0;
917
918 for (size_t i = 0; i < p_db.size(); ++i) {
919 for (size_t j = 0; j < p_db[i].lines.size(); ++j) {
920 if (p_disable_coverage || 0 != p_db[i].lines[j].exec_count) {
921 code_line_stats[line_index].filename = p_db[i].filename;
922 code_line_stats[line_index].funcname = NULL;
923 code_line_stats[line_index].lineno = p_db[i].lines[j].lineno;
924 code_line_stats[line_index].total_time = p_db[i].lines[j].total_time;
925 code_line_stats[line_index].exec_count = p_db[i].lines[j].exec_count;
926 int func = get_function(p_db, i, p_db[i].lines[j].lineno);
927 if (-1 != func) {
928 code_line_stats[line_index].funcname = p_db[i].functions[func].name;
929 }
930 ++line_index;
931 }
932 }
933 for (size_t j = 0; j < p_db[i].functions.size(); ++j) {
934 if (p_disable_coverage || 0 != p_db[i].functions[j].exec_count) {
935 function_stats[func_index].filename = p_db[i].filename;
936 function_stats[func_index].funcname = p_db[i].functions[j].name;
937 function_stats[func_index].lineno = p_db[i].functions[j].lineno;
938 function_stats[func_index].total_time = p_db[i].functions[j].total_time;
939 function_stats[func_index].exec_count = p_db[i].functions[j].exec_count;
940 ++func_index;
941 }
942 }
943 }
944
945 if (!p_disable_profiler) {
946 // sort the code lines and functions by total time
947 qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_time);
948 qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_time);
949
950 if (p_flags & (STATS_LINE_TIMES_SORTED_TOTAL | STATS_TOP10_LINE_TIMES)) {
951 // cycle through the sorted code lines and gather the necessary data
952 for (size_t i = 0; i < used_code_lines; ++i) {
953 char* total_time_str = timeval2string(code_line_stats[i].total_time);
954 char* the_data = mprintf("%ss\t%s:%d", total_time_str,
955 code_line_stats[i].filename, code_line_stats[i].lineno);
956 Free(total_time_str);
957 if (NULL != code_line_stats[i].funcname) {
958 the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname);
959 }
960 the_data = mputstrn(the_data, "\n", 1);
961 if (p_flags & STATS_LINE_TIMES_SORTED_TOTAL) {
962 line_time_sorted_tot_str = mputstr(line_time_sorted_tot_str, the_data);
963 }
964 if (i < 10 && (p_flags & STATS_TOP10_LINE_TIMES)) {
965 line_time_sorted_top10_str = mputprintf(line_time_sorted_top10_str,
966 "%2lu.\t%s", i + 1, the_data);
967 }
968 Free(the_data);
969 }
970 }
971
972 if (p_flags & (STATS_FUNC_TIMES_SORTED_TOTAL | STATS_TOP10_FUNC_TIMES)) {
973 // cycle through the sorted functions and gather the necessary data
974 for (size_t i = 0; i < used_functions; ++i) {
975 char* total_time_str = timeval2string(function_stats[i].total_time);
976 char* the_data = mprintf("%ss\t%s:%d [%s]\n", total_time_str,
977 function_stats[i].filename, function_stats[i].lineno, function_stats[i].funcname);
978 Free(total_time_str);
979 if (p_flags & STATS_FUNC_TIMES_SORTED_TOTAL) {
980 func_time_sorted_tot_str = mputstr(func_time_sorted_tot_str, the_data);
981 }
982 if (i < 10 && (p_flags & STATS_TOP10_FUNC_TIMES)) {
983 func_time_sorted_top10_str = mputprintf(func_time_sorted_top10_str,
984 "%2lu.\t%s", i + 1, the_data);
985 }
986 Free(the_data);
987 }
988 }
989
990 if (p_flags & (STATS_LINE_TIMES_SORTED_BY_MOD | STATS_FUNC_TIMES_SORTED_BY_MOD)) {
991 // cached string lengths, to avoid multiple separators after each other
992 size_t line_time_sorted_mod_str_len = mstrlen(line_time_sorted_mod_str);
993 size_t func_time_sorted_mod_str_len = mstrlen(func_time_sorted_mod_str);
994
995 // cycle through the sorted statistics and gather the necessary data per module
996 for (size_t i = 0; i < p_db.size(); ++i) {
997 if (i > 0) {
998 if ((p_flags & STATS_LINE_TIMES_SORTED_BY_MOD) &&
999 line_time_sorted_mod_str_len != mstrlen(line_time_sorted_mod_str)) {
1000 line_time_sorted_mod_str = mputstr(line_time_sorted_mod_str,
1001 "------------------------------------------------\n");
1002 line_time_sorted_mod_str_len = mstrlen(line_time_sorted_mod_str);
1003 }
1004 if ((p_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) &&
1005 func_time_sorted_mod_str_len != mstrlen(func_time_sorted_mod_str)) {
1006 func_time_sorted_mod_str = mputstr(func_time_sorted_mod_str,
1007 "-----------------------------------------------\n");
1008 func_time_sorted_mod_str_len = mstrlen(func_time_sorted_mod_str);
1009 }
1010 }
1011 if (p_flags & STATS_LINE_TIMES_SORTED_BY_MOD) {
1012 for (size_t j = 0; j < used_code_lines; ++j) {
1013 if (0 == strcmp(code_line_stats[j].filename, p_db[i].filename)) {
1014 char* total_time_str = timeval2string(code_line_stats[j].total_time);
1015 line_time_sorted_mod_str = mputprintf(line_time_sorted_mod_str,
1016 "%ss\t%s:%d", total_time_str, code_line_stats[j].filename,
1017 code_line_stats[j].lineno);
1018 Free(total_time_str);
1019 if (NULL != code_line_stats[j].funcname) {
1020 line_time_sorted_mod_str = mputprintf(line_time_sorted_mod_str,
1021 " [%s]", code_line_stats[j].funcname);
1022 }
1023 line_time_sorted_mod_str = mputstrn(line_time_sorted_mod_str, "\n", 1);
1024 }
1025 }
1026 }
1027 if (p_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) {
1028 for (size_t j = 0; j < used_functions; ++j) {
1029 if (0 == strcmp(function_stats[j].filename, p_db[i].filename)) {
1030 char* total_time_str = timeval2string(function_stats[j].total_time);
1031 func_time_sorted_mod_str = mputprintf(func_time_sorted_mod_str,
1032 "%ss\t%s:%d [%s]\n", total_time_str, function_stats[j].filename,
1033 function_stats[j].lineno, function_stats[j].funcname);
1034 Free(total_time_str);
1035 }
1036 }
1037 }
1038 }
1039 }
1040 }
1041
1042 if (!p_disable_coverage) {
1043 // sort the code lines and functions by execution count
1044 qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_count);
1045 qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_count);
1046
1047 if (p_flags & (STATS_LINE_COUNT_SORTED_TOTAL | STATS_TOP10_LINE_COUNT)) {
1048 // cycle through the sorted code lines and gather the necessary data
1049 for (size_t i = 0; i < used_code_lines; ++i) {
1050 char* the_data = mprintf("%d\t%s:%d", code_line_stats[i].exec_count,
1051 code_line_stats[i].filename, code_line_stats[i].lineno);
1052 if (NULL != code_line_stats[i].funcname) {
1053 the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname);
1054 }
1055 the_data = mputstrn(the_data, "\n", 1);
1056 if (p_flags & STATS_LINE_COUNT_SORTED_TOTAL) {
1057 line_count_sorted_tot_str = mputstr(line_count_sorted_tot_str, the_data);
1058 }
1059 if (i < 10 && (p_flags & STATS_TOP10_LINE_COUNT)) {
1060 line_count_sorted_top10_str = mputprintf(line_count_sorted_top10_str,
1061 "%2lu.\t%s", i + 1, the_data);
1062 }
1063 Free(the_data);
1064 }
1065 }
1066
1067 if (p_flags & (STATS_FUNC_COUNT_SORTED_TOTAL | STATS_TOP10_FUNC_COUNT)) {
1068 // cycle through the sorted functions and gather the necessary data
1069 for (size_t i = 0; i < used_functions; ++i) {
1070 char* the_data = mprintf("%d\t%s:%d [%s]\n",
1071 function_stats[i].exec_count, function_stats[i].filename,
1072 function_stats[i].lineno, function_stats[i].funcname);
1073 if (p_flags & STATS_FUNC_COUNT_SORTED_TOTAL) {
1074 func_count_sorted_tot_str = mputstr(func_count_sorted_tot_str, the_data);
1075 }
1076 if (i < 10 && (p_flags & STATS_TOP10_FUNC_COUNT)) {
1077 func_count_sorted_top10_str = mputprintf(func_count_sorted_top10_str,
1078 "%2lu.\t%s", i + 1, the_data);
1079 }
1080 Free(the_data);
1081 }
1082 }
1083
1084 if (p_flags & (STATS_LINE_COUNT_SORTED_BY_MOD | STATS_FUNC_COUNT_SORTED_BY_MOD)) {
1085 // cached string lengths, to avoid multiple separators after each other
1086 size_t line_count_sorted_mod_str_len = mstrlen(line_count_sorted_mod_str);
1087 size_t func_count_sorted_mod_str_len = mstrlen(func_count_sorted_mod_str);
1088
1089 // cycle through the sorted statistics and gather the necessary data per module
1090 for (size_t i = 0; i < p_db.size(); ++i) {
1091 if (i > 0) {
1092 if ((p_flags & STATS_LINE_COUNT_SORTED_BY_MOD) &&
1093 line_count_sorted_mod_str_len != mstrlen(line_count_sorted_mod_str)) {
1094 line_count_sorted_mod_str = mputstr(line_count_sorted_mod_str,
1095 "-----------------------------------------------------\n");
1096 line_count_sorted_mod_str_len = mstrlen(line_count_sorted_mod_str);
1097 }
1098 if ((p_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) &&
1099 func_count_sorted_mod_str_len != mstrlen(func_count_sorted_mod_str)) {
1100 func_count_sorted_mod_str = mputstr(func_count_sorted_mod_str,
1101 "----------------------------------------------------\n");
1102 func_count_sorted_mod_str_len = mstrlen(func_count_sorted_mod_str);
1103 }
1104 }
1105 if (p_flags & STATS_LINE_COUNT_SORTED_BY_MOD) {
1106 for (size_t j = 0; j < used_code_lines; ++j) {
1107 if (0 == strcmp(code_line_stats[j].filename, p_db[i].filename)) {
1108 line_count_sorted_mod_str = mputprintf(line_count_sorted_mod_str,
1109 "%d\t%s:%d", code_line_stats[j].exec_count, code_line_stats[j].filename,
1110 code_line_stats[j].lineno);
1111 if (NULL != code_line_stats[j].funcname) {
1112 line_count_sorted_mod_str = mputprintf(line_count_sorted_mod_str,
1113 " [%s]", code_line_stats[j].funcname);
1114 }
1115 line_count_sorted_mod_str = mputstrn(line_count_sorted_mod_str, "\n", 1);
1116 }
1117 }
1118 }
1119 if (p_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) {
1120 for (size_t j = 0; j < used_functions; ++j) {
1121 if (0 == strcmp(function_stats[j].filename, p_db[i].filename)) {
1122 func_count_sorted_mod_str = mputprintf(func_count_sorted_mod_str,
1123 "%d\t%s:%d [%s]\n", function_stats[j].exec_count, function_stats[j].filename,
1124 function_stats[j].lineno, function_stats[j].funcname);
1125 }
1126 }
1127 }
1128 }
1129 }
1130 }
1131
1132 if (!p_disable_profiler && !p_disable_coverage) {
1133 // sort the code lines and functions by average time / execution
1134 qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_avg);
1135 qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_avg);
1136
1137 if (p_flags & (STATS_LINE_AVG_SORTED_TOTAL | STATS_TOP10_LINE_AVG)) {
1138 // cycle through the sorted code lines and gather the necessary data
1139 for (size_t i = 0; i < used_code_lines; ++i) {
1140 double avg = (code_line_stats[i].total_time.tv_sec +
1141 code_line_stats[i].total_time.tv_usec / 1000000.0) /
1142 code_line_stats[i].exec_count;
1143 char* total_time_str = timeval2string(code_line_stats[i].total_time);
1144 char* the_data = mprintf("%.6lfs\t(%ss / %d)\t%s:%d",
1145 avg, total_time_str, code_line_stats[i].exec_count,
1146 code_line_stats[i].filename, code_line_stats[i].lineno);
1147 Free(total_time_str);
1148 if (NULL != code_line_stats[i].funcname) {
1149 the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname);
1150 }
1151 the_data = mputstrn(the_data, "\n", 1);
1152 if (p_flags & STATS_LINE_AVG_SORTED_TOTAL) {
1153 line_avg_sorted_tot_str = mputstr(line_avg_sorted_tot_str, the_data);
1154 }
1155 if (i < 10 && (p_flags & STATS_TOP10_LINE_AVG)) {
1156 line_avg_sorted_top10_str = mputprintf(line_avg_sorted_top10_str,
1157 "%2lu.\t%s", i + 1, the_data);
1158 }
1159 Free(the_data);
1160 }
1161 }
1162
1163 if (p_flags & (STATS_FUNC_AVG_SORTED_TOTAL | STATS_TOP10_FUNC_AVG)) {
1164 // cycle through the sorted functions and gather the necessary data
1165 for (size_t i = 0; i < used_functions; ++i) {
1166 double avg = (function_stats[i].total_time.tv_sec +
1167 function_stats[i].total_time.tv_usec / 1000000.0) /
1168 function_stats[i].exec_count;
1169 char* total_time_str = timeval2string(function_stats[i].total_time);
1170 char* the_data = mprintf("%.6lfs\t(%ss / %d)\t%s:%d [%s]\n",
1171 avg, total_time_str, function_stats[i].exec_count,
1172 function_stats[i].filename, function_stats[i].lineno, function_stats[i].funcname);
1173 Free(total_time_str);
1174 if (p_flags & STATS_FUNC_AVG_SORTED_TOTAL) {
1175 func_avg_sorted_tot_str = mputstr(func_avg_sorted_tot_str, the_data);
1176 }
1177 if (i < 10 && (p_flags & STATS_TOP10_FUNC_AVG)) {
1178 func_avg_sorted_top10_str = mputprintf(func_avg_sorted_top10_str,
1179 "%2lu.\t%s", i + 1, the_data);
1180 }
1181 Free(the_data);
1182 }
1183 }
1184
1185 if (p_flags & (STATS_LINE_AVG_SORTED_BY_MOD | STATS_FUNC_AVG_SORTED_BY_MOD)) {
1186 // cached string lengths, to avoid multiple separators after each other
1187 size_t line_avg_sorted_mod_str_len = mstrlen(line_avg_sorted_mod_str);
1188 size_t func_avg_sorted_mod_str_len = mstrlen(func_avg_sorted_mod_str);
1189
1190 // cycle through the sorted statistics and gather the necessary data per module
1191 for (size_t i = 0; i < p_db.size(); ++i) {
1192 if (i > 0) {
1193 if ((p_flags & STATS_LINE_AVG_SORTED_BY_MOD) &&
1194 line_avg_sorted_mod_str_len != mstrlen(line_avg_sorted_mod_str)) {
1195 line_avg_sorted_mod_str = mputstr(line_avg_sorted_mod_str,
1196 "--------------------------------------------------------------\n");
1197 line_avg_sorted_mod_str_len = mstrlen(line_avg_sorted_mod_str);
1198 }
1199 if ((p_flags & STATS_FUNC_AVG_SORTED_BY_MOD) &&
1200 func_avg_sorted_mod_str_len != mstrlen(func_avg_sorted_mod_str)) {
1201 func_avg_sorted_mod_str = mputstr(func_avg_sorted_mod_str,
1202 "-------------------------------------------------------------\n");
1203 func_avg_sorted_mod_str_len = mstrlen(func_avg_sorted_mod_str);
1204 }
1205 }
1206 if (p_flags & STATS_LINE_AVG_SORTED_BY_MOD) {
1207 for (size_t j = 0; j < used_code_lines; ++j) {
1208 if (0 == strcmp(code_line_stats[j].filename, p_db[i].filename)) {
1209 double avg = (code_line_stats[j].total_time.tv_sec +
1210 code_line_stats[j].total_time.tv_usec / 1000000.0) /
1211 code_line_stats[j].exec_count;
1212 char* total_time_str = timeval2string(code_line_stats[j].total_time);
1213 line_avg_sorted_mod_str = mputprintf(line_avg_sorted_mod_str,
1214 "%.6lfs\t(%ss / %d)\t%s:%d",
1215 avg, total_time_str, code_line_stats[j].exec_count,
1216 code_line_stats[j].filename, code_line_stats[j].lineno);
1217 Free(total_time_str);
1218 if (NULL != code_line_stats[j].funcname) {
1219 line_avg_sorted_mod_str = mputprintf(line_avg_sorted_mod_str,
1220 " [%s]", code_line_stats[j].funcname);
1221 }
1222 line_avg_sorted_mod_str = mputstrn(line_avg_sorted_mod_str, "\n", 1);
1223 }
1224 }
1225 }
1226 if (p_flags & STATS_FUNC_AVG_SORTED_BY_MOD) {
1227 for (size_t j = 0; j < used_functions; ++j) {
1228 if (0 == strcmp(function_stats[j].filename, p_db[i].filename)) {
1229 double avg = (function_stats[j].total_time.tv_sec +
1230 function_stats[j].total_time.tv_usec / 1000000.0) /
1231 function_stats[j].exec_count;
1232 char* total_time_str = timeval2string(function_stats[j].total_time);
1233 func_avg_sorted_mod_str = mputprintf(func_avg_sorted_mod_str,
1234 "%.6lfs\t(%ss / %d)\t%s:%d [%s]\n",
1235 avg, total_time_str, function_stats[j].exec_count,
1236 function_stats[j].filename, function_stats[j].lineno, function_stats[j].funcname);
1237 Free(total_time_str);
1238 }
1239 }
1240 }
1241 }
1242 }
1243 }
1244
1245 // free the stats data
1246 Free(code_line_stats);
1247 Free(function_stats);
1248 }
1249
1250 // add new lines at the end of each segment
1251 if (p_flags & STATS_NUMBER_OF_LINES) {
1252 line_func_count_str = mputstrn(line_func_count_str, "\n", 1);
1253 }
1254 if (p_flags & STATS_LINE_DATA_RAW) {
1255 line_data_str = mputstrn(line_data_str, "\n", 1);
1256 }
1257 if (p_flags & STATS_FUNC_DATA_RAW) {
1258 func_data_str = mputstrn(func_data_str, "\n", 1);
1259 }
1260 if (!p_disable_profiler) {
1261 if (p_flags & STATS_LINE_TIMES_SORTED_BY_MOD) {
1262 line_time_sorted_mod_str = mputstrn(line_time_sorted_mod_str, "\n", 1);
1263 }
1264 if (p_flags & STATS_LINE_TIMES_SORTED_TOTAL) {
1265 line_time_sorted_tot_str = mputstrn(line_time_sorted_tot_str, "\n", 1);
1266 }
1267 if (p_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) {
1268 func_time_sorted_mod_str = mputstrn(func_time_sorted_mod_str, "\n", 1);
1269 }
1270 if (p_flags & STATS_FUNC_TIMES_SORTED_TOTAL) {
1271 func_time_sorted_tot_str = mputstrn(func_time_sorted_tot_str, "\n", 1);
1272 }
1273 if (p_flags & STATS_TOP10_LINE_TIMES) {
1274 line_time_sorted_top10_str = mputstrn(line_time_sorted_top10_str, "\n", 1);
1275 }
1276 if (p_flags & STATS_TOP10_FUNC_TIMES) {
1277 func_time_sorted_top10_str = mputstrn(func_time_sorted_top10_str, "\n", 1);
1278 }
1279 if (!p_disable_coverage) {
1280 if (p_flags & STATS_LINE_AVG_RAW) {
1281 line_avg_str = mputstrn(line_avg_str, "\n", 1);
1282 }
1283 if (p_flags & STATS_LINE_AVG_RAW) {
1284 func_avg_str = mputstrn(func_avg_str, "\n", 1);
1285 }
1286 if (p_flags & STATS_LINE_AVG_SORTED_BY_MOD) {
1287 line_avg_sorted_mod_str = mputstrn(line_avg_sorted_mod_str, "\n", 1);
1288 }
1289 if (p_flags & STATS_LINE_AVG_SORTED_TOTAL) {
1290 line_avg_sorted_tot_str = mputstrn(line_avg_sorted_tot_str, "\n", 1);
1291 }
1292 if (p_flags & STATS_FUNC_AVG_SORTED_BY_MOD) {
1293 func_avg_sorted_mod_str = mputstrn(func_avg_sorted_mod_str, "\n", 1);
1294 }
1295 if (p_flags & STATS_FUNC_AVG_SORTED_TOTAL) {
1296 func_avg_sorted_tot_str = mputstrn(func_avg_sorted_tot_str, "\n", 1);
1297 }
1298 if (p_flags & STATS_TOP10_LINE_AVG) {
1299 line_avg_sorted_top10_str = mputstrn(line_avg_sorted_top10_str, "\n", 1);
1300 }
1301 if (p_flags & STATS_TOP10_FUNC_AVG) {
1302 func_avg_sorted_top10_str = mputstrn(func_avg_sorted_top10_str, "\n", 1);
1303 }
1304 }
1305 }
1306 if (!p_disable_coverage) {
1307 if (p_flags & STATS_LINE_COUNT_SORTED_BY_MOD) {
1308 line_count_sorted_mod_str = mputstrn(line_count_sorted_mod_str, "\n", 1);
1309 }
1310 if (p_flags & STATS_LINE_COUNT_SORTED_TOTAL) {
1311 line_count_sorted_tot_str = mputstrn(line_count_sorted_tot_str, "\n", 1);
1312 }
1313 if (p_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) {
1314 func_count_sorted_mod_str = mputstrn(func_count_sorted_mod_str, "\n", 1);
1315 }
1316 if (p_flags & STATS_FUNC_COUNT_SORTED_TOTAL) {
1317 func_count_sorted_tot_str = mputstrn(func_count_sorted_tot_str, "\n", 1);
1318 }
1319 if (p_flags & STATS_TOP10_LINE_COUNT) {
1320 line_count_sorted_top10_str = mputstrn(line_count_sorted_top10_str, "\n", 1);
1321 }
1322 if (p_flags & STATS_TOP10_FUNC_COUNT) {
1323 func_count_sorted_top10_str = mputstrn(func_count_sorted_top10_str, "\n", 1);
1324 }
1325 if (p_flags & STATS_UNUSED_LINES) {
1326 unused_lines_str = mputstrn(unused_lines_str, "\n", 1);
1327 }
1328 if (p_flags & STATS_UNUSED_FUNC) {
1329 unused_func_str = mputstrn(unused_func_str, "\n", 1);
1330 }
1331 }
1332
1333 // write the statistics to the specified file
1334 FILE* file = fopen(p_filename, "w");
1335 if (NULL == file) {
1336 p_error_function("Could not open file '%s' for writing. Profiling and/or "
1337 "code coverage statistics will not be saved.", p_filename);
1338 return;
1339 }
1340 // by now the strings for all disabled statistics entries should be null
1341 fprintf(file, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
1342 , title_str
1343 , (NULL != line_func_count_str) ? line_func_count_str : ""
1344 , (NULL != line_data_str) ? line_data_str : ""
1345 , (NULL != line_avg_str) ? line_avg_str : ""
1346 , (NULL != func_data_str) ? func_data_str : ""
1347 , (NULL != func_avg_str) ? func_avg_str : ""
1348 , (NULL != line_time_sorted_mod_str) ? line_time_sorted_mod_str : ""
1349 , (NULL != line_time_sorted_tot_str) ? line_time_sorted_tot_str : ""
1350 , (NULL != func_time_sorted_mod_str) ? func_time_sorted_mod_str : ""
1351 , (NULL != func_time_sorted_tot_str) ? func_time_sorted_tot_str : ""
1352 , (NULL != line_count_sorted_mod_str) ? line_count_sorted_mod_str : ""
1353 , (NULL != line_count_sorted_tot_str) ? line_count_sorted_tot_str : ""
1354 , (NULL != func_count_sorted_mod_str) ? func_count_sorted_mod_str : ""
1355 , (NULL != func_count_sorted_tot_str) ? func_count_sorted_tot_str : ""
1356 , (NULL != line_avg_sorted_mod_str) ? line_avg_sorted_mod_str : ""
1357 , (NULL != line_avg_sorted_tot_str) ? line_avg_sorted_tot_str : ""
1358 , (NULL != func_avg_sorted_mod_str) ? func_avg_sorted_mod_str : ""
1359 , (NULL != func_avg_sorted_tot_str) ? func_avg_sorted_tot_str : ""
1360 , (NULL != line_time_sorted_top10_str) ? line_time_sorted_top10_str : ""
1361 , (NULL != func_time_sorted_top10_str) ? func_time_sorted_top10_str : ""
1362 , (NULL != line_count_sorted_top10_str) ? line_count_sorted_top10_str : ""
1363 , (NULL != func_count_sorted_top10_str) ? func_count_sorted_top10_str : ""
1364 , (NULL != line_avg_sorted_top10_str) ? line_avg_sorted_top10_str : ""
1365 , (NULL != func_avg_sorted_top10_str) ? func_avg_sorted_top10_str : ""
1366 , (NULL != unused_lines_str) ? unused_lines_str : ""
1367 , (NULL != unused_func_str) ? unused_func_str : "");
1368
1369 fclose(file);
1370
1371 // free the strings
1372 Free(title_str);
1373 Free(line_func_count_str);
1374 Free(line_data_str);
1375 Free(line_avg_str);
1376 Free(func_data_str);
1377 Free(func_avg_str);
1378 Free(line_time_sorted_mod_str);
1379 Free(line_time_sorted_tot_str);
1380 Free(func_time_sorted_mod_str);
1381 Free(func_time_sorted_tot_str);
1382 Free(line_count_sorted_mod_str);
1383 Free(line_count_sorted_tot_str);
1384 Free(func_count_sorted_mod_str);
1385 Free(func_count_sorted_tot_str);
1386 Free(line_avg_sorted_mod_str);
1387 Free(line_avg_sorted_tot_str);
1388 Free(func_avg_sorted_mod_str);
1389 Free(func_avg_sorted_tot_str);
1390 Free(line_time_sorted_top10_str);
1391 Free(func_time_sorted_top10_str);
1392 Free(line_count_sorted_top10_str);
1393 Free(func_count_sorted_top10_str);
1394 Free(line_avg_sorted_top10_str);
1395 Free(func_avg_sorted_top10_str);
1396 Free(unused_lines_str);
1397 Free(unused_func_str);
1398 }
1399
1400} // namespace
This page took 0.083757 seconds and 5 git commands to generate.