2 This file is part of Callgrind, a Valgrind tool for call graph
5 Copyright (C) 2002-2017, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
7 This tool is derived from and contains lot of code from Cachegrind
8 Copyright (C) 2002-2017 Nicholas Nethercote (njn@valgrind.org)
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 The GNU General Public License is contained in the file COPYING.
26 #include "config.h" // for VG_PREFIX
32 /*------------------------------------------------------------*/
33 /*--- Function specific configuration options ---*/
34 /*------------------------------------------------------------*/
36 /* Special value for separate_callers: automatic = adaptive */
37 #define CONFIG_AUTO -1
39 #define CONFIG_DEFAULT -1
40 #define CONFIG_FALSE 0
43 /* Logging configuration for a function */
50 Int skip
; /* Handle CALL to this function as JMP (= Skip)? */
51 Int group
; /* don't change caller dependency inside group !=0 */
54 Int separate_callers
; /* separate logging dependent on caller */
55 Int separate_recursions
; /* separate logging of rec. levels */
58 Int verbosity
; /* Change debug verbosity level while in function */
62 /* Configurations for function name prefix patterns.
63 * Currently, only very limit patterns are possible:
64 * Exact prefix patterns and "*::" are allowed.
66 * - "abc" matches all functions starting with "abc".
67 * - "abc*::def" matches all functions starting with "abc" and
68 * starting with "def" after the first "::" separator.
69 * - "*::print(" matches C++ methods "print" in all classes
70 * without namespace. I.e. "*" doesn't match a "::".
72 * We build a trie from patterns, and for a given function, we
73 * go down the tree and apply all non-default configurations.
77 #define NODE_DEGREE 30
79 /* node of compressed trie search structure */
80 typedef struct _config_node config_node
;
85 config_node
* sub_node
[NODE_DEGREE
];
87 config_node
* wild_star
;
88 config_node
* wild_char
;
94 static config_node
* fn_configs
= 0;
97 fn_config
* new_fnc(void)
99 fn_config
* fnc
= (fn_config
*) CLG_MALLOC("cl.clo.nf.1",
102 fnc
->dump_before
= CONFIG_DEFAULT
;
103 fnc
->dump_after
= CONFIG_DEFAULT
;
104 fnc
->zero_before
= CONFIG_DEFAULT
;
105 fnc
->toggle_collect
= CONFIG_DEFAULT
;
106 fnc
->skip
= CONFIG_DEFAULT
;
107 fnc
->pop_on_jump
= CONFIG_DEFAULT
;
108 fnc
->group
= CONFIG_DEFAULT
;
109 fnc
->separate_callers
= CONFIG_DEFAULT
;
110 fnc
->separate_recursions
= CONFIG_DEFAULT
;
113 fnc
->verbosity
= CONFIG_DEFAULT
;
120 static config_node
* new_config(const HChar
* name
, int length
)
123 config_node
* node
= (config_node
*) CLG_MALLOC("cl.clo.nc.1",
124 sizeof(config_node
) + length
);
126 for(i
=0;i
<length
;i
++) {
127 if (name
[i
] == 0) break;
128 node
->name
[i
] = name
[i
];
132 node
->length
= length
;
134 for(i
=0;i
<NODE_DEGREE
;i
++)
135 node
->sub_node
[i
] = 0;
140 CLG_DEBUG(3, " new_config('%s', len %d)\n", node
->name
, length
);
146 Bool
is_wild(HChar n
)
148 return (n
== '*') || (n
== '?');
151 /* Recursively build up function matching tree (prefix tree).
152 * Returns function config object for pattern <name>
153 * and starting at tree node <*pnode>.
155 * Tree nodes (config_node) are created as needed,
156 * tree root is stored into <*pnode>, and the created
157 * leaf (fn_config) for the given pattern is returned.
159 static fn_config
* get_fnc2(config_node
* node
, const HChar
* name
)
161 config_node
*new_sub
, *n
, *nprev
;
164 CLG_DEBUG(3, " get_fnc2(%p, '%s')\n", node
, name
);
167 if (!node
->config
) node
->config
= new_fnc();
171 if (is_wild(*name
)) {
173 while(name
[1] == '*') name
++;
174 new_sub
= node
->wild_star
;
177 new_sub
= node
->wild_char
;
180 new_sub
= new_config(name
, 1);
182 node
->wild_star
= new_sub
;
184 node
->wild_char
= new_sub
;
187 return get_fnc2( new_sub
, name
+1);
190 n
= node
->sub_node
[ name
[0]%NODE_DEGREE
];
194 for(len
=0; name
[len
] == n
->name
[len
]; len
++);
202 while(name
[len
] && (!is_wild(name
[len
]))) len
++;
203 new_sub
= new_config(name
, len
);
204 new_sub
->next
= node
->sub_node
[ name
[0]%NODE_DEGREE
];
205 node
->sub_node
[ name
[0]%NODE_DEGREE
] = new_sub
;
207 if (name
[len
] == 0) {
208 new_sub
->config
= new_fnc();
209 return new_sub
->config
;
212 /* recurse on wildcard */
213 return get_fnc2( new_sub
, name
+len
);
216 if (len
< n
->length
) {
218 /* split up the subnode <n> */
219 config_node
*new_node
;
222 new_node
= new_config(n
->name
, len
);
224 nprev
->next
= new_node
;
226 node
->sub_node
[ n
->name
[0]%NODE_DEGREE
] = new_node
;
227 new_node
->next
= n
->next
;
229 new_node
->sub_node
[ n
->name
[len
]%NODE_DEGREE
] = n
;
231 for(i
=0, offset
=len
; offset
< n
->length
; i
++, offset
++)
232 n
->name
[i
] = n
->name
[offset
];
238 while(name
[offset
] && (!is_wild(name
[offset
]))) offset
++;
239 new_sub
= new_config(name
, offset
);
240 /* this sub_node of new_node could already be set: chain! */
241 new_sub
->next
= new_node
->sub_node
[ name
[0]%NODE_DEGREE
];
242 new_node
->sub_node
[ name
[0]%NODE_DEGREE
] = new_sub
;
244 if (name
[offset
]==0) {
245 new_sub
->config
= new_fnc();
246 return new_sub
->config
;
249 /* recurse on wildcard */
250 return get_fnc2( new_sub
, name
+offset
);
256 /* name and node name are the same */
257 if (!n
->config
) n
->config
= new_fnc();
262 while(name
[offset
] && (!is_wild(name
[offset
]))) offset
++;
264 new_sub
= new_config(name
, offset
);
265 new_sub
->next
= n
->sub_node
[ name
[0]%NODE_DEGREE
];
266 n
->sub_node
[ name
[0]%NODE_DEGREE
] = new_sub
;
268 return get_fnc2(new_sub
, name
+offset
);
271 static void print_config_node(int depth
, int hash
, config_node
* node
)
276 if (node
!= fn_configs
) {
277 const HChar sp
[] = " ";
279 if (depth
>40) depth
=40;
280 VG_(printf
)("%s", sp
+40-depth
);
281 if (hash
>=0) VG_(printf
)(" [hash %2d]", hash
);
282 else if (hash
== -2) VG_(printf
)(" [wildc ?]");
283 else if (hash
== -3) VG_(printf
)(" [wildc *]");
284 VG_(printf
)(" '%s' (len %d)\n", node
->name
, node
->length
);
286 for(i
=0;i
<NODE_DEGREE
;i
++) {
287 n
= node
->sub_node
[i
];
289 print_config_node(depth
+1, i
, n
);
293 if (node
->wild_char
) print_config_node(depth
+1, -2, node
->wild_char
);
294 if (node
->wild_star
) print_config_node(depth
+1, -3, node
->wild_star
);
297 /* get a function config for a name pattern (from command line) */
298 static fn_config
* get_fnc(const HChar
* name
)
302 CLG_DEBUG(3, " +get_fnc(%s)\n", name
);
304 fn_configs
= new_config(name
, 0);
305 fnc
= get_fnc2(fn_configs
, name
);
308 CLG_DEBUG(3, " -get_fnc(%s):\n", name
);
309 print_config_node(3, -1, fn_configs
);
316 static void update_fn_config1(fn_node
* fn
, fn_config
* fnc
)
318 if (fnc
->dump_before
!= CONFIG_DEFAULT
)
319 fn
->dump_before
= (fnc
->dump_before
== CONFIG_TRUE
);
321 if (fnc
->dump_after
!= CONFIG_DEFAULT
)
322 fn
->dump_after
= (fnc
->dump_after
== CONFIG_TRUE
);
324 if (fnc
->zero_before
!= CONFIG_DEFAULT
)
325 fn
->zero_before
= (fnc
->zero_before
== CONFIG_TRUE
);
327 if (fnc
->toggle_collect
!= CONFIG_DEFAULT
)
328 fn
->toggle_collect
= (fnc
->toggle_collect
== CONFIG_TRUE
);
330 if (fnc
->skip
!= CONFIG_DEFAULT
)
331 fn
->skip
= (fnc
->skip
== CONFIG_TRUE
);
333 if (fnc
->pop_on_jump
!= CONFIG_DEFAULT
)
334 fn
->pop_on_jump
= (fnc
->pop_on_jump
== CONFIG_TRUE
);
336 if (fnc
->group
!= CONFIG_DEFAULT
)
337 fn
->group
= fnc
->group
;
339 if (fnc
->separate_callers
!= CONFIG_DEFAULT
)
340 fn
->separate_callers
= fnc
->separate_callers
;
342 if (fnc
->separate_recursions
!= CONFIG_DEFAULT
)
343 fn
->separate_recursions
= fnc
->separate_recursions
;
346 if (fnc
->verbosity
!= CONFIG_DEFAULT
)
347 fn
->verbosity
= fnc
->verbosity
;
351 /* Recursively go down the function matching tree,
352 * looking for a match to <name>. For every matching leaf,
353 * <fn> is updated with the pattern config.
355 static void update_fn_config2(fn_node
* fn
, const HChar
* name
,
360 CLG_DEBUG(3, " update_fn_config2('%s', node '%s'): \n",
362 if ((*name
== 0) && node
->config
) {
363 CLG_DEBUG(3, " found!\n");
364 update_fn_config1(fn
, node
->config
);
368 n
= node
->sub_node
[ name
[0]%NODE_DEGREE
];
370 if (VG_(strncmp
)(name
, n
->name
, n
->length
)==0) break;
374 CLG_DEBUG(3, " '%s' matching at hash %d\n",
375 n
->name
, name
[0]%NODE_DEGREE
);
376 update_fn_config2(fn
, name
+n
->length
, n
);
379 if (node
->wild_char
) {
380 CLG_DEBUG(3, " skip '%c' for wildcard '?'\n", *name
);
381 update_fn_config2(fn
, name
+1, node
->wild_char
);
384 if (node
->wild_star
) {
385 CLG_DEBUG(3, " wildcard '*'\n");
387 update_fn_config2(fn
, name
, node
->wild_star
);
390 update_fn_config2(fn
, name
, node
->wild_star
);
394 /* Update function config according to configs of name prefixes */
395 void CLG_(update_fn_config
)(fn_node
* fn
)
397 CLG_DEBUG(3, " update_fn_config('%s')\n", fn
->name
);
399 update_fn_config2(fn
, fn
->name
, fn_configs
);
403 /*--------------------------------------------------------------------*/
404 /*--- Command line processing ---*/
405 /*--------------------------------------------------------------------*/
407 Bool
CLG_(process_cmd_line_option
)(const HChar
* arg
)
409 const HChar
* tmp_str
;
411 if VG_BOOL_CLO(arg
, "--skip-plt", CLG_(clo
).skip_plt
) {}
413 else if VG_BOOL_CLO(arg
, "--collect-jumps", CLG_(clo
).collect_jumps
) {}
414 /* compatibility alias, deprecated option */
415 else if VG_BOOL_CLO(arg
, "--trace-jump", CLG_(clo
).collect_jumps
) {}
417 else if VG_BOOL_CLO(arg
, "--combine-dumps", CLG_(clo
).combine_dumps
) {}
419 else if VG_BOOL_CLO(arg
, "--collect-atstart", CLG_(clo
).collect_atstart
) {}
421 else if VG_BOOL_CLO(arg
, "--instr-atstart", CLG_(clo
).instrument_atstart
) {}
423 else if VG_BOOL_CLO(arg
, "--separate-threads", CLG_(clo
).separate_threads
) {}
425 else if VG_BOOL_CLO(arg
, "--compress-strings", CLG_(clo
).compress_strings
) {}
426 else if VG_BOOL_CLO(arg
, "--compress-mangled", CLG_(clo
).compress_mangled
) {}
427 else if VG_BOOL_CLO(arg
, "--compress-pos", CLG_(clo
).compress_pos
) {}
429 else if VG_STR_CLO(arg
, "--fn-skip", tmp_str
) {
430 fn_config
* fnc
= get_fnc(tmp_str
);
431 fnc
->skip
= CONFIG_TRUE
;
434 else if VG_STR_CLO(arg
, "--dump-before", tmp_str
) {
435 fn_config
* fnc
= get_fnc(tmp_str
);
436 fnc
->dump_before
= CONFIG_TRUE
;
439 else if VG_STR_CLO(arg
, "--zero-before", tmp_str
) {
440 fn_config
* fnc
= get_fnc(tmp_str
);
441 fnc
->zero_before
= CONFIG_TRUE
;
444 else if VG_STR_CLO(arg
, "--dump-after", tmp_str
) {
445 fn_config
* fnc
= get_fnc(tmp_str
);
446 fnc
->dump_after
= CONFIG_TRUE
;
449 else if VG_STR_CLO(arg
, "--toggle-collect", tmp_str
) {
450 fn_config
* fnc
= get_fnc(tmp_str
);
451 fnc
->toggle_collect
= CONFIG_TRUE
;
452 /* defaults to initial collection off */
453 CLG_(clo
).collect_atstart
= False
;
456 else if VG_INT_CLO(arg
, "--separate-recs", CLG_(clo
).separate_recursions
) {}
458 /* change handling of a jump between functions to ret+call */
459 else if VG_XACT_CLO(arg
, "--pop-on-jump", CLG_(clo
).pop_on_jump
, True
) {}
460 else if VG_STR_CLO( arg
, "--pop-on-jump", tmp_str
) {
461 fn_config
* fnc
= get_fnc(tmp_str
);
462 fnc
->pop_on_jump
= CONFIG_TRUE
;
466 else if VG_INT_CLO(arg
, "--ct-verbose", CLG_(clo
).verbose
) {}
467 else if VG_INT_CLO(arg
, "--ct-vstart", CLG_(clo
).verbose_start
) {}
469 else if VG_STREQN(12, arg
, "--ct-verbose") {
472 UInt n
= VG_(strtoll10
)(arg
+12, &s
);
473 if ((n
<= 0) || *s
!= '=') return False
;
479 else if VG_XACT_CLO(arg
, "--separate-callers=auto",
480 CLG_(clo
).separate_callers
, CONFIG_AUTO
) {}
481 else if VG_INT_CLO( arg
, "--separate-callers",
482 CLG_(clo
).separate_callers
) {}
484 else if VG_STREQN(10, arg
, "--fn-group") {
487 UInt n
= VG_(strtoll10
)(arg
+10, &s
);
488 if ((n
<= 0) || *s
!= '=') return False
;
493 else if VG_STREQN(18, arg
, "--separate-callers") {
496 UInt n
= VG_(strtoll10
)(arg
+18, &s
);
497 if ((n
<= 0) || *s
!= '=') return False
;
499 fnc
->separate_callers
= n
;
502 else if VG_STREQN(15, arg
, "--separate-recs") {
505 UInt n
= VG_(strtoll10
)(arg
+15, &s
);
506 if ((n
<= 0) || *s
!= '=') return False
;
508 fnc
->separate_recursions
= n
;
511 else if VG_STR_CLO(arg
, "--callgrind-out-file", CLG_(clo
).out_format
) {}
513 else if VG_BOOL_CLO(arg
, "--mangle-names", CLG_(clo
).mangle_names
) {}
515 else if VG_BOOL_CLO(arg
, "--skip-direct-rec",
516 CLG_(clo
).skip_direct_recursion
) {}
518 else if VG_BOOL_CLO(arg
, "--dump-bbs", CLG_(clo
).dump_bbs
) {}
519 else if VG_BOOL_CLO(arg
, "--dump-line", CLG_(clo
).dump_line
) {}
520 else if VG_BOOL_CLO(arg
, "--dump-instr", CLG_(clo
).dump_instr
) {}
521 else if VG_BOOL_CLO(arg
, "--dump-bb", CLG_(clo
).dump_bb
) {}
523 else if VG_INT_CLO( arg
, "--dump-every-bb", CLG_(clo
).dump_every_bb
) {}
525 else if VG_BOOL_CLO(arg
, "--collect-alloc", CLG_(clo
).collect_alloc
) {}
526 else if VG_XACT_CLO(arg
, "--collect-systime=no",
527 CLG_(clo
).collect_systime
, systime_no
) {}
528 else if VG_XACT_CLO(arg
, "--collect-systime=msec",
529 CLG_(clo
).collect_systime
, systime_msec
) {}
530 else if VG_XACT_CLO(arg
, "--collect-systime=yes", /* backward compatibility. */
531 CLG_(clo
).collect_systime
, systime_msec
) {}
532 else if VG_XACT_CLO(arg
, "--collect-systime=usec",
533 CLG_(clo
).collect_systime
, systime_usec
) {}
534 else if VG_XACT_CLO(arg
, "--collect-systime=nsec",
535 CLG_(clo
).collect_systime
, systime_nsec
) {
536 # if defined(VGO_darwin)
539 "--collect-systime=nsec not supported on darwin\n");
543 else if VG_BOOL_CLO(arg
, "--collect-bus", CLG_(clo
).collect_bus
) {}
544 /* for option compatibility with cachegrind */
545 else if VG_BOOL_CLO(arg
, "--cache-sim", CLG_(clo
).simulate_cache
) {}
546 /* compatibility alias, deprecated option */
547 else if VG_BOOL_CLO(arg
, "--simulate-cache", CLG_(clo
).simulate_cache
) {}
548 /* for option compatibility with cachegrind */
549 else if VG_BOOL_CLO(arg
, "--branch-sim", CLG_(clo
).simulate_branch
) {}
551 Bool isCachesimOption
= (*CLG_(cachesim
).parse_opt
)(arg
);
553 /* cache simulator is used if a simulator option is given */
554 if (isCachesimOption
)
555 CLG_(clo
).simulate_cache
= True
;
557 return isCachesimOption
;
563 void CLG_(print_usage
)(void)
566 "\n dump creation options:\n"
567 " --callgrind-out-file=<f> Output file name [callgrind.out.%%p]\n"
568 " --dump-line=no|yes Dump source lines of costs? [yes]\n"
569 " --dump-instr=no|yes Dump instruction address of costs? [no]\n"
570 " --compress-strings=no|yes Compress strings in profile dump? [yes]\n"
571 " --compress-pos=no|yes Compress positions in profile dump? [yes]\n"
572 " --combine-dumps=no|yes Concat all dumps into same file [no]\n"
574 " --compress-events=no|yes Compress events in profile dump? [no]\n"
575 " --dump-bb=no|yes Dump basic block address of costs? [no]\n"
576 " --dump-bbs=no|yes Dump basic block info? [no]\n"
577 " --dump-skipped=no|yes Dump info on skipped functions in calls? [no]\n"
578 " --mangle-names=no|yes Mangle separation into names? [yes]\n"
581 "\n activity options (for interactivity use callgrind_control):\n"
582 " --dump-every-bb=<count> Dump every <count> basic blocks [0=never]\n"
583 " --dump-before=<func> Dump when entering function\n"
584 " --zero-before=<func> Zero all costs when entering function\n"
585 " --dump-after=<func> Dump when leaving function\n"
587 " --dump-objs=no|yes Dump static object information [no]\n"
590 "\n data collection options:\n"
591 " --instr-atstart=no|yes Do instrumentation at callgrind start [yes]\n"
592 " --collect-atstart=no|yes Collect at process/thread start [yes]\n"
593 " --toggle-collect=<func> Toggle collection on enter/leave function\n"
594 " --collect-jumps=no|yes Collect jumps? [no]\n"
595 " --collect-bus=no|yes Collect global bus events? [no]\n"
597 " --collect-alloc=no|yes Collect memory allocation info? [no]\n"
599 " --collect-systime=no|yes|msec|usec|nsec Collect system call time info? [no]\n"
600 " no Do not collect system call time info.\n"
601 " msec|yes Collect syscount, syscall elapsed time (milli-seconds).\n"
602 " usec Collect syscount, syscall elapsed time (micro-seconds).\n"
603 " nsec Collect syscount, syscall elapsed and syscall cpu time (nano-seconds).\n"
605 "\n cost entity separation options:\n"
606 " --separate-threads=no|yes Separate data per thread [no]\n"
607 " --separate-callers=<n> Separate functions by call chain length [0]\n"
608 " --separate-callers<n>=<f> Separate <n> callers for function <f>\n"
609 " --separate-recs=<n> Separate function recursions up to level [2]\n"
610 " --separate-recs<n>=<f> Separate <n> recursions for function <f>\n"
611 " --skip-plt=no|yes Ignore calls to/from PLT sections? [yes]\n"
612 " --skip-direct-rec=no|yes Ignore direct recursions? [yes]\n"
613 " --fn-skip=<function> Ignore calls to/from function?\n"
615 " --fn-group<no>=<func> Put function into separation group <no>\n"
617 "\n simulation options:\n"
618 " --branch-sim=no|yes Do branch prediction simulation [no]\n"
619 " --cache-sim=no|yes Do cache simulation [no]\n"
622 (*CLG_(cachesim
).print_opts
)();
625 // " For full callgrind documentation, see\n"
626 // " "VG_PREFIX"/share/doc/callgrind/html/callgrind.html\n\n");
629 void CLG_(print_debug_usage
)(void)
634 " --ct-verbose=<level> Verbosity of standard debug output [0]\n"
635 " --ct-vstart=<BB number> Only be verbose after basic block [0]\n"
636 " --ct-verbose<level>=<func> Verbosity while in <func>\n"
645 void CLG_(set_clo_defaults
)(void)
647 /* Default values for command line arguments */
650 CLG_(clo
).out_format
= 0;
651 CLG_(clo
).combine_dumps
= False
;
652 CLG_(clo
).compress_strings
= True
;
653 CLG_(clo
).compress_mangled
= False
;
654 CLG_(clo
).compress_events
= False
;
655 CLG_(clo
).compress_pos
= True
;
656 CLG_(clo
).mangle_names
= True
;
657 CLG_(clo
).dump_line
= True
;
658 CLG_(clo
).dump_instr
= False
;
659 CLG_(clo
).dump_bb
= False
;
660 CLG_(clo
).dump_bbs
= False
;
662 CLG_(clo
).dump_every_bb
= 0;
665 CLG_(clo
).separate_threads
= False
;
666 CLG_(clo
).collect_atstart
= True
;
667 CLG_(clo
).collect_jumps
= False
;
668 CLG_(clo
).collect_alloc
= False
;
669 CLG_(clo
).collect_systime
= systime_no
;
670 CLG_(clo
).collect_bus
= False
;
672 CLG_(clo
).skip_plt
= True
;
673 CLG_(clo
).separate_callers
= 0;
674 CLG_(clo
).separate_recursions
= 2;
675 CLG_(clo
).skip_direct_recursion
= False
;
677 /* Instrumentation */
678 CLG_(clo
).instrument_atstart
= True
;
679 CLG_(clo
).simulate_cache
= False
;
680 CLG_(clo
).simulate_branch
= False
;
683 CLG_(clo
).pop_on_jump
= False
;
686 CLG_(clo
).verbose
= 0;
687 CLG_(clo
).verbose_start
= 0;