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 | 107 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index b58f718a6afc..4bdab3cf1b6c 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -505,6 +505,108 @@ 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;
+       const char spaces[] = "                                               "
+       "                                                                     "
+       "                                                                     ";
+       const char dots[] = "................................................."
+       "....................................................................."
+       ".....................................................................";
+
+       nr_sort = perf_hpp__count_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)
 {
@@ -536,6 +638,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;
-- 
2.7.0

Reply via email to