The hierarchy output mode is to group entries so the existing columns
won't fit to the new output.  Treat all sort keys as a single column and
separate headers by "/".

  #    Overhead  Command / Shared Object
  # ...........  ................................
  #
      15.11%     swapper
         14.97%     [kernel.vmlinux]
          0.09%     [libahci]
          0.05%     [iwlwifi]
  ...

Acked-by: Pekka Enberg <penb...@kernel.org>
Signed-off-by: Namhyung Kim <namhy...@kernel.org>
---
 tools/perf/ui/stdio/hist.c | 101 +++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/ctype.c    |   9 ++++
 tools/perf/util/util.h     |   2 +
 3 files changed, 112 insertions(+)

diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 0d5640e0df63..1b6646a0873b 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -506,6 +506,102 @@ static int hist_entry__fprintf(struct hist_entry *he, 
size_t size,
        return ret;
 }
 
+static int print_hierarchy_indent(const char *sep, int nr_sort,
+                                 const char *line, FILE *fp)
+{
+       if (sep != NULL || nr_sort < 1)
+               return 0;
+
+       return fprintf(fp, "%-.*s", (nr_sort - 1) * HIERARCHY_INDENT, line);
+}
+
+static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
+                                 const char *sep, FILE *fp)
+{
+       bool first = true;
+       int nr_sort;
+       unsigned width = 0;
+       unsigned header_width = 0;
+       struct perf_hpp_fmt *fmt;
+
+       nr_sort = hists->hpp_list->nr_sort_keys;
+
+       /* preserve max indent depth for column headers */
+       print_hierarchy_indent(sep, nr_sort, spaces, fp);
+
+       hists__for_each_format(hists, fmt) {
+               if (perf_hpp__is_sort_entry(fmt) || 
perf_hpp__is_dynamic_entry(fmt))
+                       break;
+
+               if (!first)
+                       fprintf(fp, "%s", sep ?: "  ");
+               else
+                       first = false;
+
+               fmt->header(fmt, hpp, hists_to_evsel(hists));
+               fprintf(fp, "%s", hpp->buf);
+       }
+
+       /* combine sort headers with ' / ' */
+       first = true;
+       hists__for_each_format(hists, fmt) {
+               if (!perf_hpp__is_sort_entry(fmt) && 
!perf_hpp__is_dynamic_entry(fmt))
+                       continue;
+
+               if (!first)
+                       header_width += fprintf(fp, " / ");
+               else {
+                       header_width += fprintf(fp, "%s", sep ?: "  ");
+                       first = false;
+               }
+
+               fmt->header(fmt, hpp, hists_to_evsel(hists));
+               rtrim(hpp->buf);
+
+               header_width += fprintf(fp, "%s", hpp->buf);
+       }
+
+       /* preserve max indent depth for combined sort headers */
+       print_hierarchy_indent(sep, nr_sort, spaces, fp);
+
+       fprintf(fp, "\n# ");
+
+       /* preserve max indent depth for initial dots */
+       print_hierarchy_indent(sep, nr_sort, dots, fp);
+
+       first = true;
+       hists__for_each_format(hists, fmt) {
+               if (perf_hpp__is_sort_entry(fmt) || 
perf_hpp__is_dynamic_entry(fmt))
+                       break;
+
+               if (!first)
+                       fprintf(fp, "%s", sep ?: "  ");
+               else
+                       first = false;
+
+               width = fmt->width(fmt, hpp, hists_to_evsel(hists));
+               fprintf(fp, "%.*s", width, dots);
+       }
+
+       hists__for_each_format(hists, fmt) {
+               if (!perf_hpp__is_sort_entry(fmt) && 
!perf_hpp__is_dynamic_entry(fmt))
+                       continue;
+
+               width = fmt->width(fmt, hpp, hists_to_evsel(hists));
+               if (width > header_width)
+                       header_width = width;
+       }
+
+       fprintf(fp, "%s%-.*s", sep ?: "  ", header_width, dots);
+
+       /* preserve max indent depth for dots under sort headers */
+       print_hierarchy_indent(sep, nr_sort, dots, fp);
+
+       fprintf(fp, "\n#\n");
+
+       return 2;
+}
+
 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                      int max_cols, float min_pcnt, FILE *fp)
 {
@@ -537,6 +633,11 @@ size_t hists__fprintf(struct hists *hists, bool 
show_header, int max_rows,
 
        fprintf(fp, "# ");
 
+       if (symbol_conf.report_hierarchy) {
+               nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp);
+               goto print_entries;
+       }
+
        hists__for_each_format(hists, fmt) {
                if (perf_hpp__should_skip(fmt, hists))
                        continue;
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index aada3ac5e891..d4a5a21c2a7e 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -32,8 +32,17 @@ unsigned char sane_ctype[256] = {
 
 const char *graph_line =
        "_____________________________________________________________________"
+       "_____________________________________________________________________"
        "_____________________________________________________________________";
 const char *graph_dotted_line =
        "---------------------------------------------------------------------"
        "---------------------------------------------------------------------"
        "---------------------------------------------------------------------";
+const char *spaces =
+       "                                                                     "
+       "                                                                     "
+       "                                                                     ";
+const char *dots =
+       "....................................................................."
+       "....................................................................."
+       ".....................................................................";
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index a8615816a00d..73fa72c768db 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -82,6 +82,8 @@
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
+extern const char *spaces;
+extern const char *dots;
 extern char buildid_dir[];
 
 /* On most systems <limits.h> would have given us this, but
-- 
2.7.1

Reply via email to