diff options
| -rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-data.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-stat.c | 30 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/annotate.c | 36 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 11 | ||||
| -rw-r--r-- | tools/perf/util/counts.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/data-convert-bt.c | 127 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 5 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 139 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/sort.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/stat.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/stat.h | 5 |
13 files changed, 334 insertions, 32 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6db782dfce96..658c920d74b9 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -177,8 +177,6 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
| 177 | */ | 177 | */ |
| 178 | process_branch_stack(sample->branch_stack, al, sample); | 178 | process_branch_stack(sample->branch_stack, al, sample); |
| 179 | 179 | ||
| 180 | sample->weight = 1; | ||
| 181 | |||
| 182 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | 180 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); |
| 183 | if (he == NULL) | 181 | if (he == NULL) |
| 184 | return -ENOMEM; | 182 | return -ENOMEM; |
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index 0adb5f82335a..46cd8490baf4 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c | |||
| @@ -69,7 +69,7 @@ static int cmd_data_convert(int argc, const char **argv) | |||
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | #ifndef HAVE_LIBBABELTRACE_SUPPORT | 71 | #ifndef HAVE_LIBBABELTRACE_SUPPORT |
| 72 | pr_err("No conversion support compiled in.\n"); | 72 | pr_err("No conversion support compiled in. perf should be compiled with environment variables LIBBABELTRACE=1 and LIBBABELTRACE_DIR=/path/to/libbabeltrace/\n"); |
| 73 | return -1; | 73 | return -1; |
| 74 | #endif | 74 | #endif |
| 75 | 75 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 48ac53b199fc..866da7aa54bf 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -213,10 +213,20 @@ static void perf_stat__reset_stats(void) | |||
| 213 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 213 | static int create_perf_stat_counter(struct perf_evsel *evsel) |
| 214 | { | 214 | { |
| 215 | struct perf_event_attr *attr = &evsel->attr; | 215 | struct perf_event_attr *attr = &evsel->attr; |
| 216 | struct perf_evsel *leader = evsel->leader; | ||
| 216 | 217 | ||
| 217 | if (stat_config.scale) | 218 | if (stat_config.scale) { |
| 218 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 219 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
| 219 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 220 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * The event is part of non trivial group, let's enable | ||
| 225 | * the group read (for leader) and ID retrieval for all | ||
| 226 | * members. | ||
| 227 | */ | ||
| 228 | if (leader->nr_members > 1) | ||
| 229 | attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP; | ||
| 220 | 230 | ||
| 221 | attr->inherit = !no_inherit; | 231 | attr->inherit = !no_inherit; |
| 222 | 232 | ||
| @@ -333,13 +343,21 @@ static int read_counter(struct perf_evsel *counter) | |||
| 333 | struct perf_counts_values *count; | 343 | struct perf_counts_values *count; |
| 334 | 344 | ||
| 335 | count = perf_counts(counter->counts, cpu, thread); | 345 | count = perf_counts(counter->counts, cpu, thread); |
| 336 | if (perf_evsel__read(counter, cpu, thread, count)) { | 346 | |
| 347 | /* | ||
| 348 | * The leader's group read loads data into its group members | ||
| 349 | * (via perf_evsel__read_counter) and sets threir count->loaded. | ||
| 350 | */ | ||
| 351 | if (!count->loaded && | ||
| 352 | perf_evsel__read_counter(counter, cpu, thread)) { | ||
| 337 | counter->counts->scaled = -1; | 353 | counter->counts->scaled = -1; |
| 338 | perf_counts(counter->counts, cpu, thread)->ena = 0; | 354 | perf_counts(counter->counts, cpu, thread)->ena = 0; |
| 339 | perf_counts(counter->counts, cpu, thread)->run = 0; | 355 | perf_counts(counter->counts, cpu, thread)->run = 0; |
| 340 | return -1; | 356 | return -1; |
| 341 | } | 357 | } |
| 342 | 358 | ||
| 359 | count->loaded = false; | ||
| 360 | |||
| 343 | if (STAT_RECORD) { | 361 | if (STAT_RECORD) { |
| 344 | if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { | 362 | if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { |
| 345 | pr_err("failed to write stat event\n"); | 363 | pr_err("failed to write stat event\n"); |
| @@ -559,6 +577,11 @@ static int store_counter_ids(struct perf_evsel *counter) | |||
| 559 | return __store_counter_ids(counter, cpus, threads); | 577 | return __store_counter_ids(counter, cpus, threads); |
| 560 | } | 578 | } |
| 561 | 579 | ||
| 580 | static bool perf_evsel__should_store_id(struct perf_evsel *counter) | ||
| 581 | { | ||
| 582 | return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; | ||
| 583 | } | ||
| 584 | |||
| 562 | static int __run_perf_stat(int argc, const char **argv) | 585 | static int __run_perf_stat(int argc, const char **argv) |
| 563 | { | 586 | { |
| 564 | int interval = stat_config.interval; | 587 | int interval = stat_config.interval; |
| @@ -631,7 +654,8 @@ try_again: | |||
| 631 | if (l > unit_width) | 654 | if (l > unit_width) |
| 632 | unit_width = l; | 655 | unit_width = l; |
| 633 | 656 | ||
| 634 | if (STAT_RECORD && store_counter_ids(counter)) | 657 | if (perf_evsel__should_store_id(counter) && |
| 658 | store_counter_ids(counter)) | ||
| 635 | return -1; | 659 | return -1; |
| 636 | } | 660 | } |
| 637 | 661 | ||
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index dbe4e630b90f..80f38dab9c3a 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
| @@ -17,8 +17,8 @@ | |||
| 17 | #include <sys/ttydefaults.h> | 17 | #include <sys/ttydefaults.h> |
| 18 | 18 | ||
| 19 | struct disasm_line_samples { | 19 | struct disasm_line_samples { |
| 20 | double percent; | 20 | double percent; |
| 21 | u64 nr; | 21 | struct sym_hist_entry he; |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | #define IPC_WIDTH 6 | 24 | #define IPC_WIDTH 6 |
| @@ -110,11 +110,12 @@ static int annotate_browser__set_jumps_percent_color(struct annotate_browser *br | |||
| 110 | 110 | ||
| 111 | static int annotate_browser__pcnt_width(struct annotate_browser *ab) | 111 | static int annotate_browser__pcnt_width(struct annotate_browser *ab) |
| 112 | { | 112 | { |
| 113 | int w = 7 * ab->nr_events; | 113 | return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; |
| 114 | } | ||
| 114 | 115 | ||
| 115 | if (ab->have_cycles) | 116 | static int annotate_browser__cycles_width(struct annotate_browser *ab) |
| 116 | w += IPC_WIDTH + CYCLES_WIDTH; | 117 | { |
| 117 | return w; | 118 | return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0; |
| 118 | } | 119 | } |
| 119 | 120 | ||
| 120 | static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) | 121 | static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) |
| @@ -127,7 +128,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 127 | (!current_entry || (browser->use_navkeypressed && | 128 | (!current_entry || (browser->use_navkeypressed && |
| 128 | !browser->navkeypressed))); | 129 | !browser->navkeypressed))); |
| 129 | int width = browser->width, printed; | 130 | int width = browser->width, printed; |
| 130 | int i, pcnt_width = annotate_browser__pcnt_width(ab); | 131 | int i, pcnt_width = annotate_browser__pcnt_width(ab), |
| 132 | cycles_width = annotate_browser__cycles_width(ab); | ||
| 131 | double percent_max = 0.0; | 133 | double percent_max = 0.0; |
| 132 | char bf[256]; | 134 | char bf[256]; |
| 133 | bool show_title = false; | 135 | bool show_title = false; |
| @@ -151,8 +153,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 151 | bdl->samples[i].percent, | 153 | bdl->samples[i].percent, |
| 152 | current_entry); | 154 | current_entry); |
| 153 | if (annotate_browser__opts.show_total_period) { | 155 | if (annotate_browser__opts.show_total_period) { |
| 154 | ui_browser__printf(browser, "%6" PRIu64 " ", | 156 | ui_browser__printf(browser, "%11" PRIu64 " ", |
| 155 | bdl->samples[i].nr); | 157 | bdl->samples[i].he.period); |
| 156 | } else { | 158 | } else { |
| 157 | ui_browser__printf(browser, "%6.2f ", | 159 | ui_browser__printf(browser, "%6.2f ", |
| 158 | bdl->samples[i].percent); | 160 | bdl->samples[i].percent); |
| @@ -162,9 +164,11 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 162 | ui_browser__set_percent_color(browser, 0, current_entry); | 164 | ui_browser__set_percent_color(browser, 0, current_entry); |
| 163 | 165 | ||
| 164 | if (!show_title) | 166 | if (!show_title) |
| 165 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | 167 | ui_browser__write_nstring(browser, " ", pcnt_width); |
| 166 | else | 168 | else { |
| 167 | ui_browser__printf(browser, "%*s", 7, "Percent"); | 169 | ui_browser__printf(browser, "%*s", pcnt_width, |
| 170 | annotate_browser__opts.show_total_period ? "Period" : "Percent"); | ||
| 171 | } | ||
| 168 | } | 172 | } |
| 169 | if (ab->have_cycles) { | 173 | if (ab->have_cycles) { |
| 170 | if (dl->ipc) | 174 | if (dl->ipc) |
| @@ -190,7 +194,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 190 | width += 1; | 194 | width += 1; |
| 191 | 195 | ||
| 192 | if (!*dl->line) | 196 | if (!*dl->line) |
| 193 | ui_browser__write_nstring(browser, " ", width - pcnt_width); | 197 | ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); |
| 194 | else if (dl->offset == -1) { | 198 | else if (dl->offset == -1) { |
| 195 | if (dl->line_nr && annotate_browser__opts.show_linenr) | 199 | if (dl->line_nr && annotate_browser__opts.show_linenr) |
| 196 | printed = scnprintf(bf, sizeof(bf), "%-*d ", | 200 | printed = scnprintf(bf, sizeof(bf), "%-*d ", |
| @@ -199,7 +203,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 199 | printed = scnprintf(bf, sizeof(bf), "%*s ", | 203 | printed = scnprintf(bf, sizeof(bf), "%*s ", |
| 200 | ab->addr_width, " "); | 204 | ab->addr_width, " "); |
| 201 | ui_browser__write_nstring(browser, bf, printed); | 205 | ui_browser__write_nstring(browser, bf, printed); |
| 202 | ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1); | 206 | ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1); |
| 203 | } else { | 207 | } else { |
| 204 | u64 addr = dl->offset; | 208 | u64 addr = dl->offset; |
| 205 | int color = -1; | 209 | int color = -1; |
| @@ -256,7 +260,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); | 262 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); |
| 259 | ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed); | 263 | ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed); |
| 260 | } | 264 | } |
| 261 | 265 | ||
| 262 | if (current_entry) | 266 | if (current_entry) |
| @@ -457,7 +461,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
| 457 | pos->offset, | 461 | pos->offset, |
| 458 | next ? next->offset : len, | 462 | next ? next->offset : len, |
| 459 | &path, &sample); | 463 | &path, &sample); |
| 460 | bpos->samples[i].nr = sample.nr_samples; | 464 | bpos->samples[i].he = sample; |
| 461 | 465 | ||
| 462 | if (max_percent < bpos->samples[i].percent) | 466 | if (max_percent < bpos->samples[i].percent) |
| 463 | max_percent = bpos->samples[i].percent; | 467 | max_percent = bpos->samples[i].percent; |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c2b4b00166ed..2dab0e5a7f2f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -963,8 +963,9 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | |||
| 963 | u64 period = 0; | 963 | u64 period = 0; |
| 964 | 964 | ||
| 965 | while (offset < end) { | 965 | while (offset < end) { |
| 966 | hits += h->addr[offset++].nr_samples; | 966 | hits += h->addr[offset].nr_samples; |
| 967 | period += h->addr[offset++].period; | 967 | period += h->addr[offset].period; |
| 968 | ++offset; | ||
| 968 | } | 969 | } |
| 969 | 970 | ||
| 970 | if (h->nr_samples) { | 971 | if (h->nr_samples) { |
| @@ -1142,7 +1143,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
| 1142 | color = get_percent_color(percent); | 1143 | color = get_percent_color(percent); |
| 1143 | 1144 | ||
| 1144 | if (symbol_conf.show_total_period) | 1145 | if (symbol_conf.show_total_period) |
| 1145 | color_fprintf(stdout, color, " %7" PRIu64, | 1146 | color_fprintf(stdout, color, " %11" PRIu64, |
| 1146 | sample.period); | 1147 | sample.period); |
| 1147 | else | 1148 | else |
| 1148 | color_fprintf(stdout, color, " %7.2f", percent); | 1149 | color_fprintf(stdout, color, " %7.2f", percent); |
| @@ -1165,7 +1166,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
| 1165 | } else if (max_lines && printed >= max_lines) | 1166 | } else if (max_lines && printed >= max_lines) |
| 1166 | return 1; | 1167 | return 1; |
| 1167 | else { | 1168 | else { |
| 1168 | int width = 8; | 1169 | int width = symbol_conf.show_total_period ? 12 : 8; |
| 1169 | 1170 | ||
| 1170 | if (queue) | 1171 | if (queue) |
| 1171 | return -1; | 1172 | return -1; |
| @@ -1806,7 +1807,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 1806 | int printed = 2, queue_len = 0; | 1807 | int printed = 2, queue_len = 0; |
| 1807 | int more = 0; | 1808 | int more = 0; |
| 1808 | u64 len; | 1809 | u64 len; |
| 1809 | int width = 8; | 1810 | int width = symbol_conf.show_total_period ? 12 : 8; |
| 1810 | int graph_dotted_len; | 1811 | int graph_dotted_len; |
| 1811 | 1812 | ||
| 1812 | filename = strdup(dso->long_name); | 1813 | filename = strdup(dso->long_name); |
diff --git a/tools/perf/util/counts.h b/tools/perf/util/counts.h index 34d8baaf558a..cb45a6aecf9d 100644 --- a/tools/perf/util/counts.h +++ b/tools/perf/util/counts.h | |||
| @@ -12,6 +12,7 @@ struct perf_counts_values { | |||
| 12 | }; | 12 | }; |
| 13 | u64 values[3]; | 13 | u64 values[3]; |
| 14 | }; | 14 | }; |
| 15 | bool loaded; | ||
| 15 | }; | 16 | }; |
| 16 | 17 | ||
| 17 | struct perf_counts { | 18 | struct perf_counts { |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 3149b70799fd..2346cecb8ea2 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
| @@ -76,6 +76,8 @@ struct ctf_writer { | |||
| 76 | struct bt_ctf_event_class *comm_class; | 76 | struct bt_ctf_event_class *comm_class; |
| 77 | struct bt_ctf_event_class *exit_class; | 77 | struct bt_ctf_event_class *exit_class; |
| 78 | struct bt_ctf_event_class *fork_class; | 78 | struct bt_ctf_event_class *fork_class; |
| 79 | struct bt_ctf_event_class *mmap_class; | ||
| 80 | struct bt_ctf_event_class *mmap2_class; | ||
| 79 | }; | 81 | }; |
| 80 | 82 | ||
| 81 | struct convert { | 83 | struct convert { |
| @@ -506,6 +508,81 @@ put_len_type: | |||
| 506 | return ret; | 508 | return ret; |
| 507 | } | 509 | } |
| 508 | 510 | ||
| 511 | static int | ||
| 512 | add_callchain_output_values(struct bt_ctf_event_class *event_class, | ||
| 513 | struct bt_ctf_event *event, | ||
| 514 | struct ip_callchain *callchain) | ||
| 515 | { | ||
| 516 | struct bt_ctf_field_type *len_type, *seq_type; | ||
| 517 | struct bt_ctf_field *len_field, *seq_field; | ||
| 518 | unsigned int nr_elements = callchain->nr; | ||
| 519 | unsigned int i; | ||
| 520 | int ret; | ||
| 521 | |||
| 522 | len_type = bt_ctf_event_class_get_field_by_name( | ||
| 523 | event_class, "perf_callchain_size"); | ||
| 524 | len_field = bt_ctf_field_create(len_type); | ||
| 525 | if (!len_field) { | ||
| 526 | pr_err("failed to create 'perf_callchain_size' for callchain output event\n"); | ||
| 527 | ret = -1; | ||
| 528 | goto put_len_type; | ||
| 529 | } | ||
| 530 | |||
| 531 | ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements); | ||
| 532 | if (ret) { | ||
| 533 | pr_err("failed to set field value for perf_callchain_size\n"); | ||
| 534 | goto put_len_field; | ||
| 535 | } | ||
| 536 | ret = bt_ctf_event_set_payload(event, "perf_callchain_size", len_field); | ||
| 537 | if (ret) { | ||
| 538 | pr_err("failed to set payload to perf_callchain_size\n"); | ||
| 539 | goto put_len_field; | ||
| 540 | } | ||
| 541 | |||
| 542 | seq_type = bt_ctf_event_class_get_field_by_name( | ||
| 543 | event_class, "perf_callchain"); | ||
| 544 | seq_field = bt_ctf_field_create(seq_type); | ||
| 545 | if (!seq_field) { | ||
| 546 | pr_err("failed to create 'perf_callchain' for callchain output event\n"); | ||
| 547 | ret = -1; | ||
| 548 | goto put_seq_type; | ||
| 549 | } | ||
| 550 | |||
| 551 | ret = bt_ctf_field_sequence_set_length(seq_field, len_field); | ||
| 552 | if (ret) { | ||
| 553 | pr_err("failed to set length of 'perf_callchain'\n"); | ||
| 554 | goto put_seq_field; | ||
| 555 | } | ||
| 556 | |||
| 557 | for (i = 0; i < nr_elements; i++) { | ||
| 558 | struct bt_ctf_field *elem_field = | ||
| 559 | bt_ctf_field_sequence_get_field(seq_field, i); | ||
| 560 | |||
| 561 | ret = bt_ctf_field_unsigned_integer_set_value(elem_field, | ||
| 562 | ((u64 *)(callchain->ips))[i]); | ||
| 563 | |||
| 564 | bt_ctf_field_put(elem_field); | ||
| 565 | if (ret) { | ||
| 566 | pr_err("failed to set callchain[%d]\n", i); | ||
| 567 | goto put_seq_field; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | ret = bt_ctf_event_set_payload(event, "perf_callchain", seq_field); | ||
| 572 | if (ret) | ||
| 573 | pr_err("failed to set payload for raw_data\n"); | ||
| 574 | |||
| 575 | put_seq_field: | ||
| 576 | bt_ctf_field_put(seq_field); | ||
| 577 | put_seq_type: | ||
| 578 | bt_ctf_field_type_put(seq_type); | ||
| 579 | put_len_field: | ||
| 580 | bt_ctf_field_put(len_field); | ||
| 581 | put_len_type: | ||
| 582 | bt_ctf_field_type_put(len_type); | ||
| 583 | return ret; | ||
| 584 | } | ||
| 585 | |||
| 509 | static int add_generic_values(struct ctf_writer *cw, | 586 | static int add_generic_values(struct ctf_writer *cw, |
| 510 | struct bt_ctf_event *event, | 587 | struct bt_ctf_event *event, |
| 511 | struct perf_evsel *evsel, | 588 | struct perf_evsel *evsel, |
| @@ -519,7 +596,6 @@ static int add_generic_values(struct ctf_writer *cw, | |||
| 519 | * PERF_SAMPLE_TIME - not needed as we have it in | 596 | * PERF_SAMPLE_TIME - not needed as we have it in |
| 520 | * ctf event header | 597 | * ctf event header |
| 521 | * PERF_SAMPLE_READ - TODO | 598 | * PERF_SAMPLE_READ - TODO |
| 522 | * PERF_SAMPLE_CALLCHAIN - TODO | ||
| 523 | * PERF_SAMPLE_RAW - tracepoint fields are handled separately | 599 | * PERF_SAMPLE_RAW - tracepoint fields are handled separately |
| 524 | * PERF_SAMPLE_BRANCH_STACK - TODO | 600 | * PERF_SAMPLE_BRANCH_STACK - TODO |
| 525 | * PERF_SAMPLE_REGS_USER - TODO | 601 | * PERF_SAMPLE_REGS_USER - TODO |
| @@ -720,6 +796,7 @@ static int process_sample_event(struct perf_tool *tool, | |||
| 720 | struct bt_ctf_event_class *event_class; | 796 | struct bt_ctf_event_class *event_class; |
| 721 | struct bt_ctf_event *event; | 797 | struct bt_ctf_event *event; |
| 722 | int ret; | 798 | int ret; |
| 799 | unsigned long type = evsel->attr.sample_type; | ||
| 723 | 800 | ||
| 724 | if (WARN_ONCE(!priv, "Failed to setup all events.\n")) | 801 | if (WARN_ONCE(!priv, "Failed to setup all events.\n")) |
| 725 | return 0; | 802 | return 0; |
| @@ -751,6 +828,13 @@ static int process_sample_event(struct perf_tool *tool, | |||
| 751 | return -1; | 828 | return -1; |
| 752 | } | 829 | } |
| 753 | 830 | ||
| 831 | if (type & PERF_SAMPLE_CALLCHAIN) { | ||
| 832 | ret = add_callchain_output_values(event_class, | ||
| 833 | event, sample->callchain); | ||
| 834 | if (ret) | ||
| 835 | return -1; | ||
| 836 | } | ||
| 837 | |||
| 754 | if (perf_evsel__is_bpf_output(evsel)) { | 838 | if (perf_evsel__is_bpf_output(evsel)) { |
| 755 | ret = add_bpf_output_values(event_class, event, sample); | 839 | ret = add_bpf_output_values(event_class, event, sample); |
| 756 | if (ret) | 840 | if (ret) |
| @@ -833,6 +917,18 @@ __FUNC_PROCESS_NON_SAMPLE(exit, | |||
| 833 | __NON_SAMPLE_SET_FIELD(fork, u32, ptid); | 917 | __NON_SAMPLE_SET_FIELD(fork, u32, ptid); |
| 834 | __NON_SAMPLE_SET_FIELD(fork, u64, time); | 918 | __NON_SAMPLE_SET_FIELD(fork, u64, time); |
| 835 | ) | 919 | ) |
| 920 | __FUNC_PROCESS_NON_SAMPLE(mmap, | ||
| 921 | __NON_SAMPLE_SET_FIELD(mmap, u32, pid); | ||
| 922 | __NON_SAMPLE_SET_FIELD(mmap, u32, tid); | ||
| 923 | __NON_SAMPLE_SET_FIELD(mmap, u64_hex, start); | ||
| 924 | __NON_SAMPLE_SET_FIELD(mmap, string, filename); | ||
| 925 | ) | ||
| 926 | __FUNC_PROCESS_NON_SAMPLE(mmap2, | ||
| 927 | __NON_SAMPLE_SET_FIELD(mmap2, u32, pid); | ||
| 928 | __NON_SAMPLE_SET_FIELD(mmap2, u32, tid); | ||
| 929 | __NON_SAMPLE_SET_FIELD(mmap2, u64_hex, start); | ||
| 930 | __NON_SAMPLE_SET_FIELD(mmap2, string, filename); | ||
| 931 | ) | ||
| 836 | #undef __NON_SAMPLE_SET_FIELD | 932 | #undef __NON_SAMPLE_SET_FIELD |
| 837 | #undef __FUNC_PROCESS_NON_SAMPLE | 933 | #undef __FUNC_PROCESS_NON_SAMPLE |
| 838 | 934 | ||
| @@ -1043,6 +1139,14 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, | |||
| 1043 | if (type & PERF_SAMPLE_TRANSACTION) | 1139 | if (type & PERF_SAMPLE_TRANSACTION) |
| 1044 | ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); | 1140 | ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); |
| 1045 | 1141 | ||
| 1142 | if (type & PERF_SAMPLE_CALLCHAIN) { | ||
| 1143 | ADD_FIELD(event_class, cw->data.u32, "perf_callchain_size"); | ||
| 1144 | ADD_FIELD(event_class, | ||
| 1145 | bt_ctf_field_type_sequence_create( | ||
| 1146 | cw->data.u64_hex, "perf_callchain_size"), | ||
| 1147 | "perf_callchain"); | ||
| 1148 | } | ||
| 1149 | |||
| 1046 | #undef ADD_FIELD | 1150 | #undef ADD_FIELD |
| 1047 | return 0; | 1151 | return 0; |
| 1048 | } | 1152 | } |
| @@ -1164,6 +1268,19 @@ __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(exit, | |||
| 1164 | __NON_SAMPLE_ADD_FIELD(u64, time); | 1268 | __NON_SAMPLE_ADD_FIELD(u64, time); |
| 1165 | ) | 1269 | ) |
| 1166 | 1270 | ||
| 1271 | __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap, | ||
| 1272 | __NON_SAMPLE_ADD_FIELD(u32, pid); | ||
| 1273 | __NON_SAMPLE_ADD_FIELD(u32, tid); | ||
| 1274 | __NON_SAMPLE_ADD_FIELD(u64_hex, start); | ||
| 1275 | __NON_SAMPLE_ADD_FIELD(string, filename); | ||
| 1276 | ) | ||
| 1277 | |||
| 1278 | __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap2, | ||
| 1279 | __NON_SAMPLE_ADD_FIELD(u32, pid); | ||
| 1280 | __NON_SAMPLE_ADD_FIELD(u32, tid); | ||
| 1281 | __NON_SAMPLE_ADD_FIELD(u64_hex, start); | ||
| 1282 | __NON_SAMPLE_ADD_FIELD(string, filename); | ||
| 1283 | ) | ||
| 1167 | #undef __NON_SAMPLE_ADD_FIELD | 1284 | #undef __NON_SAMPLE_ADD_FIELD |
| 1168 | #undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS | 1285 | #undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS |
| 1169 | 1286 | ||
| @@ -1181,6 +1298,12 @@ static int setup_non_sample_events(struct ctf_writer *cw, | |||
| 1181 | ret = add_fork_event(cw); | 1298 | ret = add_fork_event(cw); |
| 1182 | if (ret) | 1299 | if (ret) |
| 1183 | return ret; | 1300 | return ret; |
| 1301 | ret = add_mmap_event(cw); | ||
| 1302 | if (ret) | ||
| 1303 | return ret; | ||
| 1304 | ret = add_mmap2_event(cw); | ||
| 1305 | if (ret) | ||
| 1306 | return ret; | ||
| 1184 | return 0; | 1307 | return 0; |
| 1185 | } | 1308 | } |
| 1186 | 1309 | ||
| @@ -1482,6 +1605,8 @@ int bt_convert__perf2ctf(const char *input, const char *path, | |||
| 1482 | c.tool.comm = process_comm_event; | 1605 | c.tool.comm = process_comm_event; |
| 1483 | c.tool.exit = process_exit_event; | 1606 | c.tool.exit = process_exit_event; |
| 1484 | c.tool.fork = process_fork_event; | 1607 | c.tool.fork = process_fork_event; |
| 1608 | c.tool.mmap = process_mmap_event; | ||
| 1609 | c.tool.mmap2 = process_mmap2_event; | ||
| 1485 | } | 1610 | } |
| 1486 | 1611 | ||
| 1487 | err = perf_config(convert__config, &c); | 1612 | err = perf_config(convert__config, &c); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 0843746bc389..bf2c4936e35f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -265,6 +265,11 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist); | |||
| 265 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, | 265 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
| 266 | struct list_head *list); | 266 | struct list_head *list); |
| 267 | 267 | ||
| 268 | static inline bool perf_evlist__empty(struct perf_evlist *evlist) | ||
| 269 | { | ||
| 270 | return list_empty(&evlist->entries); | ||
| 271 | } | ||
| 272 | |||
| 268 | static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) | 273 | static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) |
| 269 | { | 274 | { |
| 270 | return list_entry(evlist->entries.next, struct perf_evsel, node); | 275 | return list_entry(evlist->entries.next, struct perf_evsel, node); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 450b5fadf8cb..3735c9e0080d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -49,6 +49,7 @@ static struct { | |||
| 49 | bool clockid_wrong; | 49 | bool clockid_wrong; |
| 50 | bool lbr_flags; | 50 | bool lbr_flags; |
| 51 | bool write_backward; | 51 | bool write_backward; |
| 52 | bool group_read; | ||
| 52 | } perf_missing_features; | 53 | } perf_missing_features; |
| 53 | 54 | ||
| 54 | static clockid_t clockid; | 55 | static clockid_t clockid; |
| @@ -1261,20 +1262,148 @@ void perf_counts_values__scale(struct perf_counts_values *count, | |||
| 1261 | *pscaled = scaled; | 1262 | *pscaled = scaled; |
| 1262 | } | 1263 | } |
| 1263 | 1264 | ||
| 1265 | static int perf_evsel__read_size(struct perf_evsel *evsel) | ||
| 1266 | { | ||
| 1267 | u64 read_format = evsel->attr.read_format; | ||
| 1268 | int entry = sizeof(u64); /* value */ | ||
| 1269 | int size = 0; | ||
| 1270 | int nr = 1; | ||
| 1271 | |||
| 1272 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | ||
| 1273 | size += sizeof(u64); | ||
| 1274 | |||
| 1275 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | ||
| 1276 | size += sizeof(u64); | ||
| 1277 | |||
| 1278 | if (read_format & PERF_FORMAT_ID) | ||
| 1279 | entry += sizeof(u64); | ||
| 1280 | |||
| 1281 | if (read_format & PERF_FORMAT_GROUP) { | ||
| 1282 | nr = evsel->nr_members; | ||
| 1283 | size += sizeof(u64); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | size += entry * nr; | ||
| 1287 | return size; | ||
| 1288 | } | ||
| 1289 | |||
| 1264 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, | 1290 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, |
| 1265 | struct perf_counts_values *count) | 1291 | struct perf_counts_values *count) |
| 1266 | { | 1292 | { |
| 1293 | size_t size = perf_evsel__read_size(evsel); | ||
| 1294 | |||
| 1267 | memset(count, 0, sizeof(*count)); | 1295 | memset(count, 0, sizeof(*count)); |
| 1268 | 1296 | ||
| 1269 | if (FD(evsel, cpu, thread) < 0) | 1297 | if (FD(evsel, cpu, thread) < 0) |
| 1270 | return -EINVAL; | 1298 | return -EINVAL; |
| 1271 | 1299 | ||
| 1272 | if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) <= 0) | 1300 | if (readn(FD(evsel, cpu, thread), count->values, size) <= 0) |
| 1273 | return -errno; | 1301 | return -errno; |
| 1274 | 1302 | ||
| 1275 | return 0; | 1303 | return 0; |
| 1276 | } | 1304 | } |
| 1277 | 1305 | ||
| 1306 | static int | ||
| 1307 | perf_evsel__read_one(struct perf_evsel *evsel, int cpu, int thread) | ||
| 1308 | { | ||
| 1309 | struct perf_counts_values *count = perf_counts(evsel->counts, cpu, thread); | ||
| 1310 | |||
| 1311 | return perf_evsel__read(evsel, cpu, thread, count); | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | static void | ||
| 1315 | perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, | ||
| 1316 | u64 val, u64 ena, u64 run) | ||
| 1317 | { | ||
| 1318 | struct perf_counts_values *count; | ||
| 1319 | |||
| 1320 | count = perf_counts(counter->counts, cpu, thread); | ||
| 1321 | |||
| 1322 | count->val = val; | ||
| 1323 | count->ena = ena; | ||
| 1324 | count->run = run; | ||
| 1325 | count->loaded = true; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | static int | ||
| 1329 | perf_evsel__process_group_data(struct perf_evsel *leader, | ||
| 1330 | int cpu, int thread, u64 *data) | ||
| 1331 | { | ||
| 1332 | u64 read_format = leader->attr.read_format; | ||
| 1333 | struct sample_read_value *v; | ||
| 1334 | u64 nr, ena = 0, run = 0, i; | ||
| 1335 | |||
| 1336 | nr = *data++; | ||
| 1337 | |||
| 1338 | if (nr != (u64) leader->nr_members) | ||
| 1339 | return -EINVAL; | ||
| 1340 | |||
| 1341 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | ||
| 1342 | ena = *data++; | ||
| 1343 | |||
| 1344 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | ||
| 1345 | run = *data++; | ||
| 1346 | |||
| 1347 | v = (struct sample_read_value *) data; | ||
| 1348 | |||
| 1349 | perf_evsel__set_count(leader, cpu, thread, | ||
| 1350 | v[0].value, ena, run); | ||
| 1351 | |||
| 1352 | for (i = 1; i < nr; i++) { | ||
| 1353 | struct perf_evsel *counter; | ||
| 1354 | |||
| 1355 | counter = perf_evlist__id2evsel(leader->evlist, v[i].id); | ||
| 1356 | if (!counter) | ||
| 1357 | return -EINVAL; | ||
| 1358 | |||
| 1359 | perf_evsel__set_count(counter, cpu, thread, | ||
| 1360 | v[i].value, ena, run); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | return 0; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | static int | ||
| 1367 | perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) | ||
| 1368 | { | ||
| 1369 | struct perf_stat_evsel *ps = leader->priv; | ||
| 1370 | u64 read_format = leader->attr.read_format; | ||
| 1371 | int size = perf_evsel__read_size(leader); | ||
| 1372 | u64 *data = ps->group_data; | ||
| 1373 | |||
| 1374 | if (!(read_format & PERF_FORMAT_ID)) | ||
| 1375 | return -EINVAL; | ||
| 1376 | |||
| 1377 | if (!perf_evsel__is_group_leader(leader)) | ||
| 1378 | return -EINVAL; | ||
| 1379 | |||
| 1380 | if (!data) { | ||
| 1381 | data = zalloc(size); | ||
| 1382 | if (!data) | ||
| 1383 | return -ENOMEM; | ||
| 1384 | |||
| 1385 | ps->group_data = data; | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | if (FD(leader, cpu, thread) < 0) | ||
| 1389 | return -EINVAL; | ||
| 1390 | |||
| 1391 | if (readn(FD(leader, cpu, thread), data, size) <= 0) | ||
| 1392 | return -errno; | ||
| 1393 | |||
| 1394 | return perf_evsel__process_group_data(leader, cpu, thread, data); | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) | ||
| 1398 | { | ||
| 1399 | u64 read_format = evsel->attr.read_format; | ||
| 1400 | |||
| 1401 | if (read_format & PERF_FORMAT_GROUP) | ||
| 1402 | return perf_evsel__read_group(evsel, cpu, thread); | ||
| 1403 | else | ||
| 1404 | return perf_evsel__read_one(evsel, cpu, thread); | ||
| 1405 | } | ||
| 1406 | |||
| 1278 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 1407 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
| 1279 | int cpu, int thread, bool scale) | 1408 | int cpu, int thread, bool scale) |
| 1280 | { | 1409 | { |
| @@ -1550,6 +1679,8 @@ fallback_missing_features: | |||
| 1550 | if (perf_missing_features.lbr_flags) | 1679 | if (perf_missing_features.lbr_flags) |
| 1551 | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | | 1680 | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | |
| 1552 | PERF_SAMPLE_BRANCH_NO_CYCLES); | 1681 | PERF_SAMPLE_BRANCH_NO_CYCLES); |
| 1682 | if (perf_missing_features.group_read && evsel->attr.inherit) | ||
| 1683 | evsel->attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); | ||
| 1553 | retry_sample_id: | 1684 | retry_sample_id: |
| 1554 | if (perf_missing_features.sample_id_all) | 1685 | if (perf_missing_features.sample_id_all) |
| 1555 | evsel->attr.sample_id_all = 0; | 1686 | evsel->attr.sample_id_all = 0; |
| @@ -1705,6 +1836,12 @@ try_fallback: | |||
| 1705 | perf_missing_features.lbr_flags = true; | 1836 | perf_missing_features.lbr_flags = true; |
| 1706 | pr_debug2("switching off branch sample type no (cycles/flags)\n"); | 1837 | pr_debug2("switching off branch sample type no (cycles/flags)\n"); |
| 1707 | goto fallback_missing_features; | 1838 | goto fallback_missing_features; |
| 1839 | } else if (!perf_missing_features.group_read && | ||
| 1840 | evsel->attr.inherit && | ||
| 1841 | (evsel->attr.read_format & PERF_FORMAT_GROUP)) { | ||
| 1842 | perf_missing_features.group_read = true; | ||
| 1843 | pr_debug2("switching off group read\n"); | ||
| 1844 | goto fallback_missing_features; | ||
| 1708 | } | 1845 | } |
| 1709 | out_close: | 1846 | out_close: |
| 1710 | do { | 1847 | do { |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index fb40ca3c6519..de03c18daaf0 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -299,6 +299,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, | |||
| 299 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, | 299 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, |
| 300 | struct perf_counts_values *count); | 300 | struct perf_counts_values *count); |
| 301 | 301 | ||
| 302 | int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread); | ||
| 303 | |||
| 302 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 304 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
| 303 | int cpu, int thread, bool scale); | 305 | int cpu, int thread, bool scale); |
| 304 | 306 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b327c955a4f..12359bd986db 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -2563,7 +2563,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) | |||
| 2563 | 2563 | ||
| 2564 | BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); | 2564 | BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); |
| 2565 | 2565 | ||
| 2566 | if (evlist == NULL) | 2566 | if (evlist == NULL || perf_evlist__empty(evlist)) |
| 2567 | goto out_no_evlist; | 2567 | goto out_no_evlist; |
| 2568 | 2568 | ||
| 2569 | evlist__for_each_entry(evlist, evsel) { | 2569 | evlist__for_each_entry(evlist, evsel) { |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 53b9a994a3dc..35e9848734d6 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
| @@ -128,6 +128,10 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | |||
| 128 | 128 | ||
| 129 | static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | 129 | static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) |
| 130 | { | 130 | { |
| 131 | struct perf_stat_evsel *ps = evsel->priv; | ||
| 132 | |||
| 133 | if (ps) | ||
| 134 | free(ps->group_data); | ||
| 131 | zfree(&evsel->priv); | 135 | zfree(&evsel->priv); |
| 132 | } | 136 | } |
| 133 | 137 | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 7522bf10b03e..eacaf958e19d 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
| @@ -28,8 +28,9 @@ enum perf_stat_evsel_id { | |||
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | struct perf_stat_evsel { | 30 | struct perf_stat_evsel { |
| 31 | struct stats res_stats[3]; | 31 | struct stats res_stats[3]; |
| 32 | enum perf_stat_evsel_id id; | 32 | enum perf_stat_evsel_id id; |
| 33 | u64 *group_data; | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | enum aggr_mode { | 36 | enum aggr_mode { |
