29 #define CALLCHAIN_PARAM_DEFAULT \ 30 .mode = CHAIN_GRAPH_ABS, \ 32 .order = ORDER_CALLEE, \ 33 .key = CCKEY_FUNCTION, \ 34 .value = CCVAL_PERCENT, \ 62 if (!strncmp(value,
"graph", strlen(value))) {
66 if (!strncmp(value,
"flat", strlen(value))) {
70 if (!strncmp(value,
"fractal", strlen(value))) {
74 if (!strncmp(value,
"folded", strlen(value))) {
83 if (!strncmp(value,
"caller", strlen(value))) {
88 if (!strncmp(value,
"callee", strlen(value))) {
98 if (!strncmp(value,
"function", strlen(value))) {
102 if (!strncmp(value,
"address", strlen(value))) {
106 if (!strncmp(value,
"srcline", strlen(value))) {
110 if (!strncmp(value,
"branch", strlen(value))) {
119 if (!strncmp(value,
"percent", strlen(value))) {
123 if (!strncmp(value,
"period", strlen(value))) {
127 if (!strncmp(value,
"count", strlen(value))) {
138 unsigned long max_size = round_down(USHRT_MAX,
sizeof(u64));
140 size = strtoul(str, &endptr, 0);
146 size = round_up(size,
sizeof(u64));
147 if (!size || size > max_size)
155 pr_err(
"callchain: Incorrect stack dump size (max %ld): %s\n",
164 char *endptr, *saveptr = NULL;
165 bool minpcnt_set =
false;
166 bool record_opt_set =
false;
167 bool try_stack_size =
false;
169 callchain_param.
enabled =
true;
175 while ((tok = strtok_r((
char *)arg,
",", &saveptr)) != NULL) {
176 if (!strncmp(tok,
"none", strlen(tok))) {
178 callchain_param.
enabled =
false;
188 try_stack_size =
false;
190 }
else if (allow_record_opt && !record_opt_set) {
196 try_stack_size =
true;
198 record_opt_set =
true;
203 if (try_stack_size) {
204 unsigned long size = 0;
209 try_stack_size =
false;
210 }
else if (!minpcnt_set) {
212 callchain_param.
min_percent = strtod(tok, &endptr);
218 callchain_param.
print_limit = strtoul(tok, &endptr, 0);
227 pr_err(
"Can't register callchain params\n");
245 char *tok, *
name, *saveptr = NULL;
250 buf =
malloc(strlen(arg) + 1);
256 tok = strtok_r((
char *)buf,
",", &saveptr);
257 name = tok ? : (
char *)buf;
261 if (!strncmp(name,
"fp",
sizeof(
"fp"))) {
262 if (!strtok_r(NULL,
",", &saveptr)) {
266 pr_err(
"callchain: No more arguments " 267 "needed for --call-graph fp\n");
271 }
else if (!strncmp(name,
"dwarf",
sizeof(
"dwarf"))) {
272 const unsigned long default_stack_dump_size = 8192;
276 param->
dump_size = default_stack_dump_size;
279 tok = strtok_r(NULL,
",", &saveptr);
281 unsigned long size = 0;
286 }
else if (!strncmp(name,
"lbr",
sizeof(
"lbr"))) {
287 if (!strtok_r(NULL,
",", &saveptr)) {
291 pr_err(
"callchain: No more arguments " 292 "needed for --call-graph lbr\n");
295 pr_err(
"callchain: Unknown --call-graph option " 310 if (!strstarts(var,
"call-graph."))
312 var +=
sizeof(
"call-graph.") - 1;
314 if (!strcmp(var,
"record-mode"))
316 if (!strcmp(var,
"dump-size")) {
317 unsigned long size = 0;
325 if (!strcmp(var,
"print-type")){
329 pr_err(
"Invalid callchain mode: %s\n", value);
332 if (!strcmp(var,
"order")){
336 pr_err(
"Invalid callchain order: %s\n", value);
339 if (!strcmp(var,
"sort-key")){
343 pr_err(
"Invalid callchain sort key: %s\n", value);
346 if (!strcmp(var,
"threshold")) {
347 callchain_param.
min_percent = strtod(value, &endptr);
348 if (value == endptr) {
349 pr_err(
"Invalid callchain threshold: %s\n", value);
353 if (!strcmp(var,
"print-limit")) {
354 callchain_param.
print_limit = strtod(value, &endptr);
355 if (value == endptr) {
356 pr_err(
"Invalid callchain print limit: %s\n", value);
368 struct rb_node **p = &root->rb_node;
369 struct rb_node *parent = NULL;
383 if (rnode->
hit < chain->
hit)
390 if (rnode_cumul < chain_cumul)
401 rb_link_node(&chain->
rb_node, parent, p);
402 rb_insert_color(&chain->
rb_node, root);
420 if (node->
hit && node->
hit >= min_hit)
430 u64 min_hit,
struct callchain_param *param __maybe_unused)
458 u64 min_hit,
struct callchain_param *param __maybe_unused)
461 rb_root->rb_node = chain_root->
node.
rb_root.rb_node;
488 u64 min_hit __maybe_unused,
struct callchain_param *param)
491 rb_root->rb_node = chain_root->
node.
rb_root.rb_node;
496 switch (param->
mode) {
523 new =
zalloc(
sizeof(*
new));
525 perror(
"not enough memory to create child for code path tree");
529 INIT_LIST_HEAD(&
new->val);
530 INIT_LIST_HEAD(&
new->parent_val);
532 if (inherit_children) {
539 n = rb_first(&
new->rb_root_in);
547 rb_link_node(&
new->rb_node_in, NULL, &parent->
rb_root_in.rb_node);
565 pr_warning(
"Warning: empty node in callchain tree\n");
569 while (cursor_node) {
572 call =
zalloc(
sizeof(*call));
574 perror(
"not enough memory for the code path tree");
577 call->
ip = cursor_node->
ip;
582 if (cursor_node->
branch) {
614 list_add_tail(&call->
list, &node->
val);
636 list_for_each_entry_safe(call, tmp, &
new->val,
list) {
637 list_del(&call->
list);
645 new->children_hit = 0;
647 new->children_count = 0;
666 cmp = strcmp(left, right);
667 else if (!left && right)
669 else if (left && !right)
689 struct map *right_map, u64 right_ip)
691 struct dso *left_dso = left_map ? left_map->
dso : NULL;
692 struct dso *right_dso = right_map ? right_map->
dso : NULL;
694 if (left_dso != right_dso)
697 if (left_ip != right_ip)
708 switch (callchain_param.
key) {
784 u64 idx_parents, u64 idx_local, u64 period)
787 struct list_head *old_tail;
788 unsigned int idx_total = idx_parents + idx_local;
796 old_tail = parent->
val.prev;
797 list_del_range(&to_split->
list, old_tail);
798 new->val.next = &to_split->
list;
799 new->val.prev = old_tail;
800 to_split->
list.prev = &
new->val;
801 old_tail->next = &
new->val;
804 new->hit = parent->
hit;
807 new->val_nr = parent->
val_nr - idx_local;
808 parent->
val_nr = idx_local;
809 new->count = parent->
count;
814 if (idx_total < cursor->nr) {
818 struct rb_node *p, **pp;
844 rb_link_node(&
new->rb_node_in, p, pp);
847 parent->
hit = period;
865 struct rb_node **p = &root->
rb_root_in.rb_node;
866 struct rb_node *parent = NULL;
882 goto inc_children_hit;
887 p = &parent->rb_left;
889 p = &parent->rb_right;
922 list_for_each_entry(cnode, &root->
val,
list) {
940 WARN_ONCE(cmp ==
MATCH_ERROR,
"Chain comparison error\n");
947 if (matches < root->val_nr) {
956 if (matches == root->
val_nr && cursor->
pos == cursor->
nr) {
995 int old_pos = cursor->
nr;
998 list_for_each_entry_safe(list, next_list, &src->
val, list) {
1001 false, NULL, 0, 0, 0, list->
srcline);
1002 list_del(&list->
list);
1026 cursor->
nr = old_pos;
1027 cursor->
last = old_last;
1041 int nr_loop_iter, u64 iter_cycles, u64 branch_from,
1042 const char *srcline)
1047 node = calloc(1,
sizeof(*node));
1051 *cursor->
last = node;
1086 parent, al, max_stack);
1100 bool hide_unresolved)
1107 if (al->
sym == NULL) {
1108 if (hide_unresolved)
1110 if (al->
map == NULL)
1116 al->
cpumode = PERF_RECORD_MISC_KERNEL;
1119 al->
cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
1124 al->
cpumode = PERF_RECORD_MISC_USER;
1127 al->
cpumode = PERF_RECORD_MISC_GUEST_USER;
1130 al->
cpumode = PERF_RECORD_MISC_HYPERVISOR;
1140 char *bf,
size_t bfsize,
bool show_dso)
1147 const char *inlined = cl->
ms.
sym->
inlined ?
" (inlined)" :
"";
1149 if (show_srcline && cl->
srcline)
1150 printed = scnprintf(bf, bfsize,
"%s %s%s",
1154 printed = scnprintf(bf, bfsize,
"%s%s",
1157 printed = scnprintf(bf, bfsize,
"%#" PRIx64, cl->
ip);
1160 scnprintf(bf + printed, bfsize - printed,
" %s",
1169 char *bf,
size_t bfsize, u64 total)
1177 count = node->
count;
1180 switch (callchain_param.
value) {
1182 scnprintf(bf, bfsize,
"%"PRIu64, period);
1185 scnprintf(bf, bfsize,
"%u", count);
1190 percent = period * 100.0 / total;
1191 scnprintf(bf, bfsize,
"%.2f%%", percent);
1198 FILE *fp, u64 total)
1206 count = node->
count;
1209 switch (callchain_param.
value) {
1211 return fprintf(fp,
"%"PRIu64, period);
1213 return fprintf(fp,
"%u", count);
1217 percent = period * 100.0 / total;
1224 u64 *branch_count, u64 *predicted_count,
1225 u64 *abort_count, u64 *cycles_count)
1229 list_for_each_entry(clist, &node->
val,
list) {
1233 if (predicted_count)
1264 predicted_count, abort_count,
1272 u64 *branch_count, u64 *predicted_count,
1273 u64 *abort_count, u64 *cycles_count)
1278 if (predicted_count)
1279 *predicted_count = 0;
1298 printed = scnprintf(bf, bfsize,
"%s%s:%" PRId64
"", (idx) ?
" " :
" (", str, value);
1304 char *bf,
int bfsize,
float threshold)
1308 if (threshold != 0.0 && value < threshold)
1311 printed = scnprintf(bf, bfsize,
"%s%s:%.1f%%", (idx) ?
" " :
" (", str, value);
1317 u64 branch_count, u64 predicted_count,
1327 if (predicted_count < branch_count) {
1329 predicted_count * 100.0 / branch_count,
1330 bf + printed, bfsize - printed, 0.0);
1335 abort_count * 100.0 / branch_count,
1336 bf + printed, bfsize - printed, 0.1);
1340 printed += scnprintf(bf + printed, bfsize - printed,
")");
1347 u64 cycles_count, u64 iter_count,
1350 int printed = 0, i = 0;
1353 cycles = cycles_count / branch_count;
1357 bf + printed, bfsize - printed);
1363 bf + printed, bfsize - printed);
1366 iter_cycles / iter_count,
1367 bf + printed, bfsize - printed);
1371 printed += scnprintf(bf + printed, bfsize - printed,
")");
1377 u64 branch_count, u64 predicted_count,
1378 u64 abort_count, u64 cycles_count,
1379 u64 iter_count, u64 iter_cycles,
1384 if (branch_count == 0)
1385 return scnprintf(bf, bfsize,
" (calltrace)");
1389 predicted_count, abort_count, brtype_stat);
1392 cycles_count, iter_count, iter_cycles);
1402 u64 branch_count, u64 predicted_count,
1403 u64 abort_count, u64 cycles_count,
1404 u64 iter_count, u64 iter_cycles,
1410 predicted_count, abort_count, cycles_count,
1411 iter_count, iter_cycles, brtype_stat);
1414 return fprintf(fp,
"%s", str);
1416 return scnprintf(bf, bfsize,
"%s", str);
1420 FILE *fp,
char *bf,
int bfsize)
1422 u64 branch_count, predicted_count;
1423 u64 abort_count, cycles_count;
1424 u64 iter_count, iter_cycles;
1434 predicted_count, abort_count,
1435 cycles_count, iter_count, iter_cycles,
1445 list_for_each_entry_safe(list, tmp, &node->
parent_val, list) {
1446 list_del(&list->
list);
1451 list_for_each_entry_safe(list, tmp, &node->
val, list) {
1452 list_del(&list->
list);
1490 node->
hit = (node->
hit * 7) / 8;
1511 list_for_each_entry_reverse(chain, &parent->
val,
list) {
1512 new =
malloc(
sizeof(*
new));
1518 list_add_tail(&
new->list, &head);
1523 list_for_each_entry_safe_reverse(chain,
new, &head,
list)
1536 list_for_each_entry_safe(chain,
new, &head,
list) {
1537 list_del(&chain->
list);
static int merge_chain_branch(struct callchain_cursor *cursor, struct callchain_node *dst, struct callchain_node *src)
static struct callchain_node * create_child(struct callchain_node *parent, bool inherit_children)
int callchain_node__fprintf_value(struct callchain_node *node, FILE *fp, u64 total)
int branch_type_str(struct branch_type_stat *st, char *bf, int size)
void decay_callchain(struct callchain_root *root)
static enum match_result match_chain(struct callchain_cursor_node *node, struct callchain_list *cnode)
int callchain_cursor__copy(struct callchain_cursor *dst, struct callchain_cursor *src)
static LIST_HEAD(page_alloc_sort_input)
static bool machine__is_host(struct machine *machine)
#define CALLCHAIN_PARAM_DEFAULT
static void callchain_cursor_reset(struct callchain_cursor *cursor)
static int __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
static void __sort_chain_graph_abs(struct callchain_node *node, u64 min_hit)
int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, bool hide_unresolved)
static void sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root, u64 min_hit __maybe_unused, struct callchain_param *param)
struct ip_callchain * callchain
char * callchain_list__sym_name(struct callchain_list *cl, char *bf, size_t bfsize, bool show_dso)
static int count_pri64_printf(int idx, const char *str, u64 value, char *bf, int bfsize)
static enum match_result append_chain(struct callchain_node *root, struct callchain_cursor *cursor, u64 period)
enum perf_call_graph_mode record_mode
static void callchain_counts_value(struct callchain_node *node, u64 *branch_count, u64 *predicted_count, u64 *abort_count, u64 *cycles_count)
struct rb_root rb_root_in
struct callchain_cursor_node * next
struct branch_type_stat brtype_stat
static void callchain_cursor_commit(struct callchain_cursor *cursor)
static enum match_result match_chain_strings(const char *left, const char *right)
struct callchain_node node
static unsigned callchain_cumul_counts(struct callchain_node *node)
static enum match_result match_chain_dso_addresses(struct map *left_map, u64 left_ip, struct map *right_map, u64 right_ip)
struct callchain_root callchain[0]
static int counts_str_build(char *bf, int bfsize, u64 branch_count, u64 predicted_count, u64 abort_count, u64 cycles_count, u64 iter_count, u64 iter_cycles, struct branch_type_stat *brtype_stat)
int callchain_list_counts__printf_value(struct callchain_list *clist, FILE *fp, char *bf, int bfsize)
struct callchain_param callchain_param_default
int sample__resolve_callchain(struct perf_sample *sample, struct callchain_cursor *cursor, struct symbol **parent, struct perf_evsel *evsel, struct addr_location *al, int max_stack)
bool dwarf_callchain_users
struct map_groups * groups
static int count_float_printf(int idx, const char *str, float value, char *bf, int bfsize, float threshold)
int parse_callchain_report_opt(const char *arg)
int parse_callchain_record(const char *arg, struct callchain_param *param)
static void callchain_cursor_advance(struct callchain_cursor *cursor)
static u64 decay_callchain_node(struct callchain_node *node)
struct callchain_node * parent
static void sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root, u64 min_hit, struct callchain_param *param __maybe_unused)
void free_callchain(struct callchain_root *root)
static int branch_from_str(char *bf, int bfsize, u64 branch_count, u64 cycles_count, u64 iter_count, u64 iter_cycles)
static int str(yyscan_t scanner, int token)
int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
static void __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, u64 min_hit)
int callchain_merge(struct callchain_cursor *cursor, struct callchain_root *dst, struct callchain_root *src)
struct rb_node rb_node_in
int callchain_append(struct callchain_root *root, struct callchain_cursor *cursor, u64 period)
unsigned int children_count
int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, struct map *map, struct symbol *sym, bool branch, struct branch_flags *flags, int nr_loop_iter, u64 iter_cycles, u64 branch_from, const char *srcline)
x86 movsq based memcpy() in arch/x86/lib/memcpy_64.S") MEMCPY_FN(memcpy_erms
static int append_chain_children(struct callchain_node *root, struct callchain_cursor *cursor, u64 period)
static struct map * map__get(struct map *map)
void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, u64 from, u64 to)
static int parse_callchain_value(const char *value)
static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, u64 branch_count, u64 predicted_count, u64 abort_count, u64 cycles_count, u64 iter_count, u64 iter_cycles, struct branch_type_stat *brtype_stat)
static int get_stack_size(const char *str, unsigned long *_size)
static void free_callchain_node(struct callchain_node *node)
static void __sort_chain_graph_rel(struct callchain_node *node, double min_percent)
struct branch_flags branch_flags
static int split_add_child(struct callchain_node *parent, struct callchain_cursor *cursor, struct callchain_list *to_split, u64 idx_parents, u64 idx_local, u64 period)
static int parse_callchain_order(const char *value)
static int sym(yyscan_t scanner, int type, int config)
bool show_branchflag_count
static int parse_callchain_sort_key(const char *value)
int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
static double percent(int st, int tot)
static int fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
struct callchain_cursor_node ** last
static int callchain_node_branch_counts_cumul(struct callchain_node *node, u64 *branch_count, u64 *predicted_count, u64 *abort_count, u64 *cycles_count)
int thread__resolve_callchain(struct thread *thread, struct callchain_cursor *cursor, struct perf_evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, int max_stack)
int perf_callchain_config(const char *var, const char *value)
int callchain_node__make_parent_list(struct callchain_node *node)
int callchain_branch_counts(struct callchain_root *root, u64 *branch_count, u64 *predicted_count, u64 *abort_count, u64 *cycles_count)
#define pr_warning(fmt,...)
static int branch_to_str(char *bf, int bfsize, u64 branch_count, u64 predicted_count, u64 abort_count, struct branch_type_stat *brtype_stat)
int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
static u64 callchain_cumul_hits(struct callchain_node *node)
static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, enum chain_mode mode)
static void sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root, u64 min_hit, struct callchain_param *param __maybe_unused)
int callchain_register_param(struct callchain_param *param)
struct list_head parent_val
static int parse_callchain_mode(const char *value)
static struct callchain_node * add_child(struct callchain_node *parent, struct callchain_cursor *cursor, u64 period)
int parse_callchain_top_opt(const char *arg)
static struct callchain_cursor_node * callchain_cursor_current(struct callchain_cursor *cursor)
char * callchain_node__scnprintf_value(struct callchain_node *node, char *bf, size_t bfsize, u64 total)
void static void * zalloc(size_t size)