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

perf inject: Add new mmap2-buildid-all option

Add an option that allows all mmap or mmap2 events to be rewritten as
mmap2 events with build IDs.

This is similar to the existing -b/--build-ids and --buildid-all options
except instead of adding a build_id event an existing mmap/mmap2 event
is used as a template and a new mmap2 event synthesized from it.

As mmap2 events are typical this avoids the insertion of build_id
events.

Add test coverage to the pipe test.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Anne Macedo <retpolanne@posteo.net>
Cc: Casey Chen <cachen@purestorage.com>
Cc: Colin Ian King <colin.i.king@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sun Haiyong <sunhaiyong@loongson.cn>
Link: https://lore.kernel.org/r/20240909203740.143492-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
d762ba02 ae39ba16

+154 -3
+85 -3
tools/perf/builtin-inject.c
··· 107 107 BID_RWS__NONE = 0, 108 108 BID_RWS__INJECT_HEADER_LAZY, 109 109 BID_RWS__INJECT_HEADER_ALL, 110 + BID_RWS__MMAP2_BUILDID_ALL, 110 111 }; 111 112 112 113 struct perf_inject { ··· 147 146 __u16 misc, 148 147 const char *filename, 149 148 struct dso *dso, u32 flags); 149 + static int tool__inject_mmap2_build_id(const struct perf_tool *tool, 150 + struct perf_sample *sample, 151 + struct machine *machine, 152 + const struct evsel *evsel, 153 + __u16 misc, 154 + __u32 pid, __u32 tid, 155 + __u64 start, __u64 len, __u64 pgoff, 156 + struct dso *dso, 157 + __u32 prot, __u32 flags, 158 + const char *filename); 150 159 151 160 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz) 152 161 { ··· 172 161 173 162 static int perf_event__repipe_synth(const struct perf_tool *tool, 174 163 union perf_event *event) 164 + 175 165 { 176 166 struct perf_inject *inject = container_of(tool, struct perf_inject, 177 167 tool); ··· 466 454 union perf_event *event, 467 455 struct perf_sample *sample, 468 456 struct machine *machine, 469 - __u32 pid, __u32 tid, __u32 flags, 457 + __u32 pid, __u32 tid, 458 + __u64 start, __u64 len, __u64 pgoff, 459 + __u32 flags, __u32 prot, 470 460 const char *filename, 471 461 const struct dso_id *dso_id, 472 462 int (*perf_event_process)(const struct perf_tool *tool, ··· 539 525 return err; 540 526 } 541 527 } 528 + if ((inject->build_id_style == BID_RWS__MMAP2_BUILDID_ALL) && 529 + !(event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)) { 530 + struct evsel *evsel = evlist__event2evsel(inject->session->evlist, event); 531 + 532 + if (evsel && !dso_sought) { 533 + dso = findnew_dso(pid, tid, filename, dso_id, machine); 534 + dso_sought = true; 535 + } 536 + if (evsel && dso && 537 + !tool__inject_mmap2_build_id(tool, sample, machine, evsel, 538 + sample->cpumode | PERF_RECORD_MISC_MMAP_BUILD_ID, 539 + pid, tid, start, len, pgoff, 540 + dso, 541 + prot, flags, 542 + filename)) { 543 + /* Injected mmap2 so no need to repipe. */ 544 + dso__put(dso); 545 + return 0; 546 + } 547 + } 542 548 dso__put(dso); 543 549 return perf_event__repipe(tool, event, sample, machine); 544 550 } ··· 570 536 { 571 537 return perf_event__repipe_common_mmap( 572 538 tool, event, sample, machine, 573 - event->mmap.pid, event->mmap.tid, /*flags=*/0, 539 + event->mmap.pid, event->mmap.tid, 540 + event->mmap.start, event->mmap.len, event->mmap.pgoff, 541 + /*flags=*/0, PROT_EXEC, 574 542 event->mmap.filename, /*dso_id=*/NULL, 575 543 perf_event__process_mmap); 576 544 } ··· 595 559 596 560 return perf_event__repipe_common_mmap( 597 561 tool, event, sample, machine, 598 - event->mmap2.pid, event->mmap2.tid, event->mmap2.flags, 562 + event->mmap2.pid, event->mmap2.tid, 563 + event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, 564 + event->mmap2.flags, event->mmap2.prot, 599 565 event->mmap2.filename, dso_id, 600 566 perf_event__process_mmap2); 601 567 } ··· 783 745 return -1; 784 746 } 785 747 748 + return 0; 749 + } 750 + 751 + static int tool__inject_mmap2_build_id(const struct perf_tool *tool, 752 + struct perf_sample *sample, 753 + struct machine *machine, 754 + const struct evsel *evsel, 755 + __u16 misc, 756 + __u32 pid, __u32 tid, 757 + __u64 start, __u64 len, __u64 pgoff, 758 + struct dso *dso, 759 + __u32 prot, __u32 flags, 760 + const char *filename) 761 + { 762 + int err; 763 + 764 + /* Return to repipe anonymous maps. */ 765 + if (is_anon_memory(filename) || flags & MAP_HUGETLB) 766 + return 1; 767 + if (is_no_dso_memory(filename)) 768 + return 1; 769 + 770 + if (dso__read_build_id(dso)) { 771 + pr_debug("no build_id found for %s\n", filename); 772 + return -1; 773 + } 774 + 775 + err = perf_event__synthesize_mmap2_build_id(tool, sample, machine, 776 + perf_event__repipe, 777 + evsel, 778 + misc, pid, tid, 779 + start, len, pgoff, 780 + dso__bid(dso), 781 + prot, flags, 782 + filename); 783 + if (err) { 784 + pr_err("Can't synthesize build_id event for %s\n", filename); 785 + return -1; 786 + } 786 787 return 0; 787 788 } 788 789 ··· 2338 2261 const char *known_build_ids = NULL; 2339 2262 bool build_ids; 2340 2263 bool build_id_all; 2264 + bool mmap2_build_id_all; 2341 2265 2342 2266 struct option options[] = { 2343 2267 OPT_BOOLEAN('b', "build-ids", &build_ids, 2344 2268 "Inject build-ids into the output stream"), 2345 2269 OPT_BOOLEAN(0, "buildid-all", &build_id_all, 2346 2270 "Inject build-ids of all DSOs into the output stream"), 2271 + OPT_BOOLEAN(0, "mmap2-buildid-all", &mmap2_build_id_all, 2272 + "Rewrite all mmap events as mmap2 events with build IDs"), 2347 2273 OPT_STRING(0, "known-build-ids", &known_build_ids, 2348 2274 "buildid path [,buildid path...]", 2349 2275 "build-ids to use for given paths"), ··· 2443 2363 return -1; 2444 2364 } 2445 2365 } 2366 + if (mmap2_build_id_all) 2367 + inject.build_id_style = BID_RWS__MMAP2_BUILDID_ALL; 2446 2368 if (build_ids) 2447 2369 inject.build_id_style = BID_RWS__INJECT_HEADER_LAZY; 2448 2370 if (build_id_all)
+1
tools/perf/tests/shell/pipe_test.sh
··· 118 118 test_record_report 119 119 test_inject_bids -b 120 120 test_inject_bids --buildid-all 121 + test_inject_bids --mmap2-buildid-all 121 122 122 123 cleanup 123 124 exit $err
+57
tools/perf/util/synthetic-events.c
··· 2266 2266 2267 2267 ev.header.size += ret; 2268 2268 } 2269 + 2270 + return process(tool, &ev, sample, machine); 2271 + } 2272 + 2273 + int perf_event__synthesize_mmap2_build_id(const struct perf_tool *tool, 2274 + struct perf_sample *sample, 2275 + struct machine *machine, 2276 + perf_event__handler_t process, 2277 + const struct evsel *evsel, 2278 + __u16 misc, 2279 + __u32 pid, __u32 tid, 2280 + __u64 start, __u64 len, __u64 pgoff, 2281 + const struct build_id *bid, 2282 + __u32 prot, __u32 flags, 2283 + const char *filename) 2284 + { 2285 + union perf_event ev; 2286 + size_t ev_len; 2287 + void *array; 2288 + int ret; 2289 + 2290 + ev_len = sizeof(ev.mmap2) - sizeof(ev.mmap2.filename) + strlen(filename) + 1; 2291 + ev_len = PERF_ALIGN(ev_len, sizeof(u64)); 2292 + 2293 + memset(&ev, 0, ev_len); 2294 + 2295 + ev.mmap2.header.type = PERF_RECORD_MMAP2; 2296 + ev.mmap2.header.misc = misc | PERF_RECORD_MISC_MMAP_BUILD_ID; 2297 + ev.mmap2.header.size = ev_len; 2298 + 2299 + ev.mmap2.pid = pid; 2300 + ev.mmap2.tid = tid; 2301 + ev.mmap2.start = start; 2302 + ev.mmap2.len = len; 2303 + ev.mmap2.pgoff = pgoff; 2304 + 2305 + ev.mmap2.build_id_size = min(bid->size, sizeof(ev.mmap2.build_id)); 2306 + memcpy(ev.mmap2.build_id, bid->data, ev.mmap2.build_id_size); 2307 + 2308 + ev.mmap2.prot = prot; 2309 + ev.mmap2.flags = flags; 2310 + 2311 + memcpy(ev.mmap2.filename, filename, min(strlen(filename), sizeof(ev.mmap.filename))); 2312 + 2313 + array = &ev; 2314 + array += ev.header.size; 2315 + ret = perf_event__synthesize_id_sample(array, evsel->core.attr.sample_type, sample); 2316 + if (ret < 0) 2317 + return ret; 2318 + 2319 + if (ret & 7) { 2320 + pr_err("Bad id sample size %d\n", ret); 2321 + return -EINVAL; 2322 + } 2323 + 2324 + ev.header.size += ret; 2325 + 2269 2326 return process(tool, &ev, sample, machine); 2270 2327 } 2271 2328
+11
tools/perf/util/synthetic-events.h
··· 54 54 __u16 misc, 55 55 const struct build_id *bid, 56 56 const char *filename); 57 + int perf_event__synthesize_mmap2_build_id(const struct perf_tool *tool, 58 + struct perf_sample *sample, 59 + struct machine *machine, 60 + perf_event__handler_t process, 61 + const struct evsel *evsel, 62 + __u16 misc, 63 + __u32 pid, __u32 tid, 64 + __u64 start, __u64 len, __u64 pgoff, 65 + const struct build_id *bid, 66 + __u32 prot, __u32 flags, 67 + const char *filename); 57 68 int perf_event__synthesize_cpu_map(const struct perf_tool *tool, const struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine); 58 69 int perf_event__synthesize_event_update_cpus(const struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process); 59 70 int perf_event__synthesize_event_update_name(const struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);