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

perf script: Cache the output type

Right now every time we need to figure out the type of an evsel for
output purposes we do a quick sequence of ifs, but there are new cases
where there is a need to do more complex iterations over multiple data
structures, sso allow for caching this operation on a hole of 'struct
evsel'.

This should really be done on the evsel->priv area that 'perf script'
sets up, but more work is needed to make sure that it is allocated when
we need it, right now it is only used for conditionally, add some
comments so that we move this to that 'perf script' specific area when
the conditions are in place for that.

Acked-by: Thomas Falcon <thomas.falcon@intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Link: https://lore.kernel.org/lkml/Z2XCi3PgstSrV0SE@x1
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

+51 -42
+49 -42
tools/perf/builtin-script.c
··· 221 221 OUTPUT_TYPE_MAX 222 222 }; 223 223 224 + // We need to refactor the evsel->priv use in in 'perf script' to allow for 225 + // using that area, that is being used only in some cases. 226 + #define OUTPUT_TYPE_UNSET -1 227 + 224 228 /* default set to maintain compatibility with current format */ 225 229 static struct { 226 230 bool user_set; ··· 398 394 return OUTPUT_TYPE_OTHER; 399 395 } 400 396 397 + static inline int evsel__output_type(struct evsel *evsel) 398 + { 399 + if (evsel->script_output_type == OUTPUT_TYPE_UNSET) 400 + evsel->script_output_type = output_type(evsel->core.attr.type); 401 + 402 + return evsel->script_output_type; 403 + } 404 + 401 405 static bool output_set_by_user(void) 402 406 { 403 407 int j; ··· 430 418 return str; 431 419 } 432 420 433 - #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) 421 + #define PRINT_FIELD(x) (output[evsel__output_type(evsel)].fields & PERF_OUTPUT_##x) 434 422 435 423 static int evsel__do_check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg, 436 424 enum perf_output_field field, bool allow_user_set) 437 425 { 438 426 struct perf_event_attr *attr = &evsel->core.attr; 439 - int type = output_type(attr->type); 427 + int type = evsel__output_type(evsel); 440 428 const char *evname; 441 429 442 430 if (attr->sample_type & sample_type) ··· 470 458 471 459 static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) 472 460 { 473 - struct perf_event_attr *attr = &evsel->core.attr; 474 461 bool allow_user_set; 475 462 476 463 if (evsel__is_dummy_event(evsel)) ··· 586 575 return 0; 587 576 } 588 577 589 - static void set_print_ip_opts(struct perf_event_attr *attr) 578 + static void evsel__set_print_ip_opts(struct evsel *evsel) 590 579 { 591 - unsigned int type = output_type(attr->type); 580 + unsigned int type = evsel__output_type(evsel); 592 581 593 582 output[type].print_ip_opts = 0; 594 583 if (PRINT_FIELD(IP)) ··· 618 607 evlist__for_each_entry(evlist, evsel) { 619 608 if (evsel__is_dummy_event(evsel)) 620 609 continue; 621 - if (output_type(evsel->core.attr.type) == (int)type) 610 + if (evsel__output_type(evsel) == (int)type) 622 611 return evsel; 623 612 } 624 613 return NULL; ··· 660 649 if (output[j].fields & PERF_OUTPUT_DSOFF) 661 650 output[j].fields |= PERF_OUTPUT_DSO; 662 651 663 - set_print_ip_opts(&evsel->core.attr); 652 + evsel__set_print_ip_opts(evsel); 664 653 tod |= output[j].fields & PERF_OUTPUT_TOD; 665 654 } 666 655 ··· 696 685 output[j].fields |= PERF_OUTPUT_SYM; 697 686 output[j].fields |= PERF_OUTPUT_SYMOFFSET; 698 687 output[j].fields |= PERF_OUTPUT_DSO; 699 - set_print_ip_opts(&evsel->core.attr); 688 + evsel__set_print_ip_opts(evsel); 700 689 goto out; 701 690 } 702 691 } ··· 800 789 struct evsel *evsel, 801 790 u32 type, FILE *fp) 802 791 { 803 - struct perf_event_attr *attr = &evsel->core.attr; 804 792 unsigned long secs; 805 793 unsigned long long nsecs; 806 794 int printed = 0; ··· 951 941 952 942 static int perf_sample__fprintf_brstack(struct perf_sample *sample, 953 943 struct thread *thread, 954 - struct perf_event_attr *attr, FILE *fp) 944 + struct evsel *evsel, FILE *fp) 955 945 { 956 946 struct branch_stack *br = sample->branch_stack; 957 947 struct branch_entry *entries = perf_sample__branch_entries(sample); ··· 990 980 991 981 static int perf_sample__fprintf_brstacksym(struct perf_sample *sample, 992 982 struct thread *thread, 993 - struct perf_event_attr *attr, FILE *fp) 983 + struct evsel *evsel, FILE *fp) 994 984 { 995 985 struct branch_stack *br = sample->branch_stack; 996 986 struct branch_entry *entries = perf_sample__branch_entries(sample); ··· 1028 1018 1029 1019 static int perf_sample__fprintf_brstackoff(struct perf_sample *sample, 1030 1020 struct thread *thread, 1031 - struct perf_event_attr *attr, FILE *fp) 1021 + struct evsel *evsel, FILE *fp) 1032 1022 { 1033 1023 struct branch_stack *br = sample->branch_stack; 1034 1024 struct branch_entry *entries = perf_sample__branch_entries(sample); ··· 1195 1185 return ret; 1196 1186 } 1197 1187 1198 - static int any_dump_insn(struct perf_event_attr *attr __maybe_unused, 1188 + static int any_dump_insn(struct evsel *evsel __maybe_unused, 1199 1189 struct perf_insn *x, uint64_t ip, 1200 1190 u8 *inbuf, int inlen, int *lenp, 1201 1191 FILE *fp) ··· 1223 1213 static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, 1224 1214 struct perf_insn *x, u8 *inbuf, int len, 1225 1215 int insn, FILE *fp, int *total_cycles, 1226 - struct perf_event_attr *attr, 1227 - struct thread *thread, 1228 1216 struct evsel *evsel, 1217 + struct thread *thread, 1229 1218 u64 br_cntr) 1230 1219 { 1231 1220 int ilen = 0; 1232 1221 int printed = fprintf(fp, "\t%016" PRIx64 "\t", ip); 1233 1222 1234 - printed += add_padding(fp, any_dump_insn(attr, x, ip, inbuf, len, &ilen, fp), 30); 1223 + printed += add_padding(fp, any_dump_insn(evsel, x, ip, inbuf, len, &ilen, fp), 30); 1235 1224 printed += fprintf(fp, "\t"); 1236 1225 1237 1226 if (PRINT_FIELD(BRSTACKINSNLEN)) ··· 1286 1277 1287 1278 static int ip__fprintf_sym(uint64_t addr, struct thread *thread, 1288 1279 u8 cpumode, int cpu, struct symbol **lastsym, 1289 - struct perf_event_attr *attr, FILE *fp) 1280 + struct evsel *evsel, FILE *fp) 1290 1281 { 1291 1282 struct addr_location al; 1292 1283 int off, printed = 0, ret = 0; ··· 1362 1353 machine, thread, &x.is64bit, &x.cpumode, false); 1363 1354 if (len > 0) { 1364 1355 printed += ip__fprintf_sym(entries[nr - 1].from, thread, 1365 - x.cpumode, x.cpu, &lastsym, attr, fp); 1356 + x.cpumode, x.cpu, &lastsym, evsel, fp); 1366 1357 printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1], 1367 1358 &x, buffer, len, 0, fp, &total_cycles, 1368 - attr, thread, evsel, br_cntr); 1359 + evsel, thread, br_cntr); 1369 1360 if (PRINT_FIELD(SRCCODE)) 1370 1361 printed += print_srccode(thread, x.cpumode, entries[nr - 1].from); 1371 1362 } ··· 1393 1384 for (off = 0; off < (unsigned)len; off += ilen) { 1394 1385 uint64_t ip = start + off; 1395 1386 1396 - printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); 1387 + printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, evsel, fp); 1397 1388 if (ip == end) { 1398 1389 if (PRINT_FIELD(BRCNTR) && sample->branch_stack_cntr) 1399 1390 br_cntr = sample->branch_stack_cntr[i]; 1400 1391 printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp, 1401 - &total_cycles, attr, thread, evsel, br_cntr); 1392 + &total_cycles, evsel, thread, br_cntr); 1402 1393 if (PRINT_FIELD(SRCCODE)) 1403 1394 printed += print_srccode(thread, x.cpumode, ip); 1404 1395 break; 1405 1396 } else { 1406 1397 ilen = 0; 1407 1398 printed += fprintf(fp, "\t%016" PRIx64 "\t", ip); 1408 - printed += any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen, fp); 1399 + printed += any_dump_insn(evsel, &x, ip, buffer + off, len - off, &ilen, fp); 1409 1400 if (PRINT_FIELD(BRSTACKINSNLEN)) 1410 1401 printed += fprintf(fp, "\tilen: %d", ilen); 1411 1402 printed += fprintf(fp, "\n"); ··· 1444 1435 end = start + 128; 1445 1436 } 1446 1437 len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true); 1447 - printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp); 1438 + printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, evsel, fp); 1448 1439 if (len <= 0) { 1449 1440 /* Print at least last IP if basic block did not work */ 1450 1441 len = grab_bb(buffer, sample->ip, sample->ip, ··· 1453 1444 goto out; 1454 1445 ilen = 0; 1455 1446 printed += fprintf(fp, "\t%016" PRIx64 "\t", sample->ip); 1456 - printed += any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen, fp); 1447 + printed += any_dump_insn(evsel, &x, sample->ip, buffer, len, &ilen, fp); 1457 1448 if (PRINT_FIELD(BRSTACKINSNLEN)) 1458 1449 printed += fprintf(fp, "\tilen: %d", ilen); 1459 1450 printed += fprintf(fp, "\n"); ··· 1464 1455 for (off = 0; off <= end - start; off += ilen) { 1465 1456 ilen = 0; 1466 1457 printed += fprintf(fp, "\t%016" PRIx64 "\t", start + off); 1467 - printed += any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen, fp); 1458 + printed += any_dump_insn(evsel, &x, start + off, buffer + off, len - off, &ilen, fp); 1468 1459 if (PRINT_FIELD(BRSTACKINSNLEN)) 1469 1460 printed += fprintf(fp, "\tilen: %d", ilen); 1470 1461 printed += fprintf(fp, "\n"); ··· 1488 1479 1489 1480 static int perf_sample__fprintf_addr(struct perf_sample *sample, 1490 1481 struct thread *thread, 1491 - struct perf_event_attr *attr, FILE *fp) 1482 + struct evsel *evsel, FILE *fp) 1492 1483 { 1493 1484 struct addr_location al; 1494 1485 int printed = fprintf(fp, "%16" PRIx64, sample->addr); 1495 1486 1496 1487 addr_location__init(&al); 1497 - if (!sample_addr_correlates_sym(attr)) 1488 + if (!sample_addr_correlates_sym(&evsel->core.attr)) 1498 1489 goto out; 1499 1490 1500 1491 thread__resolve(thread, &al, sample); ··· 1521 1512 struct addr_location *addr_al, 1522 1513 u64 *ip) 1523 1514 { 1524 - struct perf_event_attr *attr = &evsel->core.attr; 1525 1515 const char *name = NULL; 1526 1516 1527 1517 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { 1528 - if (sample_addr_correlates_sym(attr)) { 1518 + if (sample_addr_correlates_sym(&evsel->core.attr)) { 1529 1519 if (!addr_al->thread) 1530 1520 thread__resolve(thread, addr_al, sample); 1531 1521 if (addr_al->sym) ··· 1550 1542 struct addr_location *addr_al, 1551 1543 FILE *fp) 1552 1544 { 1553 - struct perf_event_attr *attr = &evsel->core.attr; 1554 1545 size_t depth = thread_stack__depth(thread, sample->cpu); 1555 1546 const char *name = NULL; 1556 1547 static int spacing; ··· 1621 1614 } 1622 1615 1623 1616 static int perf_sample__fprintf_ipc(struct perf_sample *sample, 1624 - struct perf_event_attr *attr, FILE *fp) 1617 + struct evsel *evsel, FILE *fp) 1625 1618 { 1626 1619 unsigned int ipc; 1627 1620 ··· 1642 1635 struct machine *machine, FILE *fp) 1643 1636 { 1644 1637 struct perf_event_attr *attr = &evsel->core.attr; 1645 - unsigned int type = output_type(attr->type); 1638 + unsigned int type = evsel__output_type(evsel); 1646 1639 bool print_srcline_last = false; 1647 1640 int printed = 0; 1648 1641 ··· 1679 1672 ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && 1680 1673 !output[type].user_set)) { 1681 1674 printed += fprintf(fp, " => "); 1682 - printed += perf_sample__fprintf_addr(sample, thread, attr, fp); 1675 + printed += perf_sample__fprintf_addr(sample, thread, evsel, fp); 1683 1676 } 1684 1677 1685 - printed += perf_sample__fprintf_ipc(sample, attr, fp); 1678 + printed += perf_sample__fprintf_ipc(sample, evsel, fp); 1686 1679 1687 1680 if (print_srcline_last) 1688 1681 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); ··· 2164 2157 { 2165 2158 struct thread *thread = al->thread; 2166 2159 struct perf_event_attr *attr = &evsel->core.attr; 2167 - unsigned int type = output_type(attr->type); 2160 + unsigned int type = evsel__output_type(evsel); 2168 2161 struct evsel_script *es = evsel->priv; 2169 2162 FILE *fp = es->fp; 2170 2163 char str[PAGE_SIZE_NAME_LEN]; ··· 2212 2205 perf_sample__fprintf_synth(sample, evsel, fp); 2213 2206 2214 2207 if (PRINT_FIELD(ADDR)) 2215 - perf_sample__fprintf_addr(sample, thread, attr, fp); 2208 + perf_sample__fprintf_addr(sample, thread, evsel, fp); 2216 2209 2217 2210 if (PRINT_FIELD(DATA_SRC)) 2218 2211 data_src__fprintf(sample->data_src, fp); ··· 2262 2255 perf_sample__fprintf_uregs(sample, attr, arch, fp); 2263 2256 2264 2257 if (PRINT_FIELD(BRSTACK)) 2265 - perf_sample__fprintf_brstack(sample, thread, attr, fp); 2258 + perf_sample__fprintf_brstack(sample, thread, evsel, fp); 2266 2259 else if (PRINT_FIELD(BRSTACKSYM)) 2267 - perf_sample__fprintf_brstacksym(sample, thread, attr, fp); 2260 + perf_sample__fprintf_brstacksym(sample, thread, evsel, fp); 2268 2261 else if (PRINT_FIELD(BRSTACKOFF)) 2269 - perf_sample__fprintf_brstackoff(sample, thread, attr, fp); 2262 + perf_sample__fprintf_brstackoff(sample, thread, evsel, fp); 2270 2263 2271 2264 if (evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) 2272 2265 perf_sample__fprintf_bpf_output(sample, fp); ··· 2281 2274 if (PRINT_FIELD(CODE_PAGE_SIZE)) 2282 2275 fprintf(fp, " %s", get_page_size_name(sample->code_page_size, str)); 2283 2276 2284 - perf_sample__fprintf_ipc(sample, attr, fp); 2277 + perf_sample__fprintf_ipc(sample, evsel, fp); 2285 2278 2286 2279 fprintf(fp, "\n"); 2287 2280 ··· 2514 2507 sample_type & PERF_SAMPLE_BRANCH_STACK || 2515 2508 (sample_type & PERF_SAMPLE_REGS_USER && 2516 2509 sample_type & PERF_SAMPLE_STACK_USER))) { 2517 - int type = output_type(evsel->core.attr.type); 2510 + int type = evsel__output_type(evsel); 2518 2511 2519 2512 if (!(output[type].user_unset_fields & PERF_OUTPUT_IP)) 2520 2513 output[type].fields |= PERF_OUTPUT_IP; 2521 2514 if (!(output[type].user_unset_fields & PERF_OUTPUT_SYM)) 2522 2515 output[type].fields |= PERF_OUTPUT_SYM; 2523 2516 } 2524 - set_print_ip_opts(&evsel->core.attr); 2517 + evsel__set_print_ip_opts(evsel); 2525 2518 return 0; 2526 2519 } 2527 2520
+1
tools/perf/util/evsel.c
··· 395 395 evsel->group_pmu_name = NULL; 396 396 evsel->skippable = false; 397 397 evsel->alternate_hw_config = PERF_COUNT_HW_MAX; 398 + evsel->script_output_type = -1; // FIXME: OUTPUT_TYPE_UNSET, see builtin-script.c 398 399 } 399 400 400 401 struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)
+1
tools/perf/util/evsel.h
··· 121 121 bool default_metricgroup; /* A member of the Default metricgroup */ 122 122 struct hashmap *per_pkg_mask; 123 123 int err; 124 + int script_output_type; 124 125 struct { 125 126 evsel__sb_cb_t *cb; 126 127 void *data;