mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
perf c2c: Add stdio support for the function view
The function view is currently TUI-only, so it cannot be used by builds
without SLANG support, when output is piped, or from a script. Add a
--function option that prints the fully expanded three-level hierarchy to
stdout.
Keep the stdio renderer in builtin-c2c.c and reuse the common function-view
model introduced by the merged series. Export only the coalescing-field
capability check from the model, preserving the util/UI boundary and
leaving the TUI object in libperf-ui.a.
Stop padding the final identity column in symbol_view_entry(). The generic
formatter pads non-final columns but deliberately leaves the final column
unpadded, avoiding trailing whitespace in function-view table rows. The TUI
remains unchanged because its browser clears the rest of each rendered row.
--function implies --stdio and is rejected together with --stats. Validate
the iaddr requirement before processing events. Return function-view build
failures from the report command, and preserve TUI browser errors when
converting the display helpers to return a status.
Committer notes:
root@x2:~# uname -r
7.2.5-200.fc44.x86_64
root@x2:~# rpm -q kernel-debuginfo
kernel-debuginfo-7.2.5-200.fc44.x86_64
root@x2:~# perf c2c record perf bench futex hash -t 4 -r 1 -s > /dev/null 2>&1
root@x2:~# perf c2c report --stdio --function | grep "Functions Table" -A25
Shared Data Functions Table
=================================================
#
# Cycles Store
# % count Function / Contending function / Cacheline
# ......... ....... ..............................
#
- 47.89% 703 - [k] _raw_spin_lock
322 - [k] _raw_spin_lock
24 0xffff8b6dcbadf040
23 0xffff8b6dcbadf2c0
23 0xffff8b6dcbadf080
23 0xffff8b6dcbadf380
22 0xffff8b6dcbadf280
22 0xffff8b6dcbadf140
22 0xffff8b6dcbadf340
21 0xffff8b6dcbadf300
21 0xffff8b6dcbadf400
20 0xffff8b6dcbadf1c0
19 0xffff8b6dcbadf3c0
19 0xffff8b6dcbadf180
19 0xffff8b6dcbadf0c0
17 0xffff8b6dcbadf100
16 0xffff8b6dcbadf240
11 0xffff8b6dcbadf200
205 - [k] futex_q_unlock
root@x2:~#
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Wangyang Guo <wangyang.guo@intel.com>
Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
f4a58c7164
commit
89cfd46b7e
|
|
@ -107,6 +107,10 @@ REPORT OPTIONS
|
|||
--stats::
|
||||
Display only statistic tables and force stdio mode.
|
||||
|
||||
--function::
|
||||
Display the function view and force stdio mode. This requires `iaddr`
|
||||
in the cacheline coalescing fields and cannot be used with `--stats`.
|
||||
|
||||
--full-symbols::
|
||||
Display full length of symbols.
|
||||
|
||||
|
|
@ -360,6 +364,10 @@ Following tables are displayed:
|
|||
Shared Cache Line Distribution Pareto
|
||||
- list of all accessed offsets for each cacheline
|
||||
|
||||
With `--function`, the cacheline and Pareto tables are replaced by a fully
|
||||
expanded Shared Data Functions Table. Its three levels are the read-side
|
||||
function, contending writer, and shared cacheline, as detailed below.
|
||||
|
||||
TUI OUTPUT
|
||||
----------
|
||||
The TUI output provides interactive interface to navigate
|
||||
|
|
@ -374,8 +382,8 @@ Verbose mode also includes code addresses in function rows, and code addresses
|
|||
remain available in the per-cacheline detail view ('d').
|
||||
|
||||
The function view requires `iaddr` in the cacheline coalescing fields. If
|
||||
`--coalesce` omits it, TAB reports that the view is unavailable rather than
|
||||
attributing already-coalesced samples to an arbitrary function.
|
||||
`--coalesce` omits it, TAB or `--function` reports that the view is unavailable
|
||||
rather than attributing already-coalesced samples to an arbitrary function.
|
||||
|
||||
Level 1: the read-side function, sorted by Cycles % (estimated load
|
||||
cycles: HITM, peer-snoop and other-load cycles)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ struct perf_c2c {
|
|||
bool show_mem_region;
|
||||
bool use_stdio;
|
||||
bool stats_only;
|
||||
bool function_view;
|
||||
bool symbol_full;
|
||||
bool stitch_lbr;
|
||||
|
||||
|
|
@ -2624,7 +2625,48 @@ static void print_memory_ranges_info(FILE *out, struct perf_session *session)
|
|||
}
|
||||
}
|
||||
|
||||
static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
|
||||
static void c2c_function__unfold_all(struct rb_root_cached *root)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
|
||||
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
||||
|
||||
if (!he->has_children)
|
||||
continue;
|
||||
he->unfolded = true;
|
||||
c2c_function__unfold_all(&he->hroot_out);
|
||||
}
|
||||
}
|
||||
|
||||
static int perf_c2c__function_fprintf(FILE *out)
|
||||
{
|
||||
bool saved_use_callchain = symbol_conf.use_callchain;
|
||||
struct hists *hists;
|
||||
int ret;
|
||||
|
||||
/* Function-view entries aggregate samples and never display callchains. */
|
||||
symbol_conf.use_callchain = false;
|
||||
ret = c2c_function__build(&c2c.hists, c2c.cl_sort, c2c.symbol_full,
|
||||
&hists);
|
||||
if (ret) {
|
||||
if (ret == -EOPNOTSUPP)
|
||||
pr_err("The function view requires iaddr in --coalesce.\n");
|
||||
else
|
||||
pr_err("Failed to build function view hierarchy (ret=%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Match fold signs to hists__fprintf()'s forced child traversal. */
|
||||
c2c_function__unfold_all(&hists->entries);
|
||||
hists__fprintf(hists, true, 0, 0, 0, out, true);
|
||||
c2c_function__reset();
|
||||
out:
|
||||
symbol_conf.use_callchain = saved_use_callchain;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
|
||||
{
|
||||
setup_pager();
|
||||
|
||||
|
|
@ -2635,7 +2677,17 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
|
|||
print_c2c_info(out, session);
|
||||
|
||||
if (c2c.stats_only)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (c2c.function_view) {
|
||||
fprintf(out, "\n");
|
||||
fprintf(out, "=================================================\n");
|
||||
fprintf(out, " Shared Data Functions Table\n");
|
||||
fprintf(out, "=================================================\n");
|
||||
fprintf(out, "#\n");
|
||||
|
||||
return perf_c2c__function_fprintf(out);
|
||||
}
|
||||
|
||||
print_memory_ranges_info(out, session);
|
||||
|
||||
|
|
@ -2654,6 +2706,7 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
|
|||
fprintf(out, "#\n");
|
||||
|
||||
print_pareto(out, perf_session__env(session));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SLANG_SUPPORT
|
||||
|
|
@ -2890,18 +2943,18 @@ static int perf_c2c__hists_browse(struct hists *hists)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void perf_c2c_display(struct perf_session *session)
|
||||
static int perf_c2c_display(struct perf_session *session)
|
||||
{
|
||||
if (use_browser == 0)
|
||||
perf_c2c__hists_fprintf(stdout, session);
|
||||
else
|
||||
perf_c2c__hists_browse(&c2c.hists.hists);
|
||||
return perf_c2c__hists_fprintf(stdout, session);
|
||||
|
||||
return perf_c2c__hists_browse(&c2c.hists.hists);
|
||||
}
|
||||
#else
|
||||
static void perf_c2c_display(struct perf_session *session)
|
||||
static int perf_c2c_display(struct perf_session *session)
|
||||
{
|
||||
use_browser = 0;
|
||||
perf_c2c__hists_fprintf(stdout, session);
|
||||
return perf_c2c__hists_fprintf(stdout, session);
|
||||
}
|
||||
#endif /* HAVE_SLANG_SUPPORT */
|
||||
|
||||
|
|
@ -3180,6 +3233,8 @@ static int perf_c2c__report(int argc, const char **argv)
|
|||
OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
|
||||
OPT_BOOLEAN(0, "stats", &c2c.stats_only,
|
||||
"Display only statistic tables (implies --stdio)"),
|
||||
OPT_BOOLEAN(0, "function", &c2c.function_view,
|
||||
"Display the function view (implies --stdio)"),
|
||||
OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
|
||||
"Display full length of symbols"),
|
||||
OPT_BOOLEAN(0, "no-source", &no_source,
|
||||
|
|
@ -3219,6 +3274,11 @@ static int perf_c2c__report(int argc, const char **argv)
|
|||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (argc)
|
||||
usage_with_options(report_c2c_usage, options);
|
||||
if (c2c.stats_only && c2c.function_view) {
|
||||
pr_err("--stats and --function cannot be used together.\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef HAVE_SLANG_SUPPORT
|
||||
c2c.use_stdio = true;
|
||||
|
|
@ -3226,6 +3286,8 @@ static int perf_c2c__report(int argc, const char **argv)
|
|||
|
||||
if (c2c.stats_only)
|
||||
c2c.use_stdio = true;
|
||||
if (c2c.function_view)
|
||||
c2c.use_stdio = true;
|
||||
|
||||
/**
|
||||
* Annotation related options disassembler_style, objdump_path are set
|
||||
|
|
@ -3299,6 +3361,11 @@ static int perf_c2c__report(int argc, const char **argv)
|
|||
pr_debug("Failed to initialize hists\n");
|
||||
goto out_session;
|
||||
}
|
||||
if (c2c.function_view && !c2c_function__has_iaddr(c2c.cl_sort)) {
|
||||
pr_err("The function view requires iaddr in --coalesce.\n");
|
||||
err = -EINVAL;
|
||||
goto out_session;
|
||||
}
|
||||
|
||||
err = c2c_hists__init(&c2c.hists, "dcacheline", 2, perf_session__env(session));
|
||||
if (err) {
|
||||
|
|
@ -3452,7 +3519,7 @@ static int perf_c2c__report(int argc, const char **argv)
|
|||
goto out_str;
|
||||
}
|
||||
|
||||
perf_c2c_display(session);
|
||||
err = perf_c2c_display(session);
|
||||
|
||||
out_str:
|
||||
free(output_str);
|
||||
|
|
|
|||
|
|
@ -305,8 +305,8 @@ symbol_view_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
|||
char symbuf[32];
|
||||
|
||||
scnprintf(symbuf, sizeof(symbuf), "0x%" PRIx64, addr);
|
||||
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%-*.*s",
|
||||
text_width, text_width, symbuf);
|
||||
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%.*s",
|
||||
text_width, symbuf);
|
||||
} else {
|
||||
/* Level 1 and level 2 are both functions. */
|
||||
size_t cell_size;
|
||||
|
|
@ -331,9 +331,6 @@ symbol_view_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
|||
len = min_t(size_t, len, cell_size - 1);
|
||||
|
||||
ret += len;
|
||||
if (len < text_width)
|
||||
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%*s",
|
||||
text_width - len, "");
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -1519,7 +1516,7 @@ void c2c_function__reset(void)
|
|||
symbol_conf.use_callchain = saved_use_callchain;
|
||||
}
|
||||
|
||||
static bool c2c_function__has_iaddr(const char *cl_sort)
|
||||
bool c2c_function__has_iaddr(const char *cl_sort)
|
||||
{
|
||||
const char *field = cl_sort;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ bool c2c_fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
|
|||
int c2c_function__build(struct c2c_hists *cl_hists, const char *cl_sort,
|
||||
bool symbol_full, struct hists **hists);
|
||||
void c2c_function__reset(void);
|
||||
bool c2c_function__has_iaddr(const char *cl_sort);
|
||||
/* Valid only between a successful build and c2c_function__reset(). */
|
||||
struct hist_entry *c2c_function__find_cacheline(struct hist_entry *he);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user