perf ui/stdio: Align column header for hierarchy output
authorNamhyung Kim <namhyung@kernel.org>
Wed, 24 Feb 2016 15:13:42 +0000 (00:13 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 24 Feb 2016 23:21:12 +0000 (20:21 -0300)
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]
  ...

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Pekka Enberg <penberg@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1456326830-30456-11-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/ui/stdio/hist.c
tools/perf/util/ctype.c
tools/perf/util/util.h

index 90b86776f964c67059029ae4ff37985b948ea7f5..435eaaaf2f1d97d57baa08c93ab0596a0c2b3c7a 100644 (file)
@@ -511,6 +511,106 @@ 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 (perf_hpp__should_skip(fmt, hists))
+                       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;
+               if (perf_hpp__should_skip(fmt, hists))
+                       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)
 {
@@ -542,6 +642,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;
index aada3ac5e891f85be1f4d25791d4ee17dd859077..d4a5a21c2a7e2e47596444665b5f5828874da337 100644 (file)
@@ -31,9 +31,18 @@ unsigned char sane_ctype[256] = {
 };
 
 const char *graph_line =
+       "_____________________________________________________________________"
        "_____________________________________________________________________"
        "_____________________________________________________________________";
 const char *graph_dotted_line =
        "---------------------------------------------------------------------"
        "---------------------------------------------------------------------"
        "---------------------------------------------------------------------";
+const char *spaces =
+       "                                                                     "
+       "                                                                     "
+       "                                                                     ";
+const char *dots =
+       "....................................................................."
+       "....................................................................."
+       ".....................................................................";
index 7015019ee5fbbf8aa60e008c4af8952efd266adc..d0d50cef8b2af31703c7d298f68d93b68326c3c5 100644 (file)
@@ -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