Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'perf-core-for-mingo-4.14-20170728' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes for 4.14 from Arnaldo Carvalho de Melo:

New features:

- Add PERF_SAMPLE_CALLCHAIN and PERF_RECORD_MMAP[2] to 'perf data' CTF
conversion, allowing CTF trace visualization tools to show callchains
and to resolve symbols (Geneviève Bastien)

Improvements:

- Use group read for event groups in 'perf stat', reducing overhead when
groups are defined in the event specification, i.e. when using {} to
enclose a list of events, asking them to be read at the same time,
e.g.: "perf stat -e '{cycles,instructions}'" (Jiri Olsa)

Fixes:

- Do not overwrite perf_sample->weight in 'perf annotate' when
processing samples, use whatever came from the kernel when
perf_event_attr.sample_type has PERF_SAMPLE_WEIGHT set or just handle
its default value, 0, when that is not set and "weight" is one of the
sort orders chosen (Arnaldo Carvalho de Melo)

- 'perf annotate --show-total-period' fixes:
- TUI should show period, not nr_samples
- Set appropriate column width for period/percent
- Fix the column header to show "Period" when when that is what
is being asked for
(Taeung Song, Arnaldo Carvalho de Melo)

- Use default sort if evlist is empty, fixing pipe mode (David Carrillo-Cisneros)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+334 -32
-2
tools/perf/builtin-annotate.c
··· 177 177 */ 178 178 process_branch_stack(sample->branch_stack, al, sample); 179 179 180 - sample->weight = 1; 181 - 182 180 he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); 183 181 if (he == NULL) 184 182 return -ENOMEM;
+1 -1
tools/perf/builtin-data.c
··· 69 69 }; 70 70 71 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 73 return -1; 74 74 #endif 75 75
+27 -3
tools/perf/builtin-stat.c
··· 213 213 static int create_perf_stat_counter(struct perf_evsel *evsel) 214 214 { 215 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 219 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 219 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 231 attr->inherit = !no_inherit; 222 232 ··· 343 333 struct perf_counts_values *count; 344 334 345 335 count = perf_counts(counter->counts, cpu, thread); 346 - if (perf_evsel__read(counter, cpu, thread, count)) { 336 + 337 + /* 338 + * The leader's group read loads data into its group members 339 + * (via perf_evsel__read_counter) and sets threir count->loaded. 340 + */ 341 + if (!count->loaded && 342 + perf_evsel__read_counter(counter, cpu, thread)) { 347 343 counter->counts->scaled = -1; 348 344 perf_counts(counter->counts, cpu, thread)->ena = 0; 349 345 perf_counts(counter->counts, cpu, thread)->run = 0; 350 346 return -1; 351 347 } 348 + 349 + count->loaded = false; 352 350 353 351 if (STAT_RECORD) { 354 352 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { ··· 577 559 return __store_counter_ids(counter, cpus, threads); 578 560 } 579 561 562 + static bool perf_evsel__should_store_id(struct perf_evsel *counter) 563 + { 564 + return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; 565 + } 566 + 580 567 static int __run_perf_stat(int argc, const char **argv) 581 568 { 582 569 int interval = stat_config.interval; ··· 654 631 if (l > unit_width) 655 632 unit_width = l; 656 633 657 - if (STAT_RECORD && store_counter_ids(counter)) 634 + if (perf_evsel__should_store_id(counter) && 635 + store_counter_ids(counter)) 658 636 return -1; 659 637 } 660 638
+20 -16
tools/perf/ui/browsers/annotate.c
··· 17 17 #include <sys/ttydefaults.h> 18 18 19 19 struct disasm_line_samples { 20 - double percent; 21 - u64 nr; 20 + double percent; 21 + struct sym_hist_entry he; 22 22 }; 23 23 24 24 #define IPC_WIDTH 6 ··· 110 110 111 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 - w += IPC_WIDTH + CYCLES_WIDTH; 117 - return w; 116 + static int annotate_browser__cycles_width(struct annotate_browser *ab) 117 + { 118 + return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0; 118 119 } 119 120 120 121 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) ··· 128 127 (!current_entry || (browser->use_navkeypressed && 129 128 !browser->navkeypressed))); 130 129 int width = browser->width, printed; 131 - int i, pcnt_width = annotate_browser__pcnt_width(ab); 130 + int i, pcnt_width = annotate_browser__pcnt_width(ab), 131 + cycles_width = annotate_browser__cycles_width(ab); 132 132 double percent_max = 0.0; 133 133 char bf[256]; 134 134 bool show_title = false; ··· 153 151 bdl->samples[i].percent, 154 152 current_entry); 155 153 if (annotate_browser__opts.show_total_period) { 156 - ui_browser__printf(browser, "%6" PRIu64 " ", 157 - bdl->samples[i].nr); 154 + ui_browser__printf(browser, "%11" PRIu64 " ", 155 + bdl->samples[i].he.period); 158 156 } else { 159 157 ui_browser__printf(browser, "%6.2f ", 160 158 bdl->samples[i].percent); ··· 164 162 ui_browser__set_percent_color(browser, 0, current_entry); 165 163 166 164 if (!show_title) 167 - ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); 168 - else 169 - ui_browser__printf(browser, "%*s", 7, "Percent"); 165 + ui_browser__write_nstring(browser, " ", pcnt_width); 166 + else { 167 + ui_browser__printf(browser, "%*s", pcnt_width, 168 + annotate_browser__opts.show_total_period ? "Period" : "Percent"); 169 + } 170 170 } 171 171 if (ab->have_cycles) { 172 172 if (dl->ipc) ··· 194 190 width += 1; 195 191 196 192 if (!*dl->line) 197 - ui_browser__write_nstring(browser, " ", width - pcnt_width); 193 + ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); 198 194 else if (dl->offset == -1) { 199 195 if (dl->line_nr && annotate_browser__opts.show_linenr) 200 196 printed = scnprintf(bf, sizeof(bf), "%-*d ", ··· 203 199 printed = scnprintf(bf, sizeof(bf), "%*s ", 204 200 ab->addr_width, " "); 205 201 ui_browser__write_nstring(browser, bf, printed); 206 - ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1); 202 + ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1); 207 203 } else { 208 204 u64 addr = dl->offset; 209 205 int color = -1; ··· 260 256 } 261 257 262 258 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 263 - ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed); 259 + ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed); 264 260 } 265 261 266 262 if (current_entry) ··· 461 457 pos->offset, 462 458 next ? next->offset : len, 463 459 &path, &sample); 464 - bpos->samples[i].nr = sample.nr_samples; 460 + bpos->samples[i].he = sample; 465 461 466 462 if (max_percent < bpos->samples[i].percent) 467 463 max_percent = bpos->samples[i].percent;
+6 -5
tools/perf/util/annotate.c
··· 963 963 u64 period = 0; 964 964 965 965 while (offset < end) { 966 - hits += h->addr[offset++].nr_samples; 967 - period += h->addr[offset++].period; 966 + hits += h->addr[offset].nr_samples; 967 + period += h->addr[offset].period; 968 + ++offset; 968 969 } 969 970 970 971 if (h->nr_samples) { ··· 1143 1142 color = get_percent_color(percent); 1144 1143 1145 1144 if (symbol_conf.show_total_period) 1146 - color_fprintf(stdout, color, " %7" PRIu64, 1145 + color_fprintf(stdout, color, " %11" PRIu64, 1147 1146 sample.period); 1148 1147 else 1149 1148 color_fprintf(stdout, color, " %7.2f", percent); ··· 1166 1165 } else if (max_lines && printed >= max_lines) 1167 1166 return 1; 1168 1167 else { 1169 - int width = 8; 1168 + int width = symbol_conf.show_total_period ? 12 : 8; 1170 1169 1171 1170 if (queue) 1172 1171 return -1; ··· 1807 1806 int printed = 2, queue_len = 0; 1808 1807 int more = 0; 1809 1808 u64 len; 1810 - int width = 8; 1809 + int width = symbol_conf.show_total_period ? 12 : 8; 1811 1810 int graph_dotted_len; 1812 1811 1813 1812 filename = strdup(dso->long_name);
+1
tools/perf/util/counts.h
··· 12 12 }; 13 13 u64 values[3]; 14 14 }; 15 + bool loaded; 15 16 }; 16 17 17 18 struct perf_counts {
+126 -1
tools/perf/util/data-convert-bt.c
··· 76 76 struct bt_ctf_event_class *comm_class; 77 77 struct bt_ctf_event_class *exit_class; 78 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 83 struct convert { ··· 508 506 return ret; 509 507 } 510 508 509 + static int 510 + add_callchain_output_values(struct bt_ctf_event_class *event_class, 511 + struct bt_ctf_event *event, 512 + struct ip_callchain *callchain) 513 + { 514 + struct bt_ctf_field_type *len_type, *seq_type; 515 + struct bt_ctf_field *len_field, *seq_field; 516 + unsigned int nr_elements = callchain->nr; 517 + unsigned int i; 518 + int ret; 519 + 520 + len_type = bt_ctf_event_class_get_field_by_name( 521 + event_class, "perf_callchain_size"); 522 + len_field = bt_ctf_field_create(len_type); 523 + if (!len_field) { 524 + pr_err("failed to create 'perf_callchain_size' for callchain output event\n"); 525 + ret = -1; 526 + goto put_len_type; 527 + } 528 + 529 + ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements); 530 + if (ret) { 531 + pr_err("failed to set field value for perf_callchain_size\n"); 532 + goto put_len_field; 533 + } 534 + ret = bt_ctf_event_set_payload(event, "perf_callchain_size", len_field); 535 + if (ret) { 536 + pr_err("failed to set payload to perf_callchain_size\n"); 537 + goto put_len_field; 538 + } 539 + 540 + seq_type = bt_ctf_event_class_get_field_by_name( 541 + event_class, "perf_callchain"); 542 + seq_field = bt_ctf_field_create(seq_type); 543 + if (!seq_field) { 544 + pr_err("failed to create 'perf_callchain' for callchain output event\n"); 545 + ret = -1; 546 + goto put_seq_type; 547 + } 548 + 549 + ret = bt_ctf_field_sequence_set_length(seq_field, len_field); 550 + if (ret) { 551 + pr_err("failed to set length of 'perf_callchain'\n"); 552 + goto put_seq_field; 553 + } 554 + 555 + for (i = 0; i < nr_elements; i++) { 556 + struct bt_ctf_field *elem_field = 557 + bt_ctf_field_sequence_get_field(seq_field, i); 558 + 559 + ret = bt_ctf_field_unsigned_integer_set_value(elem_field, 560 + ((u64 *)(callchain->ips))[i]); 561 + 562 + bt_ctf_field_put(elem_field); 563 + if (ret) { 564 + pr_err("failed to set callchain[%d]\n", i); 565 + goto put_seq_field; 566 + } 567 + } 568 + 569 + ret = bt_ctf_event_set_payload(event, "perf_callchain", seq_field); 570 + if (ret) 571 + pr_err("failed to set payload for raw_data\n"); 572 + 573 + put_seq_field: 574 + bt_ctf_field_put(seq_field); 575 + put_seq_type: 576 + bt_ctf_field_type_put(seq_type); 577 + put_len_field: 578 + bt_ctf_field_put(len_field); 579 + put_len_type: 580 + bt_ctf_field_type_put(len_type); 581 + return ret; 582 + } 583 + 511 584 static int add_generic_values(struct ctf_writer *cw, 512 585 struct bt_ctf_event *event, 513 586 struct perf_evsel *evsel, ··· 596 519 * PERF_SAMPLE_TIME - not needed as we have it in 597 520 * ctf event header 598 521 * PERF_SAMPLE_READ - TODO 599 - * PERF_SAMPLE_CALLCHAIN - TODO 600 522 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 601 523 * PERF_SAMPLE_BRANCH_STACK - TODO 602 524 * PERF_SAMPLE_REGS_USER - TODO ··· 796 720 struct bt_ctf_event_class *event_class; 797 721 struct bt_ctf_event *event; 798 722 int ret; 723 + unsigned long type = evsel->attr.sample_type; 799 724 800 725 if (WARN_ONCE(!priv, "Failed to setup all events.\n")) 801 726 return 0; ··· 824 747 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { 825 748 ret = add_tracepoint_values(cw, event_class, event, 826 749 evsel, sample); 750 + if (ret) 751 + return -1; 752 + } 753 + 754 + if (type & PERF_SAMPLE_CALLCHAIN) { 755 + ret = add_callchain_output_values(event_class, 756 + event, sample->callchain); 827 757 if (ret) 828 758 return -1; 829 759 } ··· 916 832 __NON_SAMPLE_SET_FIELD(fork, u32, tid); 917 833 __NON_SAMPLE_SET_FIELD(fork, u32, ptid); 918 834 __NON_SAMPLE_SET_FIELD(fork, u64, time); 835 + ) 836 + __FUNC_PROCESS_NON_SAMPLE(mmap, 837 + __NON_SAMPLE_SET_FIELD(mmap, u32, pid); 838 + __NON_SAMPLE_SET_FIELD(mmap, u32, tid); 839 + __NON_SAMPLE_SET_FIELD(mmap, u64_hex, start); 840 + __NON_SAMPLE_SET_FIELD(mmap, string, filename); 841 + ) 842 + __FUNC_PROCESS_NON_SAMPLE(mmap2, 843 + __NON_SAMPLE_SET_FIELD(mmap2, u32, pid); 844 + __NON_SAMPLE_SET_FIELD(mmap2, u32, tid); 845 + __NON_SAMPLE_SET_FIELD(mmap2, u64_hex, start); 846 + __NON_SAMPLE_SET_FIELD(mmap2, string, filename); 919 847 ) 920 848 #undef __NON_SAMPLE_SET_FIELD 921 849 #undef __FUNC_PROCESS_NON_SAMPLE ··· 1139 1043 if (type & PERF_SAMPLE_TRANSACTION) 1140 1044 ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); 1141 1045 1046 + if (type & PERF_SAMPLE_CALLCHAIN) { 1047 + ADD_FIELD(event_class, cw->data.u32, "perf_callchain_size"); 1048 + ADD_FIELD(event_class, 1049 + bt_ctf_field_type_sequence_create( 1050 + cw->data.u64_hex, "perf_callchain_size"), 1051 + "perf_callchain"); 1052 + } 1053 + 1142 1054 #undef ADD_FIELD 1143 1055 return 0; 1144 1056 } ··· 1268 1164 __NON_SAMPLE_ADD_FIELD(u64, time); 1269 1165 ) 1270 1166 1167 + __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap, 1168 + __NON_SAMPLE_ADD_FIELD(u32, pid); 1169 + __NON_SAMPLE_ADD_FIELD(u32, tid); 1170 + __NON_SAMPLE_ADD_FIELD(u64_hex, start); 1171 + __NON_SAMPLE_ADD_FIELD(string, filename); 1172 + ) 1173 + 1174 + __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(mmap2, 1175 + __NON_SAMPLE_ADD_FIELD(u32, pid); 1176 + __NON_SAMPLE_ADD_FIELD(u32, tid); 1177 + __NON_SAMPLE_ADD_FIELD(u64_hex, start); 1178 + __NON_SAMPLE_ADD_FIELD(string, filename); 1179 + ) 1271 1180 #undef __NON_SAMPLE_ADD_FIELD 1272 1181 #undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS 1273 1182 ··· 1296 1179 if (ret) 1297 1180 return ret; 1298 1181 ret = add_fork_event(cw); 1182 + if (ret) 1183 + return ret; 1184 + ret = add_mmap_event(cw); 1185 + if (ret) 1186 + return ret; 1187 + ret = add_mmap2_event(cw); 1299 1188 if (ret) 1300 1189 return ret; 1301 1190 return 0; ··· 1605 1482 c.tool.comm = process_comm_event; 1606 1483 c.tool.exit = process_exit_event; 1607 1484 c.tool.fork = process_fork_event; 1485 + c.tool.mmap = process_mmap_event; 1486 + c.tool.mmap2 = process_mmap2_event; 1608 1487 } 1609 1488 1610 1489 err = perf_config(convert__config, &c);
+5
tools/perf/util/evlist.h
··· 265 265 void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 266 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 273 static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) 269 274 { 270 275 return list_entry(evlist->entries.next, struct perf_evsel, node);
+138 -1
tools/perf/util/evsel.c
··· 49 49 bool clockid_wrong; 50 50 bool lbr_flags; 51 51 bool write_backward; 52 + bool group_read; 52 53 } perf_missing_features; 53 54 54 55 static clockid_t clockid; ··· 1262 1261 *pscaled = scaled; 1263 1262 } 1264 1263 1264 + static int perf_evsel__read_size(struct perf_evsel *evsel) 1265 + { 1266 + u64 read_format = evsel->attr.read_format; 1267 + int entry = sizeof(u64); /* value */ 1268 + int size = 0; 1269 + int nr = 1; 1270 + 1271 + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1272 + size += sizeof(u64); 1273 + 1274 + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1275 + size += sizeof(u64); 1276 + 1277 + if (read_format & PERF_FORMAT_ID) 1278 + entry += sizeof(u64); 1279 + 1280 + if (read_format & PERF_FORMAT_GROUP) { 1281 + nr = evsel->nr_members; 1282 + size += sizeof(u64); 1283 + } 1284 + 1285 + size += entry * nr; 1286 + return size; 1287 + } 1288 + 1265 1289 int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, 1266 1290 struct perf_counts_values *count) 1267 1291 { 1292 + size_t size = perf_evsel__read_size(evsel); 1293 + 1268 1294 memset(count, 0, sizeof(*count)); 1269 1295 1270 1296 if (FD(evsel, cpu, thread) < 0) 1271 1297 return -EINVAL; 1272 1298 1273 - if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) <= 0) 1299 + if (readn(FD(evsel, cpu, thread), count->values, size) <= 0) 1274 1300 return -errno; 1275 1301 1276 1302 return 0; 1303 + } 1304 + 1305 + static int 1306 + perf_evsel__read_one(struct perf_evsel *evsel, int cpu, int thread) 1307 + { 1308 + struct perf_counts_values *count = perf_counts(evsel->counts, cpu, thread); 1309 + 1310 + return perf_evsel__read(evsel, cpu, thread, count); 1311 + } 1312 + 1313 + static void 1314 + perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, 1315 + u64 val, u64 ena, u64 run) 1316 + { 1317 + struct perf_counts_values *count; 1318 + 1319 + count = perf_counts(counter->counts, cpu, thread); 1320 + 1321 + count->val = val; 1322 + count->ena = ena; 1323 + count->run = run; 1324 + count->loaded = true; 1325 + } 1326 + 1327 + static int 1328 + perf_evsel__process_group_data(struct perf_evsel *leader, 1329 + int cpu, int thread, u64 *data) 1330 + { 1331 + u64 read_format = leader->attr.read_format; 1332 + struct sample_read_value *v; 1333 + u64 nr, ena = 0, run = 0, i; 1334 + 1335 + nr = *data++; 1336 + 1337 + if (nr != (u64) leader->nr_members) 1338 + return -EINVAL; 1339 + 1340 + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1341 + ena = *data++; 1342 + 1343 + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1344 + run = *data++; 1345 + 1346 + v = (struct sample_read_value *) data; 1347 + 1348 + perf_evsel__set_count(leader, cpu, thread, 1349 + v[0].value, ena, run); 1350 + 1351 + for (i = 1; i < nr; i++) { 1352 + struct perf_evsel *counter; 1353 + 1354 + counter = perf_evlist__id2evsel(leader->evlist, v[i].id); 1355 + if (!counter) 1356 + return -EINVAL; 1357 + 1358 + perf_evsel__set_count(counter, cpu, thread, 1359 + v[i].value, ena, run); 1360 + } 1361 + 1362 + return 0; 1363 + } 1364 + 1365 + static int 1366 + perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) 1367 + { 1368 + struct perf_stat_evsel *ps = leader->priv; 1369 + u64 read_format = leader->attr.read_format; 1370 + int size = perf_evsel__read_size(leader); 1371 + u64 *data = ps->group_data; 1372 + 1373 + if (!(read_format & PERF_FORMAT_ID)) 1374 + return -EINVAL; 1375 + 1376 + if (!perf_evsel__is_group_leader(leader)) 1377 + return -EINVAL; 1378 + 1379 + if (!data) { 1380 + data = zalloc(size); 1381 + if (!data) 1382 + return -ENOMEM; 1383 + 1384 + ps->group_data = data; 1385 + } 1386 + 1387 + if (FD(leader, cpu, thread) < 0) 1388 + return -EINVAL; 1389 + 1390 + if (readn(FD(leader, cpu, thread), data, size) <= 0) 1391 + return -errno; 1392 + 1393 + return perf_evsel__process_group_data(leader, cpu, thread, data); 1394 + } 1395 + 1396 + int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) 1397 + { 1398 + u64 read_format = evsel->attr.read_format; 1399 + 1400 + if (read_format & PERF_FORMAT_GROUP) 1401 + return perf_evsel__read_group(evsel, cpu, thread); 1402 + else 1403 + return perf_evsel__read_one(evsel, cpu, thread); 1277 1404 } 1278 1405 1279 1406 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, ··· 1679 1550 if (perf_missing_features.lbr_flags) 1680 1551 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | 1681 1552 PERF_SAMPLE_BRANCH_NO_CYCLES); 1553 + if (perf_missing_features.group_read && evsel->attr.inherit) 1554 + evsel->attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); 1682 1555 retry_sample_id: 1683 1556 if (perf_missing_features.sample_id_all) 1684 1557 evsel->attr.sample_id_all = 0; ··· 1835 1704 PERF_SAMPLE_BRANCH_NO_FLAGS))) { 1836 1705 perf_missing_features.lbr_flags = true; 1837 1706 pr_debug2("switching off branch sample type no (cycles/flags)\n"); 1707 + goto fallback_missing_features; 1708 + } else if (!perf_missing_features.group_read && 1709 + evsel->attr.inherit && 1710 + (evsel->attr.read_format & PERF_FORMAT_GROUP)) { 1711 + perf_missing_features.group_read = true; 1712 + pr_debug2("switching off group read\n"); 1838 1713 goto fallback_missing_features; 1839 1714 } 1840 1715 out_close:
+2
tools/perf/util/evsel.h
··· 299 299 int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, 300 300 struct perf_counts_values *count); 301 301 302 + int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread); 303 + 302 304 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 303 305 int cpu, int thread, bool scale); 304 306
+1 -1
tools/perf/util/sort.c
··· 2563 2563 2564 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 2567 goto out_no_evlist; 2568 2568 2569 2569 evlist__for_each_entry(evlist, evsel) {
+4
tools/perf/util/stat.c
··· 128 128 129 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 135 zfree(&evsel->priv); 132 136 } 133 137
+3 -2
tools/perf/util/stat.h
··· 28 28 }; 29 29 30 30 struct perf_stat_evsel { 31 - struct stats res_stats[3]; 32 - enum perf_stat_evsel_id id; 31 + struct stats res_stats[3]; 32 + enum perf_stat_evsel_id id; 33 + u64 *group_data; 33 34 }; 34 35 35 36 enum aggr_mode {