diff options
Diffstat (limited to 'tools/perf/util/callchain.c')
-rw-r--r-- | tools/perf/util/callchain.c | 163 |
1 files changed, 121 insertions, 42 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index aba953421a03..3cea1fb5404b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -80,6 +80,10 @@ static int parse_callchain_sort_key(const char *value) callchain_param.key = CCKEY_ADDRESS; return 0; } + if (!strncmp(value, "srcline", strlen(value))) { + callchain_param.key = CCKEY_SRCLINE; + return 0; + } if (!strncmp(value, "branch", strlen(value))) { callchain_param.branch_callstack = 1; return 0; @@ -510,14 +514,51 @@ enum match_result { MATCH_GT, }; +static enum match_result match_chain_srcline(struct callchain_cursor_node *node, + struct callchain_list *cnode) +{ + char *left = get_srcline(cnode->ms.map->dso, + map__rip_2objdump(cnode->ms.map, cnode->ip), + cnode->ms.sym, true, false); + char *right = get_srcline(node->map->dso, + map__rip_2objdump(node->map, node->ip), + node->sym, true, false); + enum match_result ret = MATCH_EQ; + int cmp; + + if (left && right) + cmp = strcmp(left, right); + else if (!left && right) + cmp = 1; + else if (left && !right) + cmp = -1; + else if (cnode->ip == node->ip) + cmp = 0; + else + cmp = (cnode->ip < node->ip) ? -1 : 1; + + if (cmp != 0) + ret = cmp < 0 ? MATCH_LT : MATCH_GT; + + free_srcline(left); + free_srcline(right); + return ret; +} + static enum match_result match_chain(struct callchain_cursor_node *node, struct callchain_list *cnode) { struct symbol *sym = node->sym; u64 left, right; - if (cnode->ms.sym && sym && - callchain_param.key == CCKEY_FUNCTION) { + if (callchain_param.key == CCKEY_SRCLINE) { + enum match_result match = match_chain_srcline(node, cnode); + + if (match != MATCH_ERROR) + return match; + } + + if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) { left = cnode->ms.sym->start; right = sym->start; } else { @@ -911,15 +952,16 @@ out: char *callchain_list__sym_name(struct callchain_list *cl, char *bf, size_t bfsize, bool show_dso) { + bool show_addr = callchain_param.key == CCKEY_ADDRESS; + bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE; int printed; if (cl->ms.sym) { - if (callchain_param.key == CCKEY_ADDRESS && - cl->ms.map && !cl->srcline) + if (show_srcline && cl->ms.map && !cl->srcline) cl->srcline = get_srcline(cl->ms.map->dso, map__rip_2objdump(cl->ms.map, cl->ip), - cl->ms.sym, false); + cl->ms.sym, false, show_addr); if (cl->srcline) printed = scnprintf(bf, bfsize, "%s %s", cl->ms.sym->name, cl->srcline); @@ -1063,63 +1105,100 @@ int callchain_branch_counts(struct callchain_root *root, cycles_count); } -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 samples_count) +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 samples_count) { double predicted_percent = 0.0; const char *null_str = ""; char iter_str[32]; - char *str; - u64 cycles = 0; - - if (branch_count == 0) { - if (fp) - return fprintf(fp, " (calltrace)"); + char cycle_str[32]; + char *istr, *cstr; + u64 cycles; + if (branch_count == 0) return scnprintf(bf, bfsize, " (calltrace)"); - } + + cycles = cycles_count / branch_count; if (iter_count && samples_count) { - scnprintf(iter_str, sizeof(iter_str), - ", iterations:%" PRId64 "", - iter_count / samples_count); - str = iter_str; + if (cycles > 0) + scnprintf(iter_str, sizeof(iter_str), + " iterations:%" PRId64 "", + iter_count / samples_count); + else + scnprintf(iter_str, sizeof(iter_str), + "iterations:%" PRId64 "", + iter_count / samples_count); + istr = iter_str; } else - str = (char *)null_str; + istr = (char *)null_str; + + if (cycles > 0) { + scnprintf(cycle_str, sizeof(cycle_str), + "cycles:%" PRId64 "", cycles); + cstr = cycle_str; + } else + cstr = (char *)null_str; predicted_percent = predicted_count * 100.0 / branch_count; - cycles = cycles_count / branch_count; - if ((predicted_percent >= 100.0) && (abort_count == 0)) { - if (fp) - return fprintf(fp, " (cycles:%" PRId64 "%s)", - cycles, str); + if ((predicted_count == branch_count) && (abort_count == 0)) { + if ((cycles > 0) || (istr != (char *)null_str)) + return scnprintf(bf, bfsize, " (%s%s)", cstr, istr); + else + return scnprintf(bf, bfsize, "%s", (char *)null_str); + } - return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)", - cycles, str); + if ((predicted_count < branch_count) && (abort_count == 0)) { + if ((cycles > 0) || (istr != (char *)null_str)) + return scnprintf(bf, bfsize, + " (predicted:%.1f%% %s%s)", + predicted_percent, cstr, istr); + else { + return scnprintf(bf, bfsize, + " (predicted:%.1f%%)", + predicted_percent); + } } - if ((predicted_percent < 100.0) && (abort_count == 0)) { - if (fp) - return fprintf(fp, - " (predicted:%.1f%%, cycles:%" PRId64 "%s)", - predicted_percent, cycles, str); + if ((predicted_count == branch_count) && (abort_count > 0)) { + if ((cycles > 0) || (istr != (char *)null_str)) + return scnprintf(bf, bfsize, + " (abort:%" PRId64 " %s%s)", + abort_count, cstr, istr); + else + return scnprintf(bf, bfsize, + " (abort:%" PRId64 ")", + abort_count); + } + if ((cycles > 0) || (istr != (char *)null_str)) return scnprintf(bf, bfsize, - " (predicted:%.1f%%, cycles:%" PRId64 "%s)", - predicted_percent, cycles, str); - } + " (predicted:%.1f%% abort:%" PRId64 " %s%s)", + predicted_percent, abort_count, cstr, istr); + + return scnprintf(bf, bfsize, + " (predicted:%.1f%% abort:%" PRId64 ")", + predicted_percent, abort_count); +} + +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 samples_count) +{ + char str[128]; + + counts_str_build(str, sizeof(str), branch_count, + predicted_count, abort_count, cycles_count, + iter_count, samples_count); if (fp) - return fprintf(fp, - " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", - predicted_percent, abort_count, cycles, str); + return fprintf(fp, "%s", str); - return scnprintf(bf, bfsize, - " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", - predicted_percent, abort_count, cycles, str); + return scnprintf(bf, bfsize, "%s", str); } int callchain_list_counts__printf_value(struct callchain_node *node, |