mirror of
https://github.com/torvalds/linux.git
synced 2026-01-12 00:42:35 +08:00
perf hist: Support multi-line header
This is a preparation to support multi-line headers in 'perf mem report'. Normal sort keys and output fields that don't have contents for multi- line will print the header string at the last line only. As we don't use multi-line headers normally, it should not have any changes in the output. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Link: https://lore.kernel.org/r/20250430205548.789750-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
43a6446998
commit
29e6392ec3
@@ -1686,7 +1686,8 @@ hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
|
||||
static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser,
|
||||
char *buf, size_t size, int line)
|
||||
{
|
||||
struct hists *hists = browser->hists;
|
||||
struct perf_hpp dummy_hpp = {
|
||||
@@ -1712,7 +1713,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
|
||||
if (column++ < browser->b.horiz_scroll)
|
||||
continue;
|
||||
|
||||
ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
|
||||
ret = fmt->header(fmt, &dummy_hpp, hists, line, NULL);
|
||||
if (advance_hpp_check(&dummy_hpp, ret))
|
||||
break;
|
||||
|
||||
@@ -1723,6 +1724,9 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
|
||||
first_node = false;
|
||||
}
|
||||
|
||||
if (line < hists->hpp_list->nr_header_lines - 1)
|
||||
return ret;
|
||||
|
||||
if (!first_node) {
|
||||
ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
|
||||
indent * HIERARCHY_INDENT, "");
|
||||
@@ -1753,7 +1757,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
|
||||
}
|
||||
first_col = false;
|
||||
|
||||
ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
|
||||
ret = fmt->header(fmt, &dummy_hpp, hists, line, NULL);
|
||||
dummy_hpp.buf[ret] = '\0';
|
||||
|
||||
start = strim(dummy_hpp.buf);
|
||||
@@ -1772,14 +1776,18 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
|
||||
|
||||
static void hists_browser__hierarchy_headers(struct hist_browser *browser)
|
||||
{
|
||||
struct perf_hpp_list *hpp_list = browser->hists->hpp_list;
|
||||
char headers[1024];
|
||||
int line;
|
||||
|
||||
hists_browser__scnprintf_hierarchy_headers(browser, headers,
|
||||
sizeof(headers));
|
||||
for (line = 0; line < hpp_list->nr_header_lines; line++) {
|
||||
hists_browser__scnprintf_hierarchy_headers(browser, headers,
|
||||
sizeof(headers), line);
|
||||
|
||||
ui_browser__gotorc_title(&browser->b, 0, 0);
|
||||
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
|
||||
ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
|
||||
ui_browser__gotorc_title(&browser->b, line, 0);
|
||||
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
|
||||
ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void hists_browser__headers(struct hist_browser *browser)
|
||||
|
||||
@@ -321,11 +321,16 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt,
|
||||
}
|
||||
|
||||
static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
||||
struct hists *hists, int line __maybe_unused,
|
||||
struct hists *hists, int line,
|
||||
int *span __maybe_unused)
|
||||
{
|
||||
int len = hpp__width_fn(fmt, hpp, hists);
|
||||
return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
|
||||
const char *hdr = "";
|
||||
|
||||
if (line == hists->hpp_list->nr_header_lines - 1)
|
||||
hdr = fmt->name;
|
||||
|
||||
return scnprintf(hpp->buf, hpp->size, "%*s", len, hdr);
|
||||
}
|
||||
|
||||
int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
|
||||
|
||||
@@ -643,45 +643,58 @@ static int hists__fprintf_hierarchy_headers(struct hists *hists,
|
||||
unsigned header_width = 0;
|
||||
struct perf_hpp_fmt *fmt;
|
||||
struct perf_hpp_list_node *fmt_node;
|
||||
struct perf_hpp_list *hpp_list = hists->hpp_list;
|
||||
const char *sep = symbol_conf.field_sep;
|
||||
|
||||
indent = hists->nr_hpp_node;
|
||||
|
||||
/* preserve max indent depth for column headers */
|
||||
print_hierarchy_indent(sep, indent, " ", fp);
|
||||
|
||||
/* the first hpp_list_node is for overhead columns */
|
||||
fmt_node = list_first_entry(&hists->hpp_formats,
|
||||
struct perf_hpp_list_node, list);
|
||||
|
||||
perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
|
||||
fmt->header(fmt, hpp, hists, 0, NULL);
|
||||
fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
|
||||
}
|
||||
for (int line = 0; line < hpp_list->nr_header_lines; line++) {
|
||||
/* first # is displayed one level up */
|
||||
if (line)
|
||||
fprintf(fp, "# ");
|
||||
|
||||
/* combine sort headers with ' / ' */
|
||||
first_node = true;
|
||||
list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
|
||||
if (!first_node)
|
||||
header_width += fprintf(fp, " / ");
|
||||
first_node = false;
|
||||
/* preserve max indent depth for column headers */
|
||||
print_hierarchy_indent(sep, indent, " ", fp);
|
||||
|
||||
first_col = true;
|
||||
perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
|
||||
if (perf_hpp__should_skip(fmt, hists))
|
||||
continue;
|
||||
|
||||
if (!first_col)
|
||||
header_width += fprintf(fp, "+");
|
||||
first_col = false;
|
||||
|
||||
fmt->header(fmt, hpp, hists, 0, NULL);
|
||||
|
||||
header_width += fprintf(fp, "%s", strim(hpp->buf));
|
||||
fmt->header(fmt, hpp, hists, line, NULL);
|
||||
fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
|
||||
}
|
||||
|
||||
if (line < hpp_list->nr_header_lines - 1)
|
||||
goto next_line;
|
||||
|
||||
/* combine sort headers with ' / ' */
|
||||
first_node = true;
|
||||
list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
|
||||
if (!first_node)
|
||||
header_width += fprintf(fp, " / ");
|
||||
first_node = false;
|
||||
|
||||
first_col = true;
|
||||
perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
|
||||
if (perf_hpp__should_skip(fmt, hists))
|
||||
continue;
|
||||
|
||||
if (!first_col)
|
||||
header_width += fprintf(fp, "+");
|
||||
first_col = false;
|
||||
|
||||
fmt->header(fmt, hpp, hists, line, NULL);
|
||||
|
||||
header_width += fprintf(fp, "%s", strim(hpp->buf));
|
||||
}
|
||||
}
|
||||
|
||||
next_line:
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "\n# ");
|
||||
fprintf(fp, "# ");
|
||||
|
||||
/* preserve max indent depth for initial dots */
|
||||
print_hierarchy_indent(sep, indent, dots, fp);
|
||||
|
||||
@@ -2641,18 +2641,22 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
|
||||
}
|
||||
|
||||
static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
||||
struct hists *hists, int line __maybe_unused,
|
||||
struct hists *hists, int line,
|
||||
int *span __maybe_unused)
|
||||
{
|
||||
struct hpp_sort_entry *hse;
|
||||
size_t len = fmt->user_len;
|
||||
const char *hdr = "";
|
||||
|
||||
if (line == hists->hpp_list->nr_header_lines - 1)
|
||||
hdr = fmt->name;
|
||||
|
||||
hse = container_of(fmt, struct hpp_sort_entry, hpp);
|
||||
|
||||
if (!len)
|
||||
len = hists__col_len(hists, hse->se->se_width_idx);
|
||||
|
||||
return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
|
||||
return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, hdr);
|
||||
}
|
||||
|
||||
static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
|
||||
|
||||
Reference in New Issue
Block a user