diff options
author | Namhyung Kim <namhyung@kernel.org> | 2016-03-07 14:44:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-03-08 04:11:19 -0500 |
commit | 1b2dbbf41a0f4cf7a5662bccb9a18128d16e5ffb (patch) | |
tree | 284079169d6939125553b2946ebd2318019029d8 | |
parent | c3bc0c436899d01c3a09fddb308d487cc032fbd2 (diff) |
perf hists: Use own hpp_list for hierarchy mode
Now each hists has its own hpp lists in hierarchy. So instead of having
a pointer to a single perf_hpp_fmt in a hist entry, make it point the
hpp_list for its level. This will be used to support multiple sort keys
in a single hierarchy level.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1457361308-514-3-git-send-email-namhyung@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 45 | ||||
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 20 | ||||
-rw-r--r-- | tools/perf/ui/hist.c | 5 | ||||
-rw-r--r-- | tools/perf/ui/stdio/hist.c | 44 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 60 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 1 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 |
7 files changed, 103 insertions, 73 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 5ffffcb1e3c5..928b4825b752 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1388,25 +1388,26 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, | |||
1388 | HE_COLORSET_NORMAL); | 1388 | HE_COLORSET_NORMAL); |
1389 | } | 1389 | } |
1390 | 1390 | ||
1391 | ui_browser__write_nstring(&browser->b, "", 2); | 1391 | perf_hpp_list__for_each_format(entry->hpp_list, fmt) { |
1392 | width -= 2; | 1392 | ui_browser__write_nstring(&browser->b, "", 2); |
1393 | width -= 2; | ||
1393 | 1394 | ||
1394 | /* | 1395 | /* |
1395 | * No need to call hist_entry__snprintf_alignment() | 1396 | * No need to call hist_entry__snprintf_alignment() |
1396 | * since this fmt is always the last column in the | 1397 | * since this fmt is always the last column in the |
1397 | * hierarchy mode. | 1398 | * hierarchy mode. |
1398 | */ | 1399 | */ |
1399 | fmt = entry->fmt; | 1400 | if (fmt->color) { |
1400 | if (fmt->color) { | 1401 | width -= fmt->color(fmt, &hpp, entry); |
1401 | width -= fmt->color(fmt, &hpp, entry); | 1402 | } else { |
1402 | } else { | 1403 | int i = 0; |
1403 | int i = 0; | ||
1404 | 1404 | ||
1405 | width -= fmt->entry(fmt, &hpp, entry); | 1405 | width -= fmt->entry(fmt, &hpp, entry); |
1406 | ui_browser__printf(&browser->b, "%s", ltrim(s)); | 1406 | ui_browser__printf(&browser->b, "%s", ltrim(s)); |
1407 | 1407 | ||
1408 | while (isspace(s[i++])) | 1408 | while (isspace(s[i++])) |
1409 | width++; | 1409 | width++; |
1410 | } | ||
1410 | } | 1411 | } |
1411 | } | 1412 | } |
1412 | 1413 | ||
@@ -1934,7 +1935,7 @@ static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, | |||
1934 | struct perf_hpp_fmt *fmt; | 1935 | struct perf_hpp_fmt *fmt; |
1935 | bool first = true; | 1936 | bool first = true; |
1936 | int ret; | 1937 | int ret; |
1937 | int hierarchy_indent = (nr_sort_keys + 1) * HIERARCHY_INDENT; | 1938 | int hierarchy_indent = nr_sort_keys * HIERARCHY_INDENT; |
1938 | 1939 | ||
1939 | printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); | 1940 | printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); |
1940 | 1941 | ||
@@ -1962,9 +1963,13 @@ static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, | |||
1962 | ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); | 1963 | ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); |
1963 | advance_hpp(&hpp, ret); | 1964 | advance_hpp(&hpp, ret); |
1964 | 1965 | ||
1965 | fmt = he->fmt; | 1966 | perf_hpp_list__for_each_format(he->hpp_list, fmt) { |
1966 | ret = fmt->entry(fmt, &hpp, he); | 1967 | ret = scnprintf(hpp.buf, hpp.size, " "); |
1967 | advance_hpp(&hpp, ret); | 1968 | advance_hpp(&hpp, ret); |
1969 | |||
1970 | ret = fmt->entry(fmt, &hpp, he); | ||
1971 | advance_hpp(&hpp, ret); | ||
1972 | } | ||
1968 | 1973 | ||
1969 | printed += fprintf(fp, "%s\n", rtrim(s)); | 1974 | printed += fprintf(fp, "%s\n", rtrim(s)); |
1970 | 1975 | ||
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index a5758fdfbe1f..4534e2d7669c 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -412,6 +412,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists, | |||
412 | for (node = rb_first(root); node; node = rb_next(node)) { | 412 | for (node = rb_first(root); node; node = rb_next(node)) { |
413 | GtkTreeIter iter; | 413 | GtkTreeIter iter; |
414 | float percent; | 414 | float percent; |
415 | char *bf; | ||
415 | 416 | ||
416 | he = rb_entry(node, struct hist_entry, rb_node); | 417 | he = rb_entry(node, struct hist_entry, rb_node); |
417 | if (he->filtered) | 418 | if (he->filtered) |
@@ -437,13 +438,20 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists, | |||
437 | gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1); | 438 | gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1); |
438 | } | 439 | } |
439 | 440 | ||
440 | fmt = he->fmt; | 441 | bf = hpp->buf; |
441 | if (fmt->color) | 442 | perf_hpp_list__for_each_format(he->hpp_list, fmt) { |
442 | fmt->color(fmt, hpp, he); | 443 | int ret; |
443 | else | 444 | |
444 | fmt->entry(fmt, hpp, he); | 445 | if (fmt->color) |
446 | ret = fmt->color(fmt, hpp, he); | ||
447 | else | ||
448 | ret = fmt->entry(fmt, hpp, he); | ||
449 | |||
450 | snprintf(hpp->buf + ret, hpp->size - ret, " "); | ||
451 | advance_hpp(hpp, ret + 2); | ||
452 | } | ||
445 | 453 | ||
446 | gtk_tree_store_set(store, &iter, col_idx, rtrim(hpp->buf), -1); | 454 | gtk_tree_store_set(store, &iter, col_idx, rtrim(bf), -1); |
447 | 455 | ||
448 | if (!he->leaf) { | 456 | if (!he->leaf) { |
449 | perf_gtk__add_hierarchy_entries(hists, &he->hroot_out, | 457 | perf_gtk__add_hierarchy_entries(hists, &he->hroot_out, |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 3a15e844f89a..95795ef4209b 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -722,6 +722,7 @@ static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt) | |||
722 | struct perf_hpp_list_node *node = NULL; | 722 | struct perf_hpp_list_node *node = NULL; |
723 | struct perf_hpp_fmt *fmt_copy; | 723 | struct perf_hpp_fmt *fmt_copy; |
724 | bool found = false; | 724 | bool found = false; |
725 | bool skip = perf_hpp__should_skip(fmt, hists); | ||
725 | 726 | ||
726 | list_for_each_entry(node, &hists->hpp_formats, list) { | 727 | list_for_each_entry(node, &hists->hpp_formats, list) { |
727 | if (node->level == fmt->level) { | 728 | if (node->level == fmt->level) { |
@@ -735,6 +736,7 @@ static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt) | |||
735 | if (node == NULL) | 736 | if (node == NULL) |
736 | return -1; | 737 | return -1; |
737 | 738 | ||
739 | node->skip = skip; | ||
738 | node->level = fmt->level; | 740 | node->level = fmt->level; |
739 | perf_hpp_list__init(&node->hpp); | 741 | perf_hpp_list__init(&node->hpp); |
740 | 742 | ||
@@ -745,6 +747,9 @@ static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt) | |||
745 | if (fmt_copy == NULL) | 747 | if (fmt_copy == NULL) |
746 | return -1; | 748 | return -1; |
747 | 749 | ||
750 | if (!skip) | ||
751 | node->skip = false; | ||
752 | |||
748 | list_add_tail(&fmt_copy->list, &node->hpp.fields); | 753 | list_add_tail(&fmt_copy->list, &node->hpp.fields); |
749 | list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts); | 754 | list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts); |
750 | 755 | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 6d06fbb365b6..073642a63cc9 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -451,33 +451,33 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he, | |||
451 | advance_hpp(hpp, ret); | 451 | advance_hpp(hpp, ret); |
452 | } | 452 | } |
453 | 453 | ||
454 | if (sep) | 454 | if (!sep) |
455 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep); | ||
456 | else | ||
457 | ret = scnprintf(hpp->buf, hpp->size, "%*s", | 455 | ret = scnprintf(hpp->buf, hpp->size, "%*s", |
458 | (nr_sort_key - 1) * HIERARCHY_INDENT + 2, ""); | 456 | (nr_sort_key - 1) * HIERARCHY_INDENT, ""); |
459 | advance_hpp(hpp, ret); | 457 | advance_hpp(hpp, ret); |
460 | 458 | ||
461 | printed += fprintf(fp, "%s", buf); | 459 | printed += fprintf(fp, "%s", buf); |
462 | 460 | ||
463 | hpp->buf = buf; | 461 | perf_hpp_list__for_each_format(he->hpp_list, fmt) { |
464 | hpp->size = size; | 462 | hpp->buf = buf; |
465 | 463 | hpp->size = size; | |
466 | /* | 464 | |
467 | * No need to call hist_entry__snprintf_alignment() since this | 465 | /* |
468 | * fmt is always the last column in the hierarchy mode. | 466 | * No need to call hist_entry__snprintf_alignment() since this |
469 | */ | 467 | * fmt is always the last column in the hierarchy mode. |
470 | fmt = he->fmt; | 468 | */ |
471 | if (perf_hpp__use_color() && fmt->color) | 469 | if (perf_hpp__use_color() && fmt->color) |
472 | fmt->color(fmt, hpp, he); | 470 | fmt->color(fmt, hpp, he); |
473 | else | 471 | else |
474 | fmt->entry(fmt, hpp, he); | 472 | fmt->entry(fmt, hpp, he); |
475 | 473 | ||
476 | /* | 474 | /* |
477 | * dynamic entries are right-aligned but we want left-aligned | 475 | * dynamic entries are right-aligned but we want left-aligned |
478 | * in the hierarchy mode | 476 | * in the hierarchy mode |
479 | */ | 477 | */ |
480 | printed += fprintf(fp, "%s\n", ltrim(buf)); | 478 | printed += fprintf(fp, "%s%s", sep ?: " ", ltrim(buf)); |
479 | } | ||
480 | printed += putc('\n', fp); | ||
481 | 481 | ||
482 | if (symbol_conf.use_callchain && he->leaf) { | 482 | if (symbol_conf.use_callchain && he->leaf) { |
483 | u64 total = hists__total_period(hists); | 483 | u64 total = hists__total_period(hists); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index fea92fcb6903..29da9e0d8db9 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1091,18 +1091,25 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he); | |||
1091 | static struct hist_entry *hierarchy_insert_entry(struct hists *hists, | 1091 | static struct hist_entry *hierarchy_insert_entry(struct hists *hists, |
1092 | struct rb_root *root, | 1092 | struct rb_root *root, |
1093 | struct hist_entry *he, | 1093 | struct hist_entry *he, |
1094 | struct perf_hpp_fmt *fmt) | 1094 | struct perf_hpp_list *hpp_list) |
1095 | { | 1095 | { |
1096 | struct rb_node **p = &root->rb_node; | 1096 | struct rb_node **p = &root->rb_node; |
1097 | struct rb_node *parent = NULL; | 1097 | struct rb_node *parent = NULL; |
1098 | struct hist_entry *iter, *new; | 1098 | struct hist_entry *iter, *new; |
1099 | struct perf_hpp_fmt *fmt; | ||
1099 | int64_t cmp; | 1100 | int64_t cmp; |
1100 | 1101 | ||
1101 | while (*p != NULL) { | 1102 | while (*p != NULL) { |
1102 | parent = *p; | 1103 | parent = *p; |
1103 | iter = rb_entry(parent, struct hist_entry, rb_node_in); | 1104 | iter = rb_entry(parent, struct hist_entry, rb_node_in); |
1104 | 1105 | ||
1105 | cmp = fmt->collapse(fmt, iter, he); | 1106 | cmp = 0; |
1107 | perf_hpp_list__for_each_sort_list(hpp_list, fmt) { | ||
1108 | cmp = fmt->collapse(fmt, iter, he); | ||
1109 | if (cmp) | ||
1110 | break; | ||
1111 | } | ||
1112 | |||
1106 | if (!cmp) { | 1113 | if (!cmp) { |
1107 | he_stat__add_stat(&iter->stat, &he->stat); | 1114 | he_stat__add_stat(&iter->stat, &he->stat); |
1108 | return iter; | 1115 | return iter; |
@@ -1121,24 +1128,26 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists, | |||
1121 | hists__apply_filters(hists, new); | 1128 | hists__apply_filters(hists, new); |
1122 | hists->nr_entries++; | 1129 | hists->nr_entries++; |
1123 | 1130 | ||
1124 | /* save related format for output */ | 1131 | /* save related format list for output */ |
1125 | new->fmt = fmt; | 1132 | new->hpp_list = hpp_list; |
1126 | 1133 | ||
1127 | /* some fields are now passed to 'new' */ | 1134 | /* some fields are now passed to 'new' */ |
1128 | if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt)) | 1135 | perf_hpp_list__for_each_sort_list(hpp_list, fmt) { |
1129 | he->trace_output = NULL; | 1136 | if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt)) |
1130 | else | 1137 | he->trace_output = NULL; |
1131 | new->trace_output = NULL; | 1138 | else |
1139 | new->trace_output = NULL; | ||
1132 | 1140 | ||
1133 | if (perf_hpp__is_srcline_entry(fmt)) | 1141 | if (perf_hpp__is_srcline_entry(fmt)) |
1134 | he->srcline = NULL; | 1142 | he->srcline = NULL; |
1135 | else | 1143 | else |
1136 | new->srcline = NULL; | 1144 | new->srcline = NULL; |
1137 | 1145 | ||
1138 | if (perf_hpp__is_srcfile_entry(fmt)) | 1146 | if (perf_hpp__is_srcfile_entry(fmt)) |
1139 | he->srcfile = NULL; | 1147 | he->srcfile = NULL; |
1140 | else | 1148 | else |
1141 | new->srcfile = NULL; | 1149 | new->srcfile = NULL; |
1150 | } | ||
1142 | 1151 | ||
1143 | rb_link_node(&new->rb_node_in, parent, p); | 1152 | rb_link_node(&new->rb_node_in, parent, p); |
1144 | rb_insert_color(&new->rb_node_in, root); | 1153 | rb_insert_color(&new->rb_node_in, root); |
@@ -1149,21 +1158,19 @@ static int hists__hierarchy_insert_entry(struct hists *hists, | |||
1149 | struct rb_root *root, | 1158 | struct rb_root *root, |
1150 | struct hist_entry *he) | 1159 | struct hist_entry *he) |
1151 | { | 1160 | { |
1152 | struct perf_hpp_fmt *fmt; | 1161 | struct perf_hpp_list_node *node; |
1153 | struct hist_entry *new_he = NULL; | 1162 | struct hist_entry *new_he = NULL; |
1154 | struct hist_entry *parent = NULL; | 1163 | struct hist_entry *parent = NULL; |
1155 | int depth = 0; | 1164 | int depth = 0; |
1156 | int ret = 0; | 1165 | int ret = 0; |
1157 | 1166 | ||
1158 | hists__for_each_sort_list(hists, fmt) { | 1167 | list_for_each_entry(node, &hists->hpp_formats, list) { |
1159 | if (!perf_hpp__is_sort_entry(fmt) && | 1168 | /* skip period (overhead) and elided columns */ |
1160 | !perf_hpp__is_dynamic_entry(fmt)) | 1169 | if (node->level == 0 || node->skip) |
1161 | continue; | ||
1162 | if (perf_hpp__should_skip(fmt, hists)) | ||
1163 | continue; | 1170 | continue; |
1164 | 1171 | ||
1165 | /* insert copy of 'he' for each fmt into the hierarchy */ | 1172 | /* insert copy of 'he' for each fmt into the hierarchy */ |
1166 | new_he = hierarchy_insert_entry(hists, root, he, fmt); | 1173 | new_he = hierarchy_insert_entry(hists, root, he, &node->hpp); |
1167 | if (new_he == NULL) { | 1174 | if (new_he == NULL) { |
1168 | ret = -1; | 1175 | ret = -1; |
1169 | break; | 1176 | break; |
@@ -1358,6 +1365,7 @@ static void hierarchy_insert_output_entry(struct rb_root *root, | |||
1358 | struct rb_node **p = &root->rb_node; | 1365 | struct rb_node **p = &root->rb_node; |
1359 | struct rb_node *parent = NULL; | 1366 | struct rb_node *parent = NULL; |
1360 | struct hist_entry *iter; | 1367 | struct hist_entry *iter; |
1368 | struct perf_hpp_fmt *fmt; | ||
1361 | 1369 | ||
1362 | while (*p != NULL) { | 1370 | while (*p != NULL) { |
1363 | parent = *p; | 1371 | parent = *p; |
@@ -1373,8 +1381,10 @@ static void hierarchy_insert_output_entry(struct rb_root *root, | |||
1373 | rb_insert_color(&he->rb_node, root); | 1381 | rb_insert_color(&he->rb_node, root); |
1374 | 1382 | ||
1375 | /* update column width of dynamic entry */ | 1383 | /* update column width of dynamic entry */ |
1376 | if (perf_hpp__is_dynamic_entry(he->fmt)) | 1384 | perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) { |
1377 | he->fmt->sort(he->fmt, he, NULL); | 1385 | if (perf_hpp__is_dynamic_entry(fmt)) |
1386 | fmt->sort(fmt, he, NULL); | ||
1387 | } | ||
1378 | } | 1388 | } |
1379 | 1389 | ||
1380 | static void hists__hierarchy_output_resort(struct hists *hists, | 1390 | static void hists__hierarchy_output_resort(struct hists *hists, |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 3cab9dc20822..2209188d729c 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -249,6 +249,7 @@ struct perf_hpp_list_node { | |||
249 | struct list_head list; | 249 | struct list_head list; |
250 | struct perf_hpp_list hpp; | 250 | struct perf_hpp_list hpp; |
251 | int level; | 251 | int level; |
252 | bool skip; | ||
252 | }; | 253 | }; |
253 | 254 | ||
254 | void perf_hpp_list__column_register(struct perf_hpp_list *list, | 255 | void perf_hpp_list__column_register(struct perf_hpp_list *list, |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 25a5529a94e4..ea1f722cffea 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -130,6 +130,7 @@ struct hist_entry { | |||
130 | u32 raw_size; | 130 | u32 raw_size; |
131 | void *trace_output; | 131 | void *trace_output; |
132 | struct perf_hpp_fmt *fmt; | 132 | struct perf_hpp_fmt *fmt; |
133 | struct perf_hpp_list *hpp_list; | ||
133 | struct hist_entry *parent_he; | 134 | struct hist_entry *parent_he; |
134 | union { | 135 | union { |
135 | /* this is for hierarchical entry structure */ | 136 | /* this is for hierarchical entry structure */ |