function_test/Semantic_Analyser/xer/aa_optional_SE.ttcn removed
[deliverable/titan.core.git] / core / Profiler.cc
CommitLineData
af710487 1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2015 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
9#include "Profiler.hh"
10#include <sys/time.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include "JSON_Tokenizer.hh"
15#include "memory.h"
16#include "Runtime.hh"
17
18////////////////////////////////////
19////////// TTCN3_Profiler //////////
20////////////////////////////////////
21
22TTCN3_Profiler ttcn3_prof;
23
24TTCN3_Profiler::TTCN3_Profiler()
25: disable_profiler(FALSE), disable_coverage(FALSE), aggregate_data(FALSE)
26, disable_stats(FALSE)
27{
28 database_filename = mcopystr("profiler.db");
29 stats_filename = mcopystr("profiler.stats");
30 reset();
31}
32
33TTCN3_Profiler::~TTCN3_Profiler()
34{
35 if (!disable_profiler || !disable_coverage) {
36 import_data();
37 export_data();
38 if (!disable_stats && (TTCN_Runtime::is_single() || TTCN_Runtime::is_hc())) {
39 print_stats();
40 }
41 }
42 for (size_t i = 0; i < profiler_db.size(); ++i) {
43 Free(profiler_db[i].filename);
44 for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) {
45 Free(profiler_db[i].functions[j].name);
46 }
47 }
48 Free(database_filename);
49 Free(stats_filename);
50}
51
52void TTCN3_Profiler::set_disable_profiler(boolean p_disable_profiler)
53{
54 disable_profiler = p_disable_profiler;
55}
56
57void TTCN3_Profiler::set_disable_coverage(boolean p_disable_coverage)
58{
59 disable_coverage = p_disable_coverage;
60}
61
62void TTCN3_Profiler::set_database_filename(const char* p_database_filename)
63{
64 Free(database_filename);
65 database_filename = mcopystr(p_database_filename);
66}
67
68void TTCN3_Profiler::set_aggregate_data(boolean p_aggregate_data)
69{
70 aggregate_data = p_aggregate_data;
71}
72
73void TTCN3_Profiler::set_stats_filename(const char* p_stats_filename)
74{
75 Free(stats_filename);
76 stats_filename = mcopystr(p_stats_filename);
77}
78
79void TTCN3_Profiler::set_disable_stats(boolean p_disable_stats)
80{
81 disable_stats = p_disable_stats;
82}
83
84boolean TTCN3_Profiler::is_profiler_disabled() const
85{
86 return disable_profiler;
87}
88
89#define IMPORT_FORMAT_ERROR(cond) \
90 if (cond) { \
91 TTCN_warning("Database format is invalid. Profiler and/or code coverage data will not be loaded."); \
92 return; \
93 }
94
95void TTCN3_Profiler::init_data_file()
96{
97 // delete the database file (from the previous run) if data aggregation is not set
98 if (!aggregate_data && (!disable_profiler || !disable_coverage)) {
99 remove(database_filename);
100 }
101}
102
103void TTCN3_Profiler::import_data()
104{
105 // open the file, if it exists
106 FILE* file = fopen(database_filename, "r");
107 if (NULL == file) {
108 return;
109 }
110
111 // get the file size
112 fseek(file, 0, SEEK_END);
113 int file_size = ftell(file);
114 rewind(file);
115
116 // read the entire file into a character buffer
117 char* buffer = (char*)Malloc(file_size);
118 fread(buffer, 1, file_size, file);
119
120 // initialize a JSON tokenizer with the buffer
121 JSON_Tokenizer json(buffer, file_size);
122 Free(buffer);
123
124 // attempt to read tokens from the buffer
125 // if the format is invalid, abort the importing process
126 json_token_t token = JSON_TOKEN_NONE;
127 char* value = NULL;
128 size_t value_len = 0;
129
130 // start of main array
131 json.get_next_token(&token, NULL, NULL);
132 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
133
134 // read objects (one for each TTCN-3 file), until the main array end mark is reached
135 json.get_next_token(&token, NULL, NULL);
136 while (JSON_TOKEN_OBJECT_START == token) {
137 size_t file_index = 0;
138
139 // file name:
140 json.get_next_token(&token, &value, &value_len);
141 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 ||
142 0 != strncmp(value, "file", value_len));
143
144 // read the file name and see if its record already exists
145 json.get_next_token(&token, &value, &value_len);
146 IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token);
147 for (file_index = 0; file_index < profiler_db.size(); ++file_index) {
148 if (strlen(profiler_db[file_index].filename) == value_len - 2 &&
149 0 == strncmp(profiler_db[file_index].filename, value + 1, value_len - 2)) {
150 break;
151 }
152 }
153
154 // insert a new element if the file was not found
155 if (profiler_db.size() == file_index) {
156 profiler_db_item_t item;
157 item.filename = mcopystrn(value + 1, value_len - 2);
158 profiler_db.push_back(item);
159 }
160
161 // functions:
162 json.get_next_token(&token, &value, &value_len);
163 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 9 ||
164 0 != strncmp(value, "functions", value_len));
165
166 // read and store the functions (an array of objects, same as before)
167 json.get_next_token(&token, NULL, NULL);
168 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
169 json.get_next_token(&token, NULL, NULL);
170 while (JSON_TOKEN_OBJECT_START == token) {
171 size_t function_index = 0;
172
173 // function name:
174 json.get_next_token(&token, &value, &value_len);
175 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 ||
176 0 != strncmp(value, "name", value_len));
177
178 // read the function name, it will be checked later
179 json.get_next_token(&token, &value, &value_len);
180 IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token);
181 char* function_name = mcopystrn(value + 1, value_len - 2);
182
183 // function start line:
184 json.get_next_token(&token, &value, &value_len);
185 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
186 0 != strncmp(value, "start line", value_len));
187
188 // read the start line and check if the function already exists
189 json.get_next_token(&token, &value, &value_len);
190 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
191 int start_line = atoi(value);
192 for (function_index = 0; function_index < profiler_db[file_index].functions.size(); ++function_index) {
193 if (profiler_db[file_index].functions[function_index].lineno == start_line &&
194 0 == strcmp(profiler_db[file_index].functions[function_index].name, function_name)) {
195 break;
196 }
197 }
198
199 // insert a new element if the function was not found
200 if (profiler_db[file_index].functions.size() == function_index) {
201 profiler_db_item_t::profiler_function_data_t func_data;
202 func_data.name = function_name;
203 func_data.lineno = start_line;
204 func_data.exec_count = 0;
205 func_data.total_time = 0.0;
206 profiler_db[file_index].functions.push_back(func_data);
207 }
208
209 if (!disable_coverage) {
210 // function execution count:
211 json.get_next_token(&token, &value, &value_len);
212 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 ||
213 0 != strncmp(value, "execution count", value_len));
214
215 // read the execution count and add it to the current data
216 json.get_next_token(&token, &value, &value_len);
217 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
218 profiler_db[file_index].functions[function_index].exec_count += atoi(value);
219 }
220
221 if (!disable_profiler) {
222 // total function execution time:
223 json.get_next_token(&token, &value, &value_len);
224 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
225 0 != strncmp(value, "total time", value_len));
226
227 // read the total time and add it to the current data
228 json.get_next_token(&token, &value, &value_len);
229 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
230 profiler_db[file_index].functions[function_index].total_time += atof(value);
231 }
232
233 // end of the function's object
234 json.get_next_token(&token, NULL, NULL);
235 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
236
237 // read the next token (either the start of another object or the function array end)
238 json.get_next_token(&token, NULL, NULL);
239 }
240
241 // function array end
242 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
243
244 // lines:
245 json.get_next_token(&token, &value, &value_len);
246 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 5 ||
247 0 != strncmp(value, "lines", value_len));
248
249 // read and store the lines (an array of objects, same as before)
250 json.get_next_token(&token, NULL, NULL);
251 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token);
252 json.get_next_token(&token, NULL, NULL);
253 while (JSON_TOKEN_OBJECT_START == token) {
254
255 // line number:
256 json.get_next_token(&token, &value, &value_len);
257 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 6 ||
258 0 != strncmp(value, "number", value_len));
259
260 // read the line number and check if the line already exists
261 json.get_next_token(&token, &value, &value_len);
262 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
263 int lineno = atoi(value);
264 IMPORT_FORMAT_ERROR(lineno < 0);
265 size_t line_no = lineno;
266 if (line_no >= profiler_db[file_index].lines.size()) {
267 for (size_t i = profiler_db[file_index].lines.size(); i <= line_no; ++i) {
268 profiler_db_item_t::profiler_line_data_t line_data;
269 line_data.total_time = 0.0;
270 line_data.exec_count = 0;
271 profiler_db[file_index].lines.push_back(line_data);
272 }
273 }
274
275 if (!disable_coverage) {
276 // line execution count:
277 json.get_next_token(&token, &value, &value_len);
278 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 ||
279 0 != strncmp(value, "execution count", value_len));
280
281 // read the execution count and add it to the current data
282 json.get_next_token(&token, &value, &value_len);
283 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
284 profiler_db[file_index].lines[line_no].exec_count += atoi(value);
285 }
286
287 if (!disable_profiler) {
288 // total line execution time:
289 json.get_next_token(&token, &value, &value_len);
290 IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 ||
291 0 != strncmp(value, "total time", value_len));
292
293 // read the total time and add it to the current data
294 json.get_next_token(&token, &value, &value_len);
295 IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token);
296 profiler_db[file_index].lines[line_no].total_time += atof(value);
297 }
298
299 // end of the line's object
300 json.get_next_token(&token, NULL, NULL);
301 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
302
303 // read the next token (either the start of another object or the line array end)
304 json.get_next_token(&token, NULL, NULL);
305 }
306
307 // line array end
308 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
309
310 // end of the file's object
311 json.get_next_token(&token, NULL, NULL);
312 IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token);
313
314 // read the next token (either the start of another object or the main array end)
315 json.get_next_token(&token, NULL, NULL);
316 }
317
318 // main array end
319 IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token);
320}
321
322void TTCN3_Profiler::export_data()
323{
324 // nothing to export if the database is empty
325 if (profiler_db.empty()) {
326 return;
327 }
328
329 // check whether the file can be opened for writing
330 FILE* file = fopen(database_filename, "w");
331 if (NULL == file) {
332 TTCN_warning("Could not open file '%s' for writing. Profiler and/or code coverage "
333 "data will not be saved.", database_filename);
334 return;
335 }
336
337 // use the JSON tokenizer to create a JSON document from the database
338 JSON_Tokenizer json(true);
339
340 // main array, contains an element for each file
341 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
342 for (size_t i = 0; i < profiler_db.size(); ++i) {
343
344 // each file's data is stored in an object
345 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
346
347 // store the file name
348 json.put_next_token(JSON_TOKEN_NAME, "file");
349 char* file_name_str = mprintf("\"%s\"", profiler_db[i].filename);
350 json.put_next_token(JSON_TOKEN_STRING, file_name_str);
351 Free(file_name_str);
352
353 // store the function data in an array (one element for each function)
354 json.put_next_token(JSON_TOKEN_NAME, "functions");
355 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
356 for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) {
357
358 // the data is stored in an object for each function
359 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
360
361 // store the function name
362 json.put_next_token(JSON_TOKEN_NAME, "name");
363 char* func_name_str = mprintf("\"%s\"", profiler_db[i].functions[j].name);
364 json.put_next_token(JSON_TOKEN_STRING, func_name_str);
365 Free(func_name_str);
366
367 // store the function start line
368 json.put_next_token(JSON_TOKEN_NAME, "start line");
369 char* start_line_str = mprintf("%d", profiler_db[i].functions[j].lineno);
370 json.put_next_token(JSON_TOKEN_NUMBER, start_line_str);
371 Free(start_line_str);
372
373 if (!disable_coverage) {
374 // store the function execution count
375 json.put_next_token(JSON_TOKEN_NAME, "execution count");
376 char* exec_count_str = mprintf("%d", profiler_db[i].functions[j].exec_count);
377 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
378 Free(exec_count_str);
379 }
380
381 if (!disable_profiler) {
382 // store the function's total execution time
383 json.put_next_token(JSON_TOKEN_NAME, "total time");
384 char* exec_count_str = mprintf("%.6lf", profiler_db[i].functions[j].total_time);
385 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
386 Free(exec_count_str);
387 }
388
389 // end of function object
390 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
391 }
392
393 // end of function data array
394 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
395
396 // store the line data in an array (one element for each line with useful data)
397 json.put_next_token(JSON_TOKEN_NAME, "lines");
398 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
399 for (size_t j = 0; j < profiler_db[i].lines.size(); ++j) {
400 if (0.0 != profiler_db[i].lines[j].total_time ||
401 0 != profiler_db[i].lines[j].exec_count) {
402
403 // store line data in an object
404 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
405
406 // store the line number
407 json.put_next_token(JSON_TOKEN_NAME, "number");
408 char* line_number_str = mprintf("%lu", j);
409 json.put_next_token(JSON_TOKEN_NUMBER, line_number_str);
410 Free(line_number_str);
411
412 if (!disable_coverage) {
413 // store the line execution count
414 json.put_next_token(JSON_TOKEN_NAME, "execution count");
415 char* exec_count_str = mprintf("%d", profiler_db[i].lines[j].exec_count);
416 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
417 Free(exec_count_str);
418 }
419
420 if (!disable_profiler) {
421 // store the line's total execution time
422 json.put_next_token(JSON_TOKEN_NAME, "total time");
423 char* exec_count_str = mprintf("%.6lf", profiler_db[i].lines[j].total_time);
424 json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str);
425 Free(exec_count_str);
426 }
427
428 // end of this line's object
429 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
430 }
431 }
432
433 // end of line data array
434 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
435
436 // end of this file's object
437 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
438 }
439
440 // end of main array
441 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
442
443 // write the JSON document into the file
444 fprintf(file, "%s\n", json.get_buffer());
445 fclose(file);
446}
447
448void TTCN3_Profiler::print_stats()
449{
450 if (profiler_db.empty()) {
451 return;
452 }
453
454 // title
455 char* title_str = mprintf(
456 "##################################################\n"
457 "%s## TTCN-3 %s%s%sstatistics ##%s\n"
458 "##################################################\n\n\n"
459 , disable_profiler ? "#######" : (disable_coverage ? "#########" : "")
460 , disable_profiler ? "" : "profiler "
461 , (disable_profiler || disable_coverage) ? "" : "and "
462 , disable_coverage ? "" : "code coverage "
463 , disable_profiler ? "######" : (disable_coverage ? "#########" : ""));
464
465 // line data
466 char* line_data_str = mprintf(
467 "-------------------------------------------------\n"
468 "%s- Code line data (%s%s%s) -%s\n"
469 "-------------------------------------------------\n"
470 , disable_profiler ? "-------" : (disable_coverage ? "---------" : "")
471 , disable_profiler ? "" : "total time"
472 , (disable_profiler || disable_coverage) ? "" : " / "
473 , disable_coverage ? "" : "execution count"
474 , disable_profiler ? "------" : (disable_coverage ? "---------" : ""));
475
476 // average time / exec count for lines
477 char* line_avg_str = NULL;
478 if (!disable_coverage && !disable_profiler) {
479 line_avg_str = mcopystr(
480 "-------------------------------------------------\n"
481 "- Average time / execution count for code lines -\n"
482 "-------------------------------------------------\n");
483 }
484
485 // function data
486 char* func_data_str = mprintf(
487 "------------------------------------------------\n"
488 "%s- Function data (%s%s%s) -%s\n"
489 "------------------------------------------------\n"
490 , disable_profiler ? "-------" : (disable_coverage ? "---------" : "")
491 , disable_profiler ? "" : "total time"
492 , (disable_profiler || disable_coverage) ? "" : " / "
493 , disable_coverage ? "" : "execution count"
494 , disable_profiler ? "------" : (disable_coverage ? "---------" : ""));
495
496 // average time / exec count for functions
497 char* func_avg_str = NULL;
498 if (!disable_coverage && !disable_profiler) {
499 func_avg_str = mcopystr(
500 "------------------------------------------------\n"
501 "- Average time / execution count for functions -\n"
502 "------------------------------------------------\n");
503 }
504
505 // cycle through the database and gather the necessary data
506 for (size_t i = 0; i < profiler_db.size(); ++i) {
507 if (i > 0) {
508 // add separators between files
509 line_data_str = mputstr(line_data_str, "-------------------------------------------------\n");
510 func_data_str = mputstr(func_data_str, "------------------------------------------------\n");
511 if (!disable_profiler && !disable_coverage) {
512 line_avg_str = mputstr(line_avg_str, "-------------------------------------------------\n");
513 func_avg_str = mputstr(func_avg_str, "------------------------------------------------\n");
514 }
515 }
516
517 // lines
518 for (size_t j = 0; j < profiler_db[i].lines.size(); ++j) {
519 if (0.0 != profiler_db[i].lines[j].total_time ||
520 0 != profiler_db[i].lines[j].exec_count) {
521 if (!disable_profiler) {
522 line_data_str = mputprintf(line_data_str, "%.6lfs", profiler_db[i].lines[j].total_time);
523 if (!disable_coverage) {
524 line_data_str = mputstrn(line_data_str, "\t/\t", 3);
525 line_avg_str = mputprintf(line_avg_str, "%.6lfs",
526 profiler_db[i].lines[j].total_time / profiler_db[i].lines[j].exec_count);
527 }
528 }
529 if (!disable_coverage) {
530 line_data_str = mputprintf(line_data_str, "%d", profiler_db[i].lines[j].exec_count);
531 }
532
533 // line specification (including function name for the function's start line)
534 char* line_spec_str = mprintf("\t%s:%lu", profiler_db[i].filename, j);
535 int func = get_function(i, j);
536 if (-1 != func) {
537 line_spec_str = mputprintf(line_spec_str, " [%s]", profiler_db[i].functions[func].name);
538 }
539 line_spec_str = mputstrn(line_spec_str, "\n", 1);
540
541 // add the line spec string to the other strings
542 line_data_str = mputstr(line_data_str, line_spec_str);
543 if (!disable_profiler && !disable_coverage) {
544 line_avg_str = mputstr(line_avg_str, line_spec_str);
545 }
546 }
547 }
548
549 // functions
550 for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) {
551 if (!disable_profiler) {
552 func_data_str = mputprintf(func_data_str, "%.6lfs", profiler_db[i].functions[j].total_time);
553 if (!disable_coverage) {
554 func_data_str = mputstrn(func_data_str, "\t/\t", 3);
555 func_avg_str = mputprintf(func_avg_str, "%.6lfs",
556 profiler_db[i].functions[j].total_time / profiler_db[i].functions[j].exec_count);
557 }
558 }
559 if (!disable_coverage) {
560 func_data_str = mputprintf(func_data_str, "%d", profiler_db[i].functions[j].exec_count);
561 }
562
563 // functions specification
564 char* func_spec_str = mprintf("\t%s:%d [%s]\n", profiler_db[i].filename,
565 profiler_db[i].functions[j].lineno, profiler_db[i].functions[j].name);
566
567 // add the line spec string to the other strings
568 func_data_str = mputstr(func_data_str, func_spec_str);
569 if (!disable_profiler && !disable_coverage) {
570 func_avg_str = mputstr(func_avg_str, func_spec_str);
571 }
572 }
573 }
574
575 // add new lines at the end of each segment
576 line_data_str = mputstrn(line_data_str, "\n", 1);
577 func_data_str = mputstrn(func_data_str, "\n", 1);
578 if (!disable_profiler && !disable_coverage) {
579 line_avg_str = mputstrn(line_avg_str, "\n", 1);
580 func_avg_str = mputstrn(func_avg_str, "\n", 1);
581 }
582
583 // write the statistics to the specified file
584 FILE* file = fopen(stats_filename, "w");
585 if (NULL == file) {
586 TTCN_warning("Could not open file '%s' for writing. Profiler and/or code coverage "
587 "statistics will not be saved.", stats_filename);
588 return;
589 }
590 fprintf(file, "%s%s%s%s%s"
591 , title_str, line_data_str
592 , (disable_profiler || disable_coverage) ? "" : line_avg_str
593 , func_data_str, (disable_profiler || disable_coverage) ? "" : func_avg_str);
594 fclose(file);
595}
596
597void TTCN3_Profiler::reset()
598{
599 prev_time = 0.0;
600 prev_file = NULL;
601 prev_line = -1;
602 prev_stack_len = 0;
603}
604
605double TTCN3_Profiler::get_time()
606{
607 timeval tv;
608 gettimeofday(&tv, NULL);
609 return tv.tv_sec + tv.tv_usec / 1000000.0;
610}
611
612void TTCN3_Profiler::enter_function(const char* filename, int lineno, const char* function_name)
613{
614 if (disable_profiler && disable_coverage) {
615 return;
616 }
617
618 // Note that the execution time of the last line in a function
619 // is measured by using the stack depth.
620 execute_line(filename, lineno);
621
622 int element = get_element(filename);
623
624 // store function data
625 int func = get_function(element, lineno);
626 if (-1 == func) {
627 create_function(element, lineno, function_name);
628 func = profiler_db[element].functions.size() - 1;
629 }
630
631 if (!disable_coverage) {
632 ++profiler_db[element].functions[func].exec_count;
633 }
634}
635
636void TTCN3_Profiler::execute_line(const char* filename, int lineno)
637{
638 if (disable_profiler && disable_coverage) {
639 return;
640 }
641
642 if (!disable_profiler) {
643 double currentTime = get_time();
644
645 // prev line should not be measured, because it is still running: we are in longer stack level
646 if (0.0 == prev_time || TTCN3_Stack_Depth::depth() > prev_stack_len) {
647 // add prev timer to call stack:
648 TTCN3_Stack_Depth::add_stack(prev_stack_len, prev_file, filename, prev_line, lineno);
649 }
650 else {
651 // if stack level is the same or higher: current line should be measured:
652 double elapsed = currentTime - prev_time;
653
654 // add the elapsed time to the time of the previous line:
655 add_line_time(elapsed, get_element(prev_file), prev_line);
656
657 TTCN3_Stack_Depth::update_stack_elapsed(elapsed);
658 }
659 }
660
661 // several instructions could be in the same line, only count the line once
662 if (!disable_coverage && (lineno != prev_line || NULL == prev_file ||
663 0 != strcmp(prev_file, filename))) {
664 int element = get_element(filename);
665
666 // make sure the line exists in the database
667 create_lines(element, lineno);
668
669 // increase line execution count
670 ++profiler_db[element].lines[lineno].exec_count;
671 }
672
673 // store the current location as previous for the next call
674 set_prev(disable_profiler ? -1 : TTCN3_Stack_Depth::depth(), filename, lineno);
675}
676
677int TTCN3_Profiler::get_element(const char* filename)
678{
679 for (size_t i = 0; i < profiler_db.size(); ++i) {
680 if (0 == strcmp(profiler_db[i].filename, filename)) {
681 return i;
682 }
683 }
684
685 profiler_db_item_t item;
686 item.filename = mcopystr(filename);
687 profiler_db.push_back(item);
688 return profiler_db.size() - 1;
689}
690
691int TTCN3_Profiler::get_function(int element, int lineno)
692{
693 for (size_t i = 0; i < profiler_db[element].functions.size(); ++i) {
694 if (profiler_db[element].functions[i].lineno == lineno) {
695 return i;
696 }
697 }
698 return -1;
699}
700
701void TTCN3_Profiler::create_function(int element, int lineno, const char* function_name)
702{
703 profiler_db_item_t::profiler_function_data_t func_data;
704 func_data.lineno = lineno;
705 func_data.total_time = 0.0;
706 func_data.exec_count = 0;
707 func_data.name = mcopystr(function_name);
708 profiler_db[element].functions.push_back(func_data);
709}
710
711void TTCN3_Profiler::create_lines(int element, int lineno)
712{
713 // set 0 for the unknown lines
714 size_t line_no = lineno;
715 if (profiler_db[element].lines.size() <= line_no) {
716 for (size_t i = profiler_db[element].lines.size(); i <= line_no; ++i) {
717 profiler_db_item_t::profiler_line_data_t line_data;
718 line_data.total_time = 0.0;
719 line_data.exec_count = 0;
720 profiler_db[element].lines.push_back(line_data);
721 }
722 }
723}
724
725void TTCN3_Profiler::add_line_time(double elapsed, int element, int lineno)
726{
727 if (-1 == lineno) {
728 return;
729 }
730
731 // ensure the line data exists
732 create_lines(element, lineno);
733
734 // increase the time of the line in the current file:
735 profiler_db[element].lines[lineno].total_time += elapsed;
736}
737
738void TTCN3_Profiler::add_function_time(double elapsed, int element, int lineno)
739{
740 int func = get_function(element, lineno);
741 if (-1 == func) {
742 return;
743 }
744 profiler_db[element].functions[func].total_time += elapsed;
745}
746
747void TTCN3_Profiler::update_last()
748{
749 if (0.0 == prev_time) {
750 return;
751 }
752
753 double currentTime = get_time();
754 double elapsed = currentTime - prev_time;
755
756 int element = get_element(prev_file);
757
758 // add the elapsed time to the time of the previous line:
759 add_line_time(elapsed, element, prev_line);
760 TTCN3_Stack_Depth::update_stack_elapsed(elapsed);
761
762 // reset measurement:
763 prev_time = 0.0;
764}
765
766void TTCN3_Profiler::set_prev(int stack_len, const char* filename, int lineno)
767{
768 prev_file = filename;
769 prev_line = lineno;
770 if (!disable_profiler) {
771 prev_time = get_time();
772 prev_stack_len = stack_len;
773 }
774}
775
776/////////////////////////////////////
777///////// TTCN3_Stack_Depth /////////
778/////////////////////////////////////
779
780int TTCN3_Stack_Depth::current_depth = -1;
781Vector<TTCN3_Stack_Depth::call_stack_timer_item_t> TTCN3_Stack_Depth::call_stack_timer_db;
782
783TTCN3_Stack_Depth::TTCN3_Stack_Depth()
784{
785 if (ttcn3_prof.is_profiler_disabled()) {
786 return;
787 }
788 ++current_depth;
789}
790
791TTCN3_Stack_Depth::~TTCN3_Stack_Depth()
792{
793 if (ttcn3_prof.is_profiler_disabled()) {
794 return;
795 }
796 ttcn3_prof.update_last();
797 remove_stack();
798 if (0 == current_depth) {
799 ttcn3_prof.reset();
800 }
801 --current_depth;
802}
803
804void TTCN3_Stack_Depth::add_stack(int stack_len, const char* caller_file, const char* func_file,
805 int caller_line, int start_line)
806{
807 call_stack_timer_item_t item;
808 item.stack_len = stack_len;
809 item.caller_file = caller_file;
810 item.func_file = func_file;
811 item.caller_line = caller_line;
812 item.start_line = start_line;
813 item.elapsed = 0.0;
814 call_stack_timer_db.push_back(item);
815}
816
817void TTCN3_Stack_Depth::remove_stack()
818{
819 // if stack level is the same or higher: measure the time:
820 double elapsed = call_stack_timer_db[current_depth].elapsed;
821
822 int element = ttcn3_prof.get_element(call_stack_timer_db[current_depth].func_file);
823
824 // add elapsed time to the total execution time of the previous line:
825 ttcn3_prof.add_function_time(elapsed, element, call_stack_timer_db[current_depth].start_line);
826
827 ttcn3_prof.set_prev(call_stack_timer_db[current_depth].stack_len,
828 call_stack_timer_db[current_depth].caller_file,
829 call_stack_timer_db[current_depth].caller_line);
830
831 call_stack_timer_db.erase_at(current_depth);
832}
833
834void TTCN3_Stack_Depth::update_stack_elapsed(double elapsed)
835{
836 for(int i = 0; i <= current_depth; i++) {
837 call_stack_timer_db[i].elapsed += elapsed;
838 }
839}
This page took 0.071507 seconds and 5 git commands to generate.