aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c843
1 files changed, 751 insertions, 92 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index c226303e3da0..290b3cbf6877 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -131,6 +131,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
131 symlen = unresolved_col_width + 4 + 2; 131 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
133 symlen); 133 symlen);
134 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
135 symlen);
134 } 136 }
135 137
136 if (h->mem_info->iaddr.sym) { 138 if (h->mem_info->iaddr.sym) {
@@ -177,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
177 if (h->transaction) 179 if (h->transaction)
178 hists__new_col_len(hists, HISTC_TRANSACTION, 180 hists__new_col_len(hists, HISTC_TRANSACTION,
179 hist_entry__transaction_len()); 181 hist_entry__transaction_len());
182
183 if (h->trace_output)
184 hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
180} 185}
181 186
182void hists__output_recalc_col_len(struct hists *hists, int max_rows) 187void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -243,6 +248,8 @@ static void he_stat__decay(struct he_stat *he_stat)
243 /* XXX need decay for weight too? */ 248 /* XXX need decay for weight too? */
244} 249}
245 250
251static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
252
246static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 253static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
247{ 254{
248 u64 prev_period = he->stat.period; 255 u64 prev_period = he->stat.period;
@@ -258,21 +265,45 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
258 265
259 diff = prev_period - he->stat.period; 266 diff = prev_period - he->stat.period;
260 267
261 hists->stats.total_period -= diff; 268 if (!he->depth) {
262 if (!he->filtered) 269 hists->stats.total_period -= diff;
263 hists->stats.total_non_filtered_period -= diff; 270 if (!he->filtered)
271 hists->stats.total_non_filtered_period -= diff;
272 }
273
274 if (!he->leaf) {
275 struct hist_entry *child;
276 struct rb_node *node = rb_first(&he->hroot_out);
277 while (node) {
278 child = rb_entry(node, struct hist_entry, rb_node);
279 node = rb_next(node);
280
281 if (hists__decay_entry(hists, child))
282 hists__delete_entry(hists, child);
283 }
284 }
264 285
265 return he->stat.period == 0; 286 return he->stat.period == 0;
266} 287}
267 288
268static void hists__delete_entry(struct hists *hists, struct hist_entry *he) 289static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
269{ 290{
270 rb_erase(&he->rb_node, &hists->entries); 291 struct rb_root *root_in;
292 struct rb_root *root_out;
271 293
272 if (sort__need_collapse) 294 if (he->parent_he) {
273 rb_erase(&he->rb_node_in, &hists->entries_collapsed); 295 root_in = &he->parent_he->hroot_in;
274 else 296 root_out = &he->parent_he->hroot_out;
275 rb_erase(&he->rb_node_in, hists->entries_in); 297 } else {
298 if (sort__need_collapse)
299 root_in = &hists->entries_collapsed;
300 else
301 root_in = hists->entries_in;
302 root_out = &hists->entries;
303 }
304
305 rb_erase(&he->rb_node_in, root_in);
306 rb_erase(&he->rb_node, root_out);
276 307
277 --hists->nr_entries; 308 --hists->nr_entries;
278 if (!he->filtered) 309 if (!he->filtered)
@@ -391,6 +422,9 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
391 } 422 }
392 INIT_LIST_HEAD(&he->pairs.node); 423 INIT_LIST_HEAD(&he->pairs.node);
393 thread__get(he->thread); 424 thread__get(he->thread);
425
426 if (!symbol_conf.report_hierarchy)
427 he->leaf = true;
394 } 428 }
395 429
396 return he; 430 return he;
@@ -403,6 +437,16 @@ static u8 symbol__parent_filter(const struct symbol *parent)
403 return 0; 437 return 0;
404} 438}
405 439
440static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
441{
442 if (!symbol_conf.use_callchain)
443 return;
444
445 he->hists->callchain_period += period;
446 if (!he->filtered)
447 he->hists->callchain_non_filtered_period += period;
448}
449
406static struct hist_entry *hists__findnew_entry(struct hists *hists, 450static struct hist_entry *hists__findnew_entry(struct hists *hists,
407 struct hist_entry *entry, 451 struct hist_entry *entry,
408 struct addr_location *al, 452 struct addr_location *al,
@@ -430,8 +474,10 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
430 cmp = hist_entry__cmp(he, entry); 474 cmp = hist_entry__cmp(he, entry);
431 475
432 if (!cmp) { 476 if (!cmp) {
433 if (sample_self) 477 if (sample_self) {
434 he_stat__add_period(&he->stat, period, weight); 478 he_stat__add_period(&he->stat, period, weight);
479 hist_entry__add_callchain_period(he, period);
480 }
435 if (symbol_conf.cumulate_callchain) 481 if (symbol_conf.cumulate_callchain)
436 he_stat__add_period(he->stat_acc, period, weight); 482 he_stat__add_period(he->stat_acc, period, weight);
437 483
@@ -464,6 +510,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
464 if (!he) 510 if (!he)
465 return NULL; 511 return NULL;
466 512
513 if (sample_self)
514 hist_entry__add_callchain_period(he, period);
467 hists->nr_entries++; 515 hists->nr_entries++;
468 516
469 rb_link_node(&he->rb_node_in, parent, p); 517 rb_link_node(&he->rb_node_in, parent, p);
@@ -949,10 +997,15 @@ out:
949int64_t 997int64_t
950hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 998hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
951{ 999{
1000 struct hists *hists = left->hists;
952 struct perf_hpp_fmt *fmt; 1001 struct perf_hpp_fmt *fmt;
953 int64_t cmp = 0; 1002 int64_t cmp = 0;
954 1003
955 perf_hpp__for_each_sort_list(fmt) { 1004 hists__for_each_sort_list(hists, fmt) {
1005 if (perf_hpp__is_dynamic_entry(fmt) &&
1006 !perf_hpp__defined_dynamic_entry(fmt, hists))
1007 continue;
1008
956 cmp = fmt->cmp(fmt, left, right); 1009 cmp = fmt->cmp(fmt, left, right);
957 if (cmp) 1010 if (cmp)
958 break; 1011 break;
@@ -964,10 +1017,15 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
964int64_t 1017int64_t
965hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 1018hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
966{ 1019{
1020 struct hists *hists = left->hists;
967 struct perf_hpp_fmt *fmt; 1021 struct perf_hpp_fmt *fmt;
968 int64_t cmp = 0; 1022 int64_t cmp = 0;
969 1023
970 perf_hpp__for_each_sort_list(fmt) { 1024 hists__for_each_sort_list(hists, fmt) {
1025 if (perf_hpp__is_dynamic_entry(fmt) &&
1026 !perf_hpp__defined_dynamic_entry(fmt, hists))
1027 continue;
1028
971 cmp = fmt->collapse(fmt, left, right); 1029 cmp = fmt->collapse(fmt, left, right);
972 if (cmp) 1030 if (cmp)
973 break; 1031 break;
@@ -1004,17 +1062,250 @@ void hist_entry__delete(struct hist_entry *he)
1004} 1062}
1005 1063
1006/* 1064/*
1065 * If this is not the last column, then we need to pad it according to the
1066 * pre-calculated max lenght for this column, otherwise don't bother adding
1067 * spaces because that would break viewing this with, for instance, 'less',
1068 * that would show tons of trailing spaces when a long C++ demangled method
1069 * names is sampled.
1070*/
1071int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
1072 struct perf_hpp_fmt *fmt, int printed)
1073{
1074 if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
1075 const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists));
1076 if (printed < width) {
1077 advance_hpp(hpp, printed);
1078 printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
1079 }
1080 }
1081
1082 return printed;
1083}
1084
1085/*
1007 * collapse the histogram 1086 * collapse the histogram
1008 */ 1087 */
1009 1088
1010bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 1089static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
1011 struct rb_root *root, struct hist_entry *he) 1090static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
1091 enum hist_filter type);
1092
1093typedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
1094
1095static bool check_thread_entry(struct perf_hpp_fmt *fmt)
1096{
1097 return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
1098}
1099
1100static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1101 enum hist_filter type,
1102 fmt_chk_fn check)
1103{
1104 struct perf_hpp_fmt *fmt;
1105 bool type_match = false;
1106 struct hist_entry *parent = he->parent_he;
1107
1108 switch (type) {
1109 case HIST_FILTER__THREAD:
1110 if (symbol_conf.comm_list == NULL &&
1111 symbol_conf.pid_list == NULL &&
1112 symbol_conf.tid_list == NULL)
1113 return;
1114 break;
1115 case HIST_FILTER__DSO:
1116 if (symbol_conf.dso_list == NULL)
1117 return;
1118 break;
1119 case HIST_FILTER__SYMBOL:
1120 if (symbol_conf.sym_list == NULL)
1121 return;
1122 break;
1123 case HIST_FILTER__PARENT:
1124 case HIST_FILTER__GUEST:
1125 case HIST_FILTER__HOST:
1126 case HIST_FILTER__SOCKET:
1127 default:
1128 return;
1129 }
1130
1131 /* if it's filtered by own fmt, it has to have filter bits */
1132 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1133 if (check(fmt)) {
1134 type_match = true;
1135 break;
1136 }
1137 }
1138
1139 if (type_match) {
1140 /*
1141 * If the filter is for current level entry, propagate
1142 * filter marker to parents. The marker bit was
1143 * already set by default so it only needs to clear
1144 * non-filtered entries.
1145 */
1146 if (!(he->filtered & (1 << type))) {
1147 while (parent) {
1148 parent->filtered &= ~(1 << type);
1149 parent = parent->parent_he;
1150 }
1151 }
1152 } else {
1153 /*
1154 * If current entry doesn't have matching formats, set
1155 * filter marker for upper level entries. it will be
1156 * cleared if its lower level entries is not filtered.
1157 *
1158 * For lower-level entries, it inherits parent's
1159 * filter bit so that lower level entries of a
1160 * non-filtered entry won't set the filter marker.
1161 */
1162 if (parent == NULL)
1163 he->filtered |= (1 << type);
1164 else
1165 he->filtered |= (parent->filtered & (1 << type));
1166 }
1167}
1168
1169static void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
1170{
1171 hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
1172 check_thread_entry);
1173
1174 hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
1175 perf_hpp__is_dso_entry);
1176
1177 hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
1178 perf_hpp__is_sym_entry);
1179
1180 hists__apply_filters(he->hists, he);
1181}
1182
1183static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
1184 struct rb_root *root,
1185 struct hist_entry *he,
1186 struct hist_entry *parent_he,
1187 struct perf_hpp_list *hpp_list)
1188{
1189 struct rb_node **p = &root->rb_node;
1190 struct rb_node *parent = NULL;
1191 struct hist_entry *iter, *new;
1192 struct perf_hpp_fmt *fmt;
1193 int64_t cmp;
1194
1195 while (*p != NULL) {
1196 parent = *p;
1197 iter = rb_entry(parent, struct hist_entry, rb_node_in);
1198
1199 cmp = 0;
1200 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1201 cmp = fmt->collapse(fmt, iter, he);
1202 if (cmp)
1203 break;
1204 }
1205
1206 if (!cmp) {
1207 he_stat__add_stat(&iter->stat, &he->stat);
1208 return iter;
1209 }
1210
1211 if (cmp < 0)
1212 p = &parent->rb_left;
1213 else
1214 p = &parent->rb_right;
1215 }
1216
1217 new = hist_entry__new(he, true);
1218 if (new == NULL)
1219 return NULL;
1220
1221 hists->nr_entries++;
1222
1223 /* save related format list for output */
1224 new->hpp_list = hpp_list;
1225 new->parent_he = parent_he;
1226
1227 hist_entry__apply_hierarchy_filters(new);
1228
1229 /* some fields are now passed to 'new' */
1230 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1231 if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1232 he->trace_output = NULL;
1233 else
1234 new->trace_output = NULL;
1235
1236 if (perf_hpp__is_srcline_entry(fmt))
1237 he->srcline = NULL;
1238 else
1239 new->srcline = NULL;
1240
1241 if (perf_hpp__is_srcfile_entry(fmt))
1242 he->srcfile = NULL;
1243 else
1244 new->srcfile = NULL;
1245 }
1246
1247 rb_link_node(&new->rb_node_in, parent, p);
1248 rb_insert_color(&new->rb_node_in, root);
1249 return new;
1250}
1251
1252static int hists__hierarchy_insert_entry(struct hists *hists,
1253 struct rb_root *root,
1254 struct hist_entry *he)
1255{
1256 struct perf_hpp_list_node *node;
1257 struct hist_entry *new_he = NULL;
1258 struct hist_entry *parent = NULL;
1259 int depth = 0;
1260 int ret = 0;
1261
1262 list_for_each_entry(node, &hists->hpp_formats, list) {
1263 /* skip period (overhead) and elided columns */
1264 if (node->level == 0 || node->skip)
1265 continue;
1266
1267 /* insert copy of 'he' for each fmt into the hierarchy */
1268 new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
1269 if (new_he == NULL) {
1270 ret = -1;
1271 break;
1272 }
1273
1274 root = &new_he->hroot_in;
1275 new_he->depth = depth++;
1276 parent = new_he;
1277 }
1278
1279 if (new_he) {
1280 new_he->leaf = true;
1281
1282 if (symbol_conf.use_callchain) {
1283 callchain_cursor_reset(&callchain_cursor);
1284 if (callchain_merge(&callchain_cursor,
1285 new_he->callchain,
1286 he->callchain) < 0)
1287 ret = -1;
1288 }
1289 }
1290
1291 /* 'he' is no longer used */
1292 hist_entry__delete(he);
1293
1294 /* return 0 (or -1) since it already applied filters */
1295 return ret;
1296}
1297
1298int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root,
1299 struct hist_entry *he)
1012{ 1300{
1013 struct rb_node **p = &root->rb_node; 1301 struct rb_node **p = &root->rb_node;
1014 struct rb_node *parent = NULL; 1302 struct rb_node *parent = NULL;
1015 struct hist_entry *iter; 1303 struct hist_entry *iter;
1016 int64_t cmp; 1304 int64_t cmp;
1017 1305
1306 if (symbol_conf.report_hierarchy)
1307 return hists__hierarchy_insert_entry(hists, root, he);
1308
1018 while (*p != NULL) { 1309 while (*p != NULL) {
1019 parent = *p; 1310 parent = *p;
1020 iter = rb_entry(parent, struct hist_entry, rb_node_in); 1311 iter = rb_entry(parent, struct hist_entry, rb_node_in);
@@ -1022,18 +1313,21 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1022 cmp = hist_entry__collapse(iter, he); 1313 cmp = hist_entry__collapse(iter, he);
1023 1314
1024 if (!cmp) { 1315 if (!cmp) {
1316 int ret = 0;
1317
1025 he_stat__add_stat(&iter->stat, &he->stat); 1318 he_stat__add_stat(&iter->stat, &he->stat);
1026 if (symbol_conf.cumulate_callchain) 1319 if (symbol_conf.cumulate_callchain)
1027 he_stat__add_stat(iter->stat_acc, he->stat_acc); 1320 he_stat__add_stat(iter->stat_acc, he->stat_acc);
1028 1321
1029 if (symbol_conf.use_callchain) { 1322 if (symbol_conf.use_callchain) {
1030 callchain_cursor_reset(&callchain_cursor); 1323 callchain_cursor_reset(&callchain_cursor);
1031 callchain_merge(&callchain_cursor, 1324 if (callchain_merge(&callchain_cursor,
1032 iter->callchain, 1325 iter->callchain,
1033 he->callchain); 1326 he->callchain) < 0)
1327 ret = -1;
1034 } 1328 }
1035 hist_entry__delete(he); 1329 hist_entry__delete(he);
1036 return false; 1330 return ret;
1037 } 1331 }
1038 1332
1039 if (cmp < 0) 1333 if (cmp < 0)
@@ -1045,7 +1339,7 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1045 1339
1046 rb_link_node(&he->rb_node_in, parent, p); 1340 rb_link_node(&he->rb_node_in, parent, p);
1047 rb_insert_color(&he->rb_node_in, root); 1341 rb_insert_color(&he->rb_node_in, root);
1048 return true; 1342 return 1;
1049} 1343}
1050 1344
1051struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 1345struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
@@ -1071,14 +1365,15 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
1071 hists__filter_entry_by_socket(hists, he); 1365 hists__filter_entry_by_socket(hists, he);
1072} 1366}
1073 1367
1074void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) 1368int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1075{ 1369{
1076 struct rb_root *root; 1370 struct rb_root *root;
1077 struct rb_node *next; 1371 struct rb_node *next;
1078 struct hist_entry *n; 1372 struct hist_entry *n;
1373 int ret;
1079 1374
1080 if (!sort__need_collapse) 1375 if (!sort__need_collapse)
1081 return; 1376 return 0;
1082 1377
1083 hists->nr_entries = 0; 1378 hists->nr_entries = 0;
1084 1379
@@ -1093,7 +1388,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1093 next = rb_next(&n->rb_node_in); 1388 next = rb_next(&n->rb_node_in);
1094 1389
1095 rb_erase(&n->rb_node_in, root); 1390 rb_erase(&n->rb_node_in, root);
1096 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) { 1391 ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
1392 if (ret < 0)
1393 return -1;
1394
1395 if (ret) {
1097 /* 1396 /*
1098 * If it wasn't combined with one of the entries already 1397 * If it wasn't combined with one of the entries already
1099 * collapsed, we need to apply the filters that may have 1398 * collapsed, we need to apply the filters that may have
@@ -1104,14 +1403,16 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1104 if (prog) 1403 if (prog)
1105 ui_progress__update(prog, 1); 1404 ui_progress__update(prog, 1);
1106 } 1405 }
1406 return 0;
1107} 1407}
1108 1408
1109static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) 1409static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
1110{ 1410{
1411 struct hists *hists = a->hists;
1111 struct perf_hpp_fmt *fmt; 1412 struct perf_hpp_fmt *fmt;
1112 int64_t cmp = 0; 1413 int64_t cmp = 0;
1113 1414
1114 perf_hpp__for_each_sort_list(fmt) { 1415 hists__for_each_sort_list(hists, fmt) {
1115 if (perf_hpp__should_skip(fmt, a->hists)) 1416 if (perf_hpp__should_skip(fmt, a->hists))
1116 continue; 1417 continue;
1117 1418
@@ -1152,6 +1453,113 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
1152 hists->stats.total_period += h->stat.period; 1453 hists->stats.total_period += h->stat.period;
1153} 1454}
1154 1455
1456static void hierarchy_recalc_total_periods(struct hists *hists)
1457{
1458 struct rb_node *node;
1459 struct hist_entry *he;
1460
1461 node = rb_first(&hists->entries);
1462
1463 hists->stats.total_period = 0;
1464 hists->stats.total_non_filtered_period = 0;
1465
1466 /*
1467 * recalculate total period using top-level entries only
1468 * since lower level entries only see non-filtered entries
1469 * but upper level entries have sum of both entries.
1470 */
1471 while (node) {
1472 he = rb_entry(node, struct hist_entry, rb_node);
1473 node = rb_next(node);
1474
1475 hists->stats.total_period += he->stat.period;
1476 if (!he->filtered)
1477 hists->stats.total_non_filtered_period += he->stat.period;
1478 }
1479}
1480
1481static void hierarchy_insert_output_entry(struct rb_root *root,
1482 struct hist_entry *he)
1483{
1484 struct rb_node **p = &root->rb_node;
1485 struct rb_node *parent = NULL;
1486 struct hist_entry *iter;
1487 struct perf_hpp_fmt *fmt;
1488
1489 while (*p != NULL) {
1490 parent = *p;
1491 iter = rb_entry(parent, struct hist_entry, rb_node);
1492
1493 if (hist_entry__sort(he, iter) > 0)
1494 p = &parent->rb_left;
1495 else
1496 p = &parent->rb_right;
1497 }
1498
1499 rb_link_node(&he->rb_node, parent, p);
1500 rb_insert_color(&he->rb_node, root);
1501
1502 /* update column width of dynamic entry */
1503 perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
1504 if (perf_hpp__is_dynamic_entry(fmt))
1505 fmt->sort(fmt, he, NULL);
1506 }
1507}
1508
1509static void hists__hierarchy_output_resort(struct hists *hists,
1510 struct ui_progress *prog,
1511 struct rb_root *root_in,
1512 struct rb_root *root_out,
1513 u64 min_callchain_hits,
1514 bool use_callchain)
1515{
1516 struct rb_node *node;
1517 struct hist_entry *he;
1518
1519 *root_out = RB_ROOT;
1520 node = rb_first(root_in);
1521
1522 while (node) {
1523 he = rb_entry(node, struct hist_entry, rb_node_in);
1524 node = rb_next(node);
1525
1526 hierarchy_insert_output_entry(root_out, he);
1527
1528 if (prog)
1529 ui_progress__update(prog, 1);
1530
1531 if (!he->leaf) {
1532 hists__hierarchy_output_resort(hists, prog,
1533 &he->hroot_in,
1534 &he->hroot_out,
1535 min_callchain_hits,
1536 use_callchain);
1537 hists->nr_entries++;
1538 if (!he->filtered) {
1539 hists->nr_non_filtered_entries++;
1540 hists__calc_col_len(hists, he);
1541 }
1542
1543 continue;
1544 }
1545
1546 if (!use_callchain)
1547 continue;
1548
1549 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1550 u64 total = he->stat.period;
1551
1552 if (symbol_conf.cumulate_callchain)
1553 total = he->stat_acc->period;
1554
1555 min_callchain_hits = total * (callchain_param.min_percent / 100);
1556 }
1557
1558 callchain_param.sort(&he->sorted_chain, he->callchain,
1559 min_callchain_hits, &callchain_param);
1560 }
1561}
1562
1155static void __hists__insert_output_entry(struct rb_root *entries, 1563static void __hists__insert_output_entry(struct rb_root *entries,
1156 struct hist_entry *he, 1564 struct hist_entry *he,
1157 u64 min_callchain_hits, 1565 u64 min_callchain_hits,
@@ -1160,10 +1568,20 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1160 struct rb_node **p = &entries->rb_node; 1568 struct rb_node **p = &entries->rb_node;
1161 struct rb_node *parent = NULL; 1569 struct rb_node *parent = NULL;
1162 struct hist_entry *iter; 1570 struct hist_entry *iter;
1571 struct perf_hpp_fmt *fmt;
1572
1573 if (use_callchain) {
1574 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1575 u64 total = he->stat.period;
1163 1576
1164 if (use_callchain) 1577 if (symbol_conf.cumulate_callchain)
1578 total = he->stat_acc->period;
1579
1580 min_callchain_hits = total * (callchain_param.min_percent / 100);
1581 }
1165 callchain_param.sort(&he->sorted_chain, he->callchain, 1582 callchain_param.sort(&he->sorted_chain, he->callchain,
1166 min_callchain_hits, &callchain_param); 1583 min_callchain_hits, &callchain_param);
1584 }
1167 1585
1168 while (*p != NULL) { 1586 while (*p != NULL) {
1169 parent = *p; 1587 parent = *p;
@@ -1177,23 +1595,41 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1177 1595
1178 rb_link_node(&he->rb_node, parent, p); 1596 rb_link_node(&he->rb_node, parent, p);
1179 rb_insert_color(&he->rb_node, entries); 1597 rb_insert_color(&he->rb_node, entries);
1598
1599 perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
1600 if (perf_hpp__is_dynamic_entry(fmt) &&
1601 perf_hpp__defined_dynamic_entry(fmt, he->hists))
1602 fmt->sort(fmt, he, NULL); /* update column width */
1603 }
1180} 1604}
1181 1605
1182void hists__output_resort(struct hists *hists, struct ui_progress *prog) 1606static void output_resort(struct hists *hists, struct ui_progress *prog,
1607 bool use_callchain)
1183{ 1608{
1184 struct rb_root *root; 1609 struct rb_root *root;
1185 struct rb_node *next; 1610 struct rb_node *next;
1186 struct hist_entry *n; 1611 struct hist_entry *n;
1612 u64 callchain_total;
1187 u64 min_callchain_hits; 1613 u64 min_callchain_hits;
1188 struct perf_evsel *evsel = hists_to_evsel(hists);
1189 bool use_callchain;
1190 1614
1191 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) 1615 callchain_total = hists->callchain_period;
1192 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; 1616 if (symbol_conf.filter_relative)
1193 else 1617 callchain_total = hists->callchain_non_filtered_period;
1194 use_callchain = symbol_conf.use_callchain;
1195 1618
1196 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 1619 min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
1620
1621 hists__reset_stats(hists);
1622 hists__reset_col_len(hists);
1623
1624 if (symbol_conf.report_hierarchy) {
1625 hists__hierarchy_output_resort(hists, prog,
1626 &hists->entries_collapsed,
1627 &hists->entries,
1628 min_callchain_hits,
1629 use_callchain);
1630 hierarchy_recalc_total_periods(hists);
1631 return;
1632 }
1197 1633
1198 if (sort__need_collapse) 1634 if (sort__need_collapse)
1199 root = &hists->entries_collapsed; 1635 root = &hists->entries_collapsed;
@@ -1203,9 +1639,6 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1203 next = rb_first(root); 1639 next = rb_first(root);
1204 hists->entries = RB_ROOT; 1640 hists->entries = RB_ROOT;
1205 1641
1206 hists__reset_stats(hists);
1207 hists__reset_col_len(hists);
1208
1209 while (next) { 1642 while (next) {
1210 n = rb_entry(next, struct hist_entry, rb_node_in); 1643 n = rb_entry(next, struct hist_entry, rb_node_in);
1211 next = rb_next(&n->rb_node_in); 1644 next = rb_next(&n->rb_node_in);
@@ -1221,15 +1654,136 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1221 } 1654 }
1222} 1655}
1223 1656
1657void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog)
1658{
1659 bool use_callchain;
1660
1661 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
1662 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
1663 else
1664 use_callchain = symbol_conf.use_callchain;
1665
1666 output_resort(evsel__hists(evsel), prog, use_callchain);
1667}
1668
1669void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1670{
1671 output_resort(hists, prog, symbol_conf.use_callchain);
1672}
1673
1674static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
1675{
1676 if (he->leaf || hmd == HMD_FORCE_SIBLING)
1677 return false;
1678
1679 if (he->unfolded || hmd == HMD_FORCE_CHILD)
1680 return true;
1681
1682 return false;
1683}
1684
1685struct rb_node *rb_hierarchy_last(struct rb_node *node)
1686{
1687 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1688
1689 while (can_goto_child(he, HMD_NORMAL)) {
1690 node = rb_last(&he->hroot_out);
1691 he = rb_entry(node, struct hist_entry, rb_node);
1692 }
1693 return node;
1694}
1695
1696struct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
1697{
1698 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1699
1700 if (can_goto_child(he, hmd))
1701 node = rb_first(&he->hroot_out);
1702 else
1703 node = rb_next(node);
1704
1705 while (node == NULL) {
1706 he = he->parent_he;
1707 if (he == NULL)
1708 break;
1709
1710 node = rb_next(&he->rb_node);
1711 }
1712 return node;
1713}
1714
1715struct rb_node *rb_hierarchy_prev(struct rb_node *node)
1716{
1717 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1718
1719 node = rb_prev(node);
1720 if (node)
1721 return rb_hierarchy_last(node);
1722
1723 he = he->parent_he;
1724 if (he == NULL)
1725 return NULL;
1726
1727 return &he->rb_node;
1728}
1729
1730bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
1731{
1732 struct rb_node *node;
1733 struct hist_entry *child;
1734 float percent;
1735
1736 if (he->leaf)
1737 return false;
1738
1739 node = rb_first(&he->hroot_out);
1740 child = rb_entry(node, struct hist_entry, rb_node);
1741
1742 while (node && child->filtered) {
1743 node = rb_next(node);
1744 child = rb_entry(node, struct hist_entry, rb_node);
1745 }
1746
1747 if (node)
1748 percent = hist_entry__get_percent_limit(child);
1749 else
1750 percent = 0;
1751
1752 return node && percent >= limit;
1753}
1754
1224static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 1755static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
1225 enum hist_filter filter) 1756 enum hist_filter filter)
1226{ 1757{
1227 h->filtered &= ~(1 << filter); 1758 h->filtered &= ~(1 << filter);
1759
1760 if (symbol_conf.report_hierarchy) {
1761 struct hist_entry *parent = h->parent_he;
1762
1763 while (parent) {
1764 he_stat__add_stat(&parent->stat, &h->stat);
1765
1766 parent->filtered &= ~(1 << filter);
1767
1768 if (parent->filtered)
1769 goto next;
1770
1771 /* force fold unfiltered entry for simplicity */
1772 parent->unfolded = false;
1773 parent->has_no_entry = false;
1774 parent->row_offset = 0;
1775 parent->nr_rows = 0;
1776next:
1777 parent = parent->parent_he;
1778 }
1779 }
1780
1228 if (h->filtered) 1781 if (h->filtered)
1229 return; 1782 return;
1230 1783
1231 /* force fold unfiltered entry for simplicity */ 1784 /* force fold unfiltered entry for simplicity */
1232 h->unfolded = false; 1785 h->unfolded = false;
1786 h->has_no_entry = false;
1233 h->row_offset = 0; 1787 h->row_offset = 0;
1234 h->nr_rows = 0; 1788 h->nr_rows = 0;
1235 1789
@@ -1252,28 +1806,6 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
1252 return false; 1806 return false;
1253} 1807}
1254 1808
1255void hists__filter_by_dso(struct hists *hists)
1256{
1257 struct rb_node *nd;
1258
1259 hists->stats.nr_non_filtered_samples = 0;
1260
1261 hists__reset_filter_stats(hists);
1262 hists__reset_col_len(hists);
1263
1264 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1265 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1266
1267 if (symbol_conf.exclude_other && !h->parent)
1268 continue;
1269
1270 if (hists__filter_entry_by_dso(hists, h))
1271 continue;
1272
1273 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1274 }
1275}
1276
1277static bool hists__filter_entry_by_thread(struct hists *hists, 1809static bool hists__filter_entry_by_thread(struct hists *hists,
1278 struct hist_entry *he) 1810 struct hist_entry *he)
1279{ 1811{
@@ -1286,25 +1818,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
1286 return false; 1818 return false;
1287} 1819}
1288 1820
1289void hists__filter_by_thread(struct hists *hists)
1290{
1291 struct rb_node *nd;
1292
1293 hists->stats.nr_non_filtered_samples = 0;
1294
1295 hists__reset_filter_stats(hists);
1296 hists__reset_col_len(hists);
1297
1298 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1299 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1300
1301 if (hists__filter_entry_by_thread(hists, h))
1302 continue;
1303
1304 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1305 }
1306}
1307
1308static bool hists__filter_entry_by_symbol(struct hists *hists, 1821static bool hists__filter_entry_by_symbol(struct hists *hists,
1309 struct hist_entry *he) 1822 struct hist_entry *he)
1310{ 1823{
@@ -1318,7 +1831,21 @@ static bool hists__filter_entry_by_symbol(struct hists *hists,
1318 return false; 1831 return false;
1319} 1832}
1320 1833
1321void hists__filter_by_symbol(struct hists *hists) 1834static bool hists__filter_entry_by_socket(struct hists *hists,
1835 struct hist_entry *he)
1836{
1837 if ((hists->socket_filter > -1) &&
1838 (he->socket != hists->socket_filter)) {
1839 he->filtered |= (1 << HIST_FILTER__SOCKET);
1840 return true;
1841 }
1842
1843 return false;
1844}
1845
1846typedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
1847
1848static void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
1322{ 1849{
1323 struct rb_node *nd; 1850 struct rb_node *nd;
1324 1851
@@ -1330,42 +1857,155 @@ void hists__filter_by_symbol(struct hists *hists)
1330 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1857 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1331 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1858 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1332 1859
1333 if (hists__filter_entry_by_symbol(hists, h)) 1860 if (filter(hists, h))
1334 continue; 1861 continue;
1335 1862
1336 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1863 hists__remove_entry_filter(hists, h, type);
1337 } 1864 }
1338} 1865}
1339 1866
1340static bool hists__filter_entry_by_socket(struct hists *hists, 1867static void resort_filtered_entry(struct rb_root *root, struct hist_entry *he)
1341 struct hist_entry *he)
1342{ 1868{
1343 if ((hists->socket_filter > -1) && 1869 struct rb_node **p = &root->rb_node;
1344 (he->socket != hists->socket_filter)) { 1870 struct rb_node *parent = NULL;
1345 he->filtered |= (1 << HIST_FILTER__SOCKET); 1871 struct hist_entry *iter;
1346 return true; 1872 struct rb_root new_root = RB_ROOT;
1873 struct rb_node *nd;
1874
1875 while (*p != NULL) {
1876 parent = *p;
1877 iter = rb_entry(parent, struct hist_entry, rb_node);
1878
1879 if (hist_entry__sort(he, iter) > 0)
1880 p = &(*p)->rb_left;
1881 else
1882 p = &(*p)->rb_right;
1347 } 1883 }
1348 1884
1349 return false; 1885 rb_link_node(&he->rb_node, parent, p);
1886 rb_insert_color(&he->rb_node, root);
1887
1888 if (he->leaf || he->filtered)
1889 return;
1890
1891 nd = rb_first(&he->hroot_out);
1892 while (nd) {
1893 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1894
1895 nd = rb_next(nd);
1896 rb_erase(&h->rb_node, &he->hroot_out);
1897
1898 resort_filtered_entry(&new_root, h);
1899 }
1900
1901 he->hroot_out = new_root;
1350} 1902}
1351 1903
1352void hists__filter_by_socket(struct hists *hists) 1904static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
1353{ 1905{
1354 struct rb_node *nd; 1906 struct rb_node *nd;
1907 struct rb_root new_root = RB_ROOT;
1355 1908
1356 hists->stats.nr_non_filtered_samples = 0; 1909 hists->stats.nr_non_filtered_samples = 0;
1357 1910
1358 hists__reset_filter_stats(hists); 1911 hists__reset_filter_stats(hists);
1359 hists__reset_col_len(hists); 1912 hists__reset_col_len(hists);
1360 1913
1361 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1914 nd = rb_first(&hists->entries);
1915 while (nd) {
1362 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1917 int ret;
1363 1918
1364 if (hists__filter_entry_by_socket(hists, h)) 1919 ret = hist_entry__filter(h, type, arg);
1365 continue;
1366 1920
1367 hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET); 1921 /*
1922 * case 1. non-matching type
1923 * zero out the period, set filter marker and move to child
1924 */
1925 if (ret < 0) {
1926 memset(&h->stat, 0, sizeof(h->stat));
1927 h->filtered |= (1 << type);
1928
1929 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
1930 }
1931 /*
1932 * case 2. matched type (filter out)
1933 * set filter marker and move to next
1934 */
1935 else if (ret == 1) {
1936 h->filtered |= (1 << type);
1937
1938 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1939 }
1940 /*
1941 * case 3. ok (not filtered)
1942 * add period to hists and parents, erase the filter marker
1943 * and move to next sibling
1944 */
1945 else {
1946 hists__remove_entry_filter(hists, h, type);
1947
1948 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1949 }
1950 }
1951
1952 hierarchy_recalc_total_periods(hists);
1953
1954 /*
1955 * resort output after applying a new filter since filter in a lower
1956 * hierarchy can change periods in a upper hierarchy.
1957 */
1958 nd = rb_first(&hists->entries);
1959 while (nd) {
1960 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1961
1962 nd = rb_next(nd);
1963 rb_erase(&h->rb_node, &hists->entries);
1964
1965 resort_filtered_entry(&new_root, h);
1368 } 1966 }
1967
1968 hists->entries = new_root;
1969}
1970
1971void hists__filter_by_thread(struct hists *hists)
1972{
1973 if (symbol_conf.report_hierarchy)
1974 hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
1975 hists->thread_filter);
1976 else
1977 hists__filter_by_type(hists, HIST_FILTER__THREAD,
1978 hists__filter_entry_by_thread);
1979}
1980
1981void hists__filter_by_dso(struct hists *hists)
1982{
1983 if (symbol_conf.report_hierarchy)
1984 hists__filter_hierarchy(hists, HIST_FILTER__DSO,
1985 hists->dso_filter);
1986 else
1987 hists__filter_by_type(hists, HIST_FILTER__DSO,
1988 hists__filter_entry_by_dso);
1989}
1990
1991void hists__filter_by_symbol(struct hists *hists)
1992{
1993 if (symbol_conf.report_hierarchy)
1994 hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
1995 hists->symbol_filter_str);
1996 else
1997 hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
1998 hists__filter_entry_by_symbol);
1999}
2000
2001void hists__filter_by_socket(struct hists *hists)
2002{
2003 if (symbol_conf.report_hierarchy)
2004 hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
2005 &hists->socket_filter);
2006 else
2007 hists__filter_by_type(hists, HIST_FILTER__SOCKET,
2008 hists__filter_entry_by_socket);
1369} 2009}
1370 2010
1371void events_stats__inc(struct events_stats *stats, u32 type) 2011void events_stats__inc(struct events_stats *stats, u32 type)
@@ -1583,7 +2223,7 @@ int perf_hist_config(const char *var, const char *value)
1583 return 0; 2223 return 0;
1584} 2224}
1585 2225
1586int __hists__init(struct hists *hists) 2226int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
1587{ 2227{
1588 memset(hists, 0, sizeof(*hists)); 2228 memset(hists, 0, sizeof(*hists));
1589 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 2229 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -1592,6 +2232,8 @@ int __hists__init(struct hists *hists)
1592 hists->entries = RB_ROOT; 2232 hists->entries = RB_ROOT;
1593 pthread_mutex_init(&hists->lock, NULL); 2233 pthread_mutex_init(&hists->lock, NULL);
1594 hists->socket_filter = -1; 2234 hists->socket_filter = -1;
2235 hists->hpp_list = hpp_list;
2236 INIT_LIST_HEAD(&hists->hpp_formats);
1595 return 0; 2237 return 0;
1596} 2238}
1597 2239
@@ -1620,15 +2262,26 @@ static void hists__delete_all_entries(struct hists *hists)
1620static void hists_evsel__exit(struct perf_evsel *evsel) 2262static void hists_evsel__exit(struct perf_evsel *evsel)
1621{ 2263{
1622 struct hists *hists = evsel__hists(evsel); 2264 struct hists *hists = evsel__hists(evsel);
2265 struct perf_hpp_fmt *fmt, *pos;
2266 struct perf_hpp_list_node *node, *tmp;
1623 2267
1624 hists__delete_all_entries(hists); 2268 hists__delete_all_entries(hists);
2269
2270 list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
2271 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
2272 list_del(&fmt->list);
2273 free(fmt);
2274 }
2275 list_del(&node->list);
2276 free(node);
2277 }
1625} 2278}
1626 2279
1627static int hists_evsel__init(struct perf_evsel *evsel) 2280static int hists_evsel__init(struct perf_evsel *evsel)
1628{ 2281{
1629 struct hists *hists = evsel__hists(evsel); 2282 struct hists *hists = evsel__hists(evsel);
1630 2283
1631 __hists__init(hists); 2284 __hists__init(hists, &perf_hpp_list);
1632 return 0; 2285 return 0;
1633} 2286}
1634 2287
@@ -1647,3 +2300,9 @@ int hists__init(void)
1647 2300
1648 return err; 2301 return err;
1649} 2302}
2303
2304void perf_hpp_list__init(struct perf_hpp_list *list)
2305{
2306 INIT_LIST_HEAD(&list->fields);
2307 INIT_LIST_HEAD(&list->sorts);
2308}