hc
2024-05-16 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb
kernel/tools/perf/builtin-report.c
....@@ -8,15 +8,20 @@
88 */
99 #include "builtin.h"
1010
11
-#include "util/util.h"
1211 #include "util/config.h"
1312
1413 #include "util/annotate.h"
1514 #include "util/color.h"
15
+#include "util/dso.h"
1616 #include <linux/list.h>
1717 #include <linux/rbtree.h>
1818 #include <linux/err.h>
19
+#include <linux/zalloc.h>
20
+#include "util/map.h"
1921 #include "util/symbol.h"
22
+#include "util/map_symbol.h"
23
+#include "util/mem-events.h"
24
+#include "util/branch.h"
2025 #include "util/callchain.h"
2126 #include "util/values.h"
2227
....@@ -24,8 +29,10 @@
2429 #include "util/debug.h"
2530 #include "util/evlist.h"
2631 #include "util/evsel.h"
32
+#include "util/evswitch.h"
2733 #include "util/header.h"
2834 #include "util/session.h"
35
+#include "util/srcline.h"
2936 #include "util/tool.h"
3037
3138 #include <subcmd/parse-options.h>
....@@ -40,15 +47,21 @@
4047 #include "util/time-utils.h"
4148 #include "util/auxtrace.h"
4249 #include "util/units.h"
43
-#include "util/branch.h"
50
+#include "util/util.h" // perf_tip()
51
+#include "ui/ui.h"
52
+#include "ui/progress.h"
53
+#include "util/block-info.h"
4454
4555 #include <dlfcn.h>
4656 #include <errno.h>
4757 #include <inttypes.h>
4858 #include <regex.h>
59
+#include <linux/ctype.h>
4960 #include <signal.h>
5061 #include <linux/bitmap.h>
62
+#include <linux/string.h>
5163 #include <linux/stringify.h>
64
+#include <linux/time64.h>
5265 #include <sys/types.h>
5366 #include <sys/stat.h>
5467 #include <unistd.h>
....@@ -57,6 +70,7 @@
5770 struct report {
5871 struct perf_tool tool;
5972 struct perf_session *session;
73
+ struct evswitch evswitch;
6074 bool use_tui, use_gtk, use_stdio;
6175 bool show_full_info;
6276 bool show_threads;
....@@ -69,6 +83,7 @@
6983 bool header_only;
7084 bool nonany_branch_mode;
7185 bool group_set;
86
+ bool stitch_lbr;
7287 int max_stack;
7388 struct perf_read_values show_threads_values;
7489 struct annotation_options annotation_opts;
....@@ -82,9 +97,14 @@
8297 float min_percent;
8398 u64 nr_entries;
8499 u64 queue_size;
100
+ u64 total_cycles;
85101 int socket_filter;
86102 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
87103 struct branch_type_stat brtype_stat;
104
+ bool symbol_ipc;
105
+ bool total_cycles_mode;
106
+ struct block_report *block_reports;
107
+ int nr_block_reports;
88108 };
89109
90110 static int report__config(const char *var, const char *value, void *cb)
....@@ -124,16 +144,13 @@
124144 int err = 0;
125145 struct report *rep = arg;
126146 struct hist_entry *he = iter->he;
127
- struct perf_evsel *evsel = iter->evsel;
147
+ struct evsel *evsel = iter->evsel;
128148 struct perf_sample *sample = iter->sample;
129149 struct mem_info *mi;
130150 struct branch_info *bi;
131151
132
- if (!ui__has_annotation())
152
+ if (!ui__has_annotation() && !rep->symbol_ipc)
133153 return 0;
134
-
135
- hist__account_cycles(sample->branch_stack, al, sample,
136
- rep->nonany_branch_mode);
137154
138155 if (sort__mode == SORT_MODE__BRANCH) {
139156 bi = he->branch_info;
....@@ -169,49 +186,44 @@
169186 {
170187 struct hist_entry *he = iter->he;
171188 struct report *rep = arg;
172
- struct branch_info *bi;
189
+ struct branch_info *bi = he->branch_info;
173190 struct perf_sample *sample = iter->sample;
174
- struct perf_evsel *evsel = iter->evsel;
191
+ struct evsel *evsel = iter->evsel;
175192 int err;
176193
177
- if (!ui__has_annotation())
194
+ branch_type_count(&rep->brtype_stat, &bi->flags,
195
+ bi->from.addr, bi->to.addr);
196
+
197
+ if (!ui__has_annotation() && !rep->symbol_ipc)
178198 return 0;
179199
180
- hist__account_cycles(sample->branch_stack, al, sample,
181
- rep->nonany_branch_mode);
182
-
183
- bi = he->branch_info;
184200 err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
185201 if (err)
186202 goto out;
187203
188204 err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
189205
190
- branch_type_count(&rep->brtype_stat, &bi->flags,
191
- bi->from.addr, bi->to.addr);
192
-
193206 out:
194207 return err;
195208 }
196209
197210 static void setup_forced_leader(struct report *report,
198
- struct perf_evlist *evlist)
211
+ struct evlist *evlist)
199212 {
200213 if (report->group_set)
201214 perf_evlist__force_leader(evlist);
202215 }
203216
204
-static int process_feature_event(struct perf_tool *tool,
205
- union perf_event *event,
206
- struct perf_session *session __maybe_unused)
217
+static int process_feature_event(struct perf_session *session,
218
+ union perf_event *event)
207219 {
208
- struct report *rep = container_of(tool, struct report, tool);
220
+ struct report *rep = container_of(session->tool, struct report, tool);
209221
210222 if (event->feat.feat_id < HEADER_LAST_FEATURE)
211
- return perf_event__process_feature(tool, event, session);
223
+ return perf_event__process_feature(session, event);
212224
213225 if (event->feat.feat_id != HEADER_LAST_FEATURE) {
214
- pr_err("failed: wrong feature ID: %" PRIu64 "\n",
226
+ pr_err("failed: wrong feature ID: %" PRI_lu64 "\n",
215227 event->feat.feat_id);
216228 return -1;
217229 }
....@@ -228,7 +240,7 @@
228240 static int process_sample_event(struct perf_tool *tool,
229241 union perf_event *event,
230242 struct perf_sample *sample,
231
- struct perf_evsel *evsel,
243
+ struct evsel *evsel,
232244 struct machine *machine)
233245 {
234246 struct report *rep = container_of(tool, struct report, tool);
....@@ -246,11 +258,17 @@
246258 return 0;
247259 }
248260
261
+ if (evswitch__discard(&rep->evswitch, evsel))
262
+ return 0;
263
+
249264 if (machine__resolve(machine, &al, sample) < 0) {
250265 pr_debug("problem processing %d event, skipping it.\n",
251266 event->header.type);
252267 return -1;
253268 }
269
+
270
+ if (rep->stitch_lbr)
271
+ al.thread->lbr_stitch_enable = true;
254272
255273 if (symbol_conf.hide_unresolved && al.sym == NULL)
256274 goto out_put;
....@@ -279,6 +297,12 @@
279297 if (al.map != NULL)
280298 al.map->dso->hit = 1;
281299
300
+ if (ui__has_annotation() || rep->symbol_ipc || rep->total_cycles_mode) {
301
+ hist__account_cycles(sample->branch_stack, &al, sample,
302
+ rep->nonany_branch_mode,
303
+ &rep->total_cycles);
304
+ }
305
+
282306 ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
283307 if (ret < 0)
284308 pr_debug("problem adding hist entry, skipping event\n");
....@@ -290,13 +314,13 @@
290314 static int process_read_event(struct perf_tool *tool,
291315 union perf_event *event,
292316 struct perf_sample *sample __maybe_unused,
293
- struct perf_evsel *evsel,
317
+ struct evsel *evsel,
294318 struct machine *machine __maybe_unused)
295319 {
296320 struct report *rep = container_of(tool, struct report, tool);
297321
298322 if (rep->show_threads) {
299
- const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
323
+ const char *name = evsel__name(evsel);
300324 int err = perf_read_values_add_value(&rep->show_threads_values,
301325 event->read.pid, event->read.tid,
302326 evsel->idx,
....@@ -314,16 +338,19 @@
314338 static int report__setup_sample_type(struct report *rep)
315339 {
316340 struct perf_session *session = rep->session;
317
- u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
341
+ u64 sample_type = evlist__combined_sample_type(session->evlist);
318342 bool is_pipe = perf_data__is_pipe(session->data);
343
+ struct evsel *evsel;
319344
320345 if (session->itrace_synth_opts->callchain ||
346
+ session->itrace_synth_opts->add_callchain ||
321347 (!is_pipe &&
322348 perf_header__has_feat(&session->header, HEADER_AUXTRACE) &&
323349 !session->itrace_synth_opts->set))
324350 sample_type |= PERF_SAMPLE_CALLCHAIN;
325351
326
- if (session->itrace_synth_opts->last_branch)
352
+ if (session->itrace_synth_opts->last_branch ||
353
+ session->itrace_synth_opts->add_last_branch)
327354 sample_type |= PERF_SAMPLE_BRANCH_STACK;
328355
329356 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
....@@ -367,20 +394,37 @@
367394 }
368395 }
369396
370
- if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
371
- if ((sample_type & PERF_SAMPLE_REGS_USER) &&
372
- (sample_type & PERF_SAMPLE_STACK_USER)) {
373
- callchain_param.record_mode = CALLCHAIN_DWARF;
374
- dwarf_callchain_users = true;
375
- } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
376
- callchain_param.record_mode = CALLCHAIN_LBR;
377
- else
378
- callchain_param.record_mode = CALLCHAIN_FP;
397
+ if (sort__mode == SORT_MODE__MEMORY) {
398
+ /*
399
+ * FIXUP: prior to kernel 5.18, Arm SPE missed to set
400
+ * PERF_SAMPLE_DATA_SRC bit in sample type. For backward
401
+ * compatibility, set the bit if it's an old perf data file.
402
+ */
403
+ evlist__for_each_entry(session->evlist, evsel) {
404
+ if (strstr(evsel->name, "arm_spe") &&
405
+ !(sample_type & PERF_SAMPLE_DATA_SRC)) {
406
+ evsel->core.attr.sample_type |= PERF_SAMPLE_DATA_SRC;
407
+ sample_type |= PERF_SAMPLE_DATA_SRC;
408
+ }
409
+ }
410
+
411
+ if (!is_pipe && !(sample_type & PERF_SAMPLE_DATA_SRC)) {
412
+ ui__error("Selected --mem-mode but no mem data. "
413
+ "Did you call perf record without -d?\n");
414
+ return -1;
415
+ }
416
+ }
417
+
418
+ callchain_param_setup(sample_type);
419
+
420
+ if (rep->stitch_lbr && (callchain_param.record_mode != CALLCHAIN_LBR)) {
421
+ ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
422
+ "Please apply --call-graph lbr when recording.\n");
423
+ rep->stitch_lbr = false;
379424 }
380425
381426 /* ??? handle more cases than just ANY? */
382
- if (!(perf_evlist__combined_branch_type(session->evlist) &
383
- PERF_SAMPLE_BRANCH_ANY))
427
+ if (!(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY))
384428 rep->nonany_branch_mode = true;
385429
386430 #if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT)
....@@ -405,7 +449,7 @@
405449 char unit;
406450 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
407451 u64 nr_events = hists->stats.total_period;
408
- struct perf_evsel *evsel = hists_to_evsel(hists);
452
+ struct evsel *evsel = hists_to_evsel(hists);
409453 char buf[512];
410454 size_t size = sizeof(buf);
411455 int socked_id = hists->socket_filter;
....@@ -418,10 +462,10 @@
418462 nr_events = hists->stats.total_non_filtered_period;
419463 }
420464
421
- if (perf_evsel__is_group_event(evsel)) {
422
- struct perf_evsel *pos;
465
+ if (evsel__is_group_event(evsel)) {
466
+ struct evsel *pos;
423467
424
- perf_evsel__group_desc(evsel, buf, size);
468
+ evsel__group_desc(evsel, buf, size);
425469 evname = buf;
426470
427471 for_each_group_member(pos, evsel) {
....@@ -441,7 +485,7 @@
441485 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
442486 if (evname != NULL) {
443487 ret += fprintf(fp, " of event%s '%s'",
444
- evsel->nr_members > 1 ? "s" : "", evname);
488
+ evsel->core.nr_members > 1 ? "s" : "", evname);
445489 }
446490
447491 if (rep->time_str)
....@@ -463,11 +507,30 @@
463507 return ret + fprintf(fp, "\n#\n");
464508 }
465509
466
-static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
510
+static int perf_evlist__tui_block_hists_browse(struct evlist *evlist,
511
+ struct report *rep)
512
+{
513
+ struct evsel *pos;
514
+ int i = 0, ret;
515
+
516
+ evlist__for_each_entry(evlist, pos) {
517
+ ret = report__browse_block_hists(&rep->block_reports[i++].hist,
518
+ rep->min_percent, pos,
519
+ &rep->session->header.env,
520
+ &rep->annotation_opts);
521
+ if (ret != 0)
522
+ return ret;
523
+ }
524
+
525
+ return 0;
526
+}
527
+
528
+static int perf_evlist__tty_browse_hists(struct evlist *evlist,
467529 struct report *rep,
468530 const char *help)
469531 {
470
- struct perf_evsel *pos;
532
+ struct evsel *pos;
533
+ int i = 0;
471534
472535 if (!quiet) {
473536 fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n",
....@@ -476,13 +539,20 @@
476539
477540 evlist__for_each_entry(evlist, pos) {
478541 struct hists *hists = evsel__hists(pos);
479
- const char *evname = perf_evsel__name(pos);
542
+ const char *evname = evsel__name(pos);
480543
481
- if (symbol_conf.event_group &&
482
- !perf_evsel__is_group_leader(pos))
544
+ if (symbol_conf.event_group && !evsel__is_group_leader(pos))
483545 continue;
484546
485547 hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
548
+
549
+ if (rep->total_cycles_mode) {
550
+ report__browse_block_hists(&rep->block_reports[i++].hist,
551
+ rep->min_percent, pos,
552
+ NULL, NULL);
553
+ continue;
554
+ }
555
+
486556 hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout,
487557 !(symbol_conf.use_callchain ||
488558 symbol_conf.show_branchflag_count));
....@@ -536,7 +606,7 @@
536606
537607 static int report__gtk_browse_hists(struct report *rep, const char *help)
538608 {
539
- int (*hist_browser)(struct perf_evlist *evlist, const char *help,
609
+ int (*hist_browser)(struct evlist *evlist, const char *help,
540610 struct hist_browser_timer *timer, float min_pcnt);
541611
542612 hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");
....@@ -553,18 +623,26 @@
553623 {
554624 int ret;
555625 struct perf_session *session = rep->session;
556
- struct perf_evlist *evlist = session->evlist;
557
- const char *help = perf_tip(system_path(TIPDIR));
626
+ struct evlist *evlist = session->evlist;
627
+ char *help = NULL, *path = NULL;
558628
559
- if (help == NULL) {
629
+ path = system_path(TIPDIR);
630
+ if (perf_tip(&help, path) || help == NULL) {
560631 /* fallback for people who don't install perf ;-) */
561
- help = perf_tip(DOCDIR);
562
- if (help == NULL)
563
- help = "Cannot load tips.txt file, please install perf!";
632
+ free(path);
633
+ path = system_path(DOCDIR);
634
+ if (perf_tip(&help, path) || help == NULL)
635
+ help = strdup("Cannot load tips.txt file, please install perf!");
564636 }
637
+ free(path);
565638
566639 switch (use_browser) {
567640 case 1:
641
+ if (rep->total_cycles_mode) {
642
+ ret = perf_evlist__tui_block_hists_browse(evlist, rep);
643
+ break;
644
+ }
645
+
568646 ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
569647 rep->min_percent,
570648 &session->header.env,
....@@ -573,7 +651,7 @@
573651 * Usually "ret" is the last pressed key, and we only
574652 * care if the key notifies us to switch data file.
575653 */
576
- if (ret != K_SWITCH_INPUT_DATA)
654
+ if (ret != K_SWITCH_INPUT_DATA && ret != K_RELOAD)
577655 ret = 0;
578656 break;
579657 case 2:
....@@ -583,14 +661,14 @@
583661 ret = perf_evlist__tty_browse_hists(evlist, rep, help);
584662 break;
585663 }
586
-
664
+ free(help);
587665 return ret;
588666 }
589667
590668 static int report__collapse_hists(struct report *rep)
591669 {
592670 struct ui_progress prog;
593
- struct perf_evsel *pos;
671
+ struct evsel *pos;
594672 int ret = 0;
595673
596674 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
....@@ -608,8 +686,7 @@
608686 break;
609687
610688 /* Non-group events are considered as leader */
611
- if (symbol_conf.event_group &&
612
- !perf_evsel__is_group_leader(pos)) {
689
+ if (symbol_conf.event_group && !evsel__is_group_leader(pos)) {
613690 struct hists *leader_hists = evsel__hists(pos->leader);
614691
615692 hists__match(leader_hists, hists);
....@@ -621,15 +698,31 @@
621698 return ret;
622699 }
623700
701
+static int hists__resort_cb(struct hist_entry *he, void *arg)
702
+{
703
+ struct report *rep = arg;
704
+ struct symbol *sym = he->ms.sym;
705
+
706
+ if (rep->symbol_ipc && sym && !sym->annotate2) {
707
+ struct evsel *evsel = hists_to_evsel(he->hists);
708
+
709
+ symbol__annotate2(&he->ms, evsel,
710
+ &annotation__default_options, NULL);
711
+ }
712
+
713
+ return 0;
714
+}
715
+
624716 static void report__output_resort(struct report *rep)
625717 {
626718 struct ui_progress prog;
627
- struct perf_evsel *pos;
719
+ struct evsel *pos;
628720
629721 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
630722
631
- evlist__for_each_entry(rep->session->evlist, pos)
632
- perf_evsel__output_resort(pos, &prog);
723
+ evlist__for_each_entry(rep->session->evlist, pos) {
724
+ evsel__output_resort_cb(pos, &prog, hists__resort_cb, rep);
725
+ }
633726
634727 ui_progress__finish();
635728 }
....@@ -693,11 +786,9 @@
693786 static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
694787 {
695788 size_t printed = 0;
696
- struct rb_node *nd;
789
+ struct map *map;
697790
698
- for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
699
- struct map *map = rb_entry(nd, struct map, rb_node);
700
-
791
+ maps__for_each_entry(maps, map) {
701792 printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",
702793 indent, "", map->start, map->end,
703794 map->prot & PROT_READ ? 'r' : '-',
....@@ -705,15 +796,10 @@
705796 map->prot & PROT_EXEC ? 'x' : '-',
706797 map->flags & MAP_SHARED ? 's' : 'p',
707798 map->pgoff,
708
- map->ino, map->dso->name);
799
+ map->dso->id.ino, map->dso->name);
709800 }
710801
711802 return printed;
712
-}
713
-
714
-static int map_groups__fprintf_task(struct map_groups *mg, int indent, FILE *fp)
715
-{
716
- return maps__fprintf_task(&mg->maps, indent, fp);
717803 }
718804
719805 static void task__print_level(struct task *task, FILE *fp, int level)
....@@ -726,7 +812,7 @@
726812
727813 fprintf(fp, "%s\n", thread__comm_str(thread));
728814
729
- map_groups__fprintf_task(thread->mg, comm_indent, fp);
815
+ maps__fprintf_task(thread->maps, comm_indent, fp);
730816
731817 if (!list_empty(&task->children)) {
732818 list_for_each_entry(child, &task->children, list)
....@@ -759,7 +845,8 @@
759845 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
760846 struct threads *threads = &machine->threads[i];
761847
762
- for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
848
+ for (nd = rb_first_cached(&threads->entries); nd;
849
+ nd = rb_next(nd)) {
763850 task = tasks + itask++;
764851
765852 task->thread = rb_entry(nd, struct thread, rb_node);
....@@ -804,7 +891,7 @@
804891 {
805892 int ret;
806893 struct perf_session *session = rep->session;
807
- struct perf_evsel *pos;
894
+ struct evsel *pos;
808895 struct perf_data *data = session->data;
809896
810897 signal(SIGINT, sig_handler);
....@@ -886,11 +973,29 @@
886973 rep->nr_entries += evsel__hists(pos)->nr_entries;
887974
888975 if (rep->nr_entries == 0) {
889
- ui__error("The %s file has no samples!\n", data->file.path);
976
+ ui__error("The %s data has no samples!\n", data->path);
890977 return 0;
891978 }
892979
893980 report__output_resort(rep);
981
+
982
+ if (rep->total_cycles_mode) {
983
+ int block_hpps[6] = {
984
+ PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT,
985
+ PERF_HPP_REPORT__BLOCK_LBR_CYCLES,
986
+ PERF_HPP_REPORT__BLOCK_CYCLES_PCT,
987
+ PERF_HPP_REPORT__BLOCK_AVG_CYCLES,
988
+ PERF_HPP_REPORT__BLOCK_RANGE,
989
+ PERF_HPP_REPORT__BLOCK_DSO,
990
+ };
991
+
992
+ rep->block_reports = block_info__create_report(session->evlist,
993
+ rep->total_cycles,
994
+ block_hpps, 6,
995
+ &rep->nr_block_reports);
996
+ if (!rep->block_reports)
997
+ return -1;
998
+ }
894999
8951000 return report__browse_hists(rep);
8961001 }
....@@ -911,6 +1016,42 @@
9111016 }
9121017
9131018 return parse_callchain_report_opt(arg);
1019
+}
1020
+
1021
+static int
1022
+parse_time_quantum(const struct option *opt, const char *arg,
1023
+ int unset __maybe_unused)
1024
+{
1025
+ unsigned long *time_q = opt->value;
1026
+ char *end;
1027
+
1028
+ *time_q = strtoul(arg, &end, 0);
1029
+ if (end == arg)
1030
+ goto parse_err;
1031
+ if (*time_q == 0) {
1032
+ pr_err("time quantum cannot be 0");
1033
+ return -1;
1034
+ }
1035
+ end = skip_spaces(end);
1036
+ if (*end == 0)
1037
+ return 0;
1038
+ if (!strcmp(end, "s")) {
1039
+ *time_q *= NSEC_PER_SEC;
1040
+ return 0;
1041
+ }
1042
+ if (!strcmp(end, "ms")) {
1043
+ *time_q *= NSEC_PER_MSEC;
1044
+ return 0;
1045
+ }
1046
+ if (!strcmp(end, "us")) {
1047
+ *time_q *= NSEC_PER_USEC;
1048
+ return 0;
1049
+ }
1050
+ if (!strcmp(end, "ns"))
1051
+ return 0;
1052
+parse_err:
1053
+ pr_err("Cannot parse time quantum `%s'\n", arg);
1054
+ return -1;
9141055 }
9151056
9161057 int
....@@ -953,6 +1094,26 @@
9531094 return 0;
9541095 }
9551096
1097
+static int process_attr(struct perf_tool *tool __maybe_unused,
1098
+ union perf_event *event,
1099
+ struct evlist **pevlist)
1100
+{
1101
+ u64 sample_type;
1102
+ int err;
1103
+
1104
+ err = perf_event__process_attr(tool, event, pevlist);
1105
+ if (err)
1106
+ return err;
1107
+
1108
+ /*
1109
+ * Check if we need to enable callchains based
1110
+ * on events sample_type.
1111
+ */
1112
+ sample_type = evlist__combined_sample_type(*pevlist);
1113
+ callchain_param_setup(sample_type);
1114
+ return 0;
1115
+}
1116
+
9561117 int cmd_report(int argc, const char **argv)
9571118 {
9581119 struct perf_session *session;
....@@ -963,9 +1124,9 @@
9631124 int last_key = 0;
9641125 bool branch_call_mode = false;
9651126 #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
966
- const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
967
- CALLCHAIN_REPORT_HELP
968
- "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
1127
+ static const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
1128
+ CALLCHAIN_REPORT_HELP
1129
+ "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
9691130 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
9701131 const char * const report_usage[] = {
9711132 "perf report [<options>]",
....@@ -978,11 +1139,12 @@
9781139 .mmap2 = perf_event__process_mmap2,
9791140 .comm = perf_event__process_comm,
9801141 .namespaces = perf_event__process_namespaces,
1142
+ .cgroup = perf_event__process_cgroup,
9811143 .exit = perf_event__process_exit,
9821144 .fork = perf_event__process_fork,
9831145 .lost = perf_event__process_lost,
9841146 .read = process_read_event,
985
- .attr = perf_event__process_attr,
1147
+ .attr = process_attr,
9861148 .tracing_data = perf_event__process_tracing_data,
9871149 .build_id = perf_event__process_build_id,
9881150 .id_index = perf_event__process_id_index,
....@@ -998,6 +1160,8 @@
9981160 .socket_filter = -1,
9991161 .annotation_opts = annotation__default_options,
10001162 };
1163
+ char *sort_order_help = sort_help("sort by key(s):");
1164
+ char *field_order_help = sort_help("output field(s): overhead period sample ");
10011165 const struct option options[] = {
10021166 OPT_STRING('i', "input", &input_name, "file",
10031167 "input file name"),
....@@ -1032,10 +1196,9 @@
10321196 OPT_BOOLEAN(0, "header-only", &report.header_only,
10331197 "Show only data header."),
10341198 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1035
- "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1036
- " Please refer the man page for the complete list."),
1199
+ sort_order_help),
10371200 OPT_STRING('F', "fields", &field_order, "key[,keys...]",
1038
- "output field(s): overhead, period, sample plus all of sort keys"),
1201
+ field_order_help),
10391202 OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
10401203 "Show sample percentage for different cpu modes"),
10411204 OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
....@@ -1049,7 +1212,8 @@
10491212 report_callchain_help, &report_parse_callchain_opt,
10501213 callchain_default_opt),
10511214 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
1052
- "Accumulate callchains of children and show total overhead as well"),
1215
+ "Accumulate callchains of children and show total overhead as well. "
1216
+ "Enabled by default, use --no-children to disable."),
10531217 OPT_INTEGER(0, "max-stack", &report.max_stack,
10541218 "Set the maximum stack depth when parsing the callchain, "
10551219 "anything beyond the specified depth will be ignored. "
....@@ -1092,10 +1256,18 @@
10921256 "Display raw encoding of assembly instructions (default)"),
10931257 OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style",
10941258 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1259
+ OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix",
1260
+ "Add prefix to source file path names in programs (with --prefix-strip)"),
1261
+ OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N",
1262
+ "Strip first N entries of source file path name in programs (with --prefix)"),
10951263 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
10961264 "Show a column with the sum of periods"),
10971265 OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set,
10981266 "Show event group information together"),
1267
+ OPT_INTEGER(0, "group-sort-idx", &symbol_conf.group_sort_idx,
1268
+ "Sort the output by the event at the index n in group. "
1269
+ "If n is invalid, sort by the first event. "
1270
+ "WARNING: should be used on grouped events."),
10991271 OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
11001272 "use branch records for per branch histogram filling",
11011273 parse_branch_mode),
....@@ -1108,17 +1280,21 @@
11081280 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
11091281 "Enable kernel symbol demangling"),
11101282 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
1283
+ OPT_INTEGER(0, "samples", &symbol_conf.res_sample,
1284
+ "Number of samples to save per histogram entry for individual browsing"),
11111285 OPT_CALLBACK(0, "percent-limit", &report, "percent",
11121286 "Don't show entries under that percent", parse_percent_limit),
11131287 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
11141288 "how to display percentage of filtered entries", parse_filter_percentage),
11151289 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
1116
- "Instruction Tracing options",
1290
+ "Instruction Tracing options\n" ITRACE_HELP,
11171291 itrace_parse_synth_opts),
11181292 OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
11191293 "Show full source file name path for source lines"),
11201294 OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
11211295 "Show callgraph from reference event"),
1296
+ OPT_BOOLEAN(0, "stitch-lbr", &report.stitch_lbr,
1297
+ "Enable LBR callgraph stitching approach"),
11221298 OPT_INTEGER(0, "socket-filter", &report.socket_filter,
11231299 "only show processor socket that match with this filter"),
11241300 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
....@@ -1135,19 +1311,27 @@
11351311 OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period",
11361312 "Set percent type local/global-period/hits",
11371313 annotate_parse_percent_type),
1314
+ OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"),
1315
+ OPT_CALLBACK(0, "time-quantum", &symbol_conf.time_quantum, "time (ms|us|ns|s)",
1316
+ "Set time quantum for time sort key (default 100ms)",
1317
+ parse_time_quantum),
1318
+ OPTS_EVSWITCH(&report.evswitch),
1319
+ OPT_BOOLEAN(0, "total-cycles", &report.total_cycles_mode,
1320
+ "Sort all blocks by 'Sampled Cycles%'"),
11381321 OPT_END()
11391322 };
11401323 struct perf_data data = {
11411324 .mode = PERF_DATA_MODE_READ,
11421325 };
11431326 int ret = hists__init();
1327
+ char sort_tmp[128];
11441328
11451329 if (ret < 0)
1146
- return ret;
1330
+ goto exit;
11471331
11481332 ret = perf_config(report__config, &report);
11491333 if (ret)
1150
- return ret;
1334
+ goto exit;
11511335
11521336 argc = parse_options(argc, argv, options, report_usage, 0);
11531337 if (argc) {
....@@ -1161,8 +1345,16 @@
11611345 report.symbol_filter_str = argv[0];
11621346 }
11631347
1348
+ if (annotate_check_args(&report.annotation_opts) < 0) {
1349
+ ret = -EINVAL;
1350
+ goto exit;
1351
+ }
1352
+
11641353 if (report.mmaps_mode)
11651354 report.tasks_mode = true;
1355
+
1356
+ if (dump_trace)
1357
+ report.tool.ordered_events = false;
11661358
11671359 if (quiet)
11681360 perf_quiet_option();
....@@ -1170,12 +1362,14 @@
11701362 if (symbol_conf.vmlinux_name &&
11711363 access(symbol_conf.vmlinux_name, R_OK)) {
11721364 pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
1173
- return -EINVAL;
1365
+ ret = -EINVAL;
1366
+ goto exit;
11741367 }
11751368 if (symbol_conf.kallsyms_name &&
11761369 access(symbol_conf.kallsyms_name, R_OK)) {
11771370 pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
1178
- return -EINVAL;
1371
+ ret = -EINVAL;
1372
+ goto exit;
11791373 }
11801374
11811375 if (report.inverted_callchain)
....@@ -1183,7 +1377,7 @@
11831377 if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
11841378 callchain_param.order = ORDER_CALLER;
11851379
1186
- if (itrace_synth_opts.callchain &&
1380
+ if ((itrace_synth_opts.callchain || itrace_synth_opts.add_callchain) &&
11871381 (int)itrace_synth_opts.callchain_sz > report.max_stack)
11881382 report.max_stack = itrace_synth_opts.callchain_sz;
11891383
....@@ -1194,13 +1388,22 @@
11941388 input_name = "perf.data";
11951389 }
11961390
1197
- data.file.path = input_name;
1198
- data.force = symbol_conf.force;
1391
+ data.path = input_name;
1392
+ data.force = symbol_conf.force;
11991393
12001394 repeat:
12011395 session = perf_session__new(&data, false, &report.tool);
1202
- if (session == NULL)
1203
- return -1;
1396
+ if (IS_ERR(session)) {
1397
+ ret = PTR_ERR(session);
1398
+ goto exit;
1399
+ }
1400
+
1401
+ ret = evswitch__init(&report.evswitch, session->evlist, stderr);
1402
+ if (ret)
1403
+ goto exit;
1404
+
1405
+ if (zstd_init(&(session->zstd_data), 0) < 0)
1406
+ pr_warning("Decompression initialization failed. Reported data may be incomplete.\n");
12041407
12051408 if (report.queue_size) {
12061409 ordered_events__set_alloc_size(&session->ordered_events,
....@@ -1213,10 +1416,18 @@
12131416
12141417 has_br_stack = perf_header__has_feat(&session->header,
12151418 HEADER_BRANCH_STACK);
1419
+ if (evlist__combined_sample_type(session->evlist) & PERF_SAMPLE_STACK_USER)
1420
+ has_br_stack = false;
12161421
12171422 setup_forced_leader(&report, session->evlist);
12181423
1219
- if (itrace_synth_opts.last_branch)
1424
+ if (symbol_conf.group_sort_idx && !session->evlist->nr_groups) {
1425
+ parse_options_usage(NULL, options, "group-sort-idx", 0);
1426
+ ret = -EINVAL;
1427
+ goto error;
1428
+ }
1429
+
1430
+ if (itrace_synth_opts.last_branch || itrace_synth_opts.add_last_branch)
12201431 has_br_stack = true;
12211432
12221433 if (has_br_stack && branch_call_mode)
....@@ -1236,7 +1447,7 @@
12361447 }
12371448 if (branch_call_mode) {
12381449 callchain_param.key = CCKEY_ADDRESS;
1239
- callchain_param.branch_callstack = 1;
1450
+ callchain_param.branch_callstack = true;
12401451 symbol_conf.use_callchain = true;
12411452 callchain_register_param(&callchain_param);
12421453 if (sort_order == NULL)
....@@ -1287,12 +1498,37 @@
12871498 goto error;
12881499 }
12891500
1501
+ if (report.total_cycles_mode) {
1502
+ if (sort__mode != SORT_MODE__BRANCH)
1503
+ report.total_cycles_mode = false;
1504
+ else
1505
+ sort_order = NULL;
1506
+ }
1507
+
12901508 if (strcmp(input_name, "-") != 0)
12911509 setup_browser(true);
12921510 else
12931511 use_browser = 0;
12941512
1295
- if ((last_key != K_SWITCH_INPUT_DATA) &&
1513
+ if (sort_order && strstr(sort_order, "ipc")) {
1514
+ parse_options_usage(report_usage, options, "s", 1);
1515
+ goto error;
1516
+ }
1517
+
1518
+ if (sort_order && strstr(sort_order, "symbol")) {
1519
+ if (sort__mode == SORT_MODE__BRANCH) {
1520
+ snprintf(sort_tmp, sizeof(sort_tmp), "%s,%s",
1521
+ sort_order, "ipc_lbr");
1522
+ report.symbol_ipc = true;
1523
+ } else {
1524
+ snprintf(sort_tmp, sizeof(sort_tmp), "%s,%s",
1525
+ sort_order, "ipc_null");
1526
+ }
1527
+
1528
+ sort_order = sort_tmp;
1529
+ }
1530
+
1531
+ if ((last_key != K_SWITCH_INPUT_DATA && last_key != K_RELOAD) &&
12961532 (setup_sorting(session->evlist) < 0)) {
12971533 if (sort_order)
12981534 parse_options_usage(report_usage, options, "s", 1);
....@@ -1320,7 +1556,8 @@
13201556 * so don't allocate extra space that won't be used in the stdio
13211557 * implementation.
13221558 */
1323
- if (ui__has_annotation()) {
1559
+ if (ui__has_annotation() || report.symbol_ipc ||
1560
+ report.total_cycles_mode) {
13241561 ret = symbol__annotation_init();
13251562 if (ret < 0)
13261563 goto error;
....@@ -1339,42 +1576,23 @@
13391576 symbol_conf.priv_size += sizeof(u32);
13401577 symbol_conf.sort_by_name = true;
13411578 }
1342
- annotation_config__init();
1579
+ annotation_config__init(&report.annotation_opts);
13431580 }
13441581
13451582 if (symbol__init(&session->header.env) < 0)
13461583 goto error;
13471584
1348
- report.ptime_range = perf_time__range_alloc(report.time_str,
1349
- &report.range_size);
1350
- if (!report.ptime_range) {
1351
- ret = -ENOMEM;
1352
- goto error;
1353
- }
1354
-
1355
- if (perf_time__parse_str(report.ptime_range, report.time_str) != 0) {
1356
- if (session->evlist->first_sample_time == 0 &&
1357
- session->evlist->last_sample_time == 0) {
1358
- pr_err("HINT: no first/last sample time found in perf data.\n"
1359
- "Please use latest perf binary to execute 'perf record'\n"
1360
- "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
1361
- ret = -EINVAL;
1585
+ if (report.time_str) {
1586
+ ret = perf_time__parse_for_ranges(report.time_str, session,
1587
+ &report.ptime_range,
1588
+ &report.range_size,
1589
+ &report.range_num);
1590
+ if (ret < 0)
13621591 goto error;
1363
- }
13641592
1365
- report.range_num = perf_time__percent_parse_str(
1366
- report.ptime_range, report.range_size,
1367
- report.time_str,
1368
- session->evlist->first_sample_time,
1369
- session->evlist->last_sample_time);
1370
-
1371
- if (report.range_num < 0) {
1372
- pr_err("Invalid time string\n");
1373
- ret = -EINVAL;
1374
- goto error;
1375
- }
1376
- } else {
1377
- report.range_num = 1;
1593
+ itrace_synth_opts__set_time_range(&itrace_synth_opts,
1594
+ report.ptime_range,
1595
+ report.range_num);
13781596 }
13791597
13801598 if (session->tevent.pevent &&
....@@ -1389,7 +1607,7 @@
13891607 sort__setup_elide(stdout);
13901608
13911609 ret = __cmd_report(&report);
1392
- if (ret == K_SWITCH_INPUT_DATA) {
1610
+ if (ret == K_SWITCH_INPUT_DATA || ret == K_RELOAD) {
13931611 perf_session__delete(session);
13941612 last_key = K_SWITCH_INPUT_DATA;
13951613 goto repeat;
....@@ -1397,8 +1615,21 @@
13971615 ret = 0;
13981616
13991617 error:
1400
- zfree(&report.ptime_range);
1618
+ if (report.ptime_range) {
1619
+ itrace_synth_opts__clear_time_range(&itrace_synth_opts);
1620
+ zfree(&report.ptime_range);
1621
+ }
14011622
1623
+ if (report.block_reports) {
1624
+ block_info__free_report(report.block_reports,
1625
+ report.nr_block_reports);
1626
+ report.block_reports = NULL;
1627
+ }
1628
+
1629
+ zstd_fini(&(session->zstd_data));
14021630 perf_session__delete(session);
1631
+exit:
1632
+ free(sort_order_help);
1633
+ free(field_order_help);
14031634 return ret;
14041635 }