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 | |
22 | namespace 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 |