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

perf inject: Lazy build-id mmap2 event insertion

Add -B option that lazily inserts mmap2 events thereby dropping all
mmap events without samples. This is similar to the behavior of -b
where only build_id events are inserted when a dso is accessed in a
sample.

File size savings can be significant in system-wide mode, consider:

$ perf record -g -a -o perf.data sleep 1
$ perf inject -B -i perf.data -o perf.new.data
$ ls -al perf.data perf.new.data
5147049 perf.data
2248493 perf.new.data

Give test coverage of the new option in 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-4-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
64eed019 d762ba02

+63 -12
+50 -12
tools/perf/builtin-inject.c
··· 108 108 BID_RWS__INJECT_HEADER_LAZY, 109 109 BID_RWS__INJECT_HEADER_ALL, 110 110 BID_RWS__MMAP2_BUILDID_ALL, 111 + BID_RWS__MMAP2_BUILDID_LAZY, 111 112 }; 112 113 113 114 struct perf_inject { ··· 528 527 * Remember the evsel for lazy build id generation. It is used 529 528 * for the sample id header type. 530 529 */ 531 - if (inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY && 530 + if ((inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY || 531 + inject->build_id_style == BID_RWS__MMAP2_BUILDID_LAZY) && 532 532 !inject->mmap_evsel) 533 533 inject->mmap_evsel = evlist__event2evsel(inject->session->evlist, event); 534 534 ··· 562 560 } 563 561 } 564 562 dso__put(dso); 563 + if (inject->build_id_style == BID_RWS__MMAP2_BUILDID_LAZY) 564 + return 0; 565 + 565 566 return perf_event__repipe(tool, event, sample, machine); 566 567 } 567 568 ··· 830 825 return 0; 831 826 } 832 827 833 - static int mark_dso_hit(const struct perf_tool *tool, 828 + static int mark_dso_hit(const struct perf_inject *inject, 829 + const struct perf_tool *tool, 834 830 struct perf_sample *sample, 835 831 struct machine *machine, 836 832 const struct evsel *mmap_evsel, ··· 860 854 } 861 855 } 862 856 dso = map__dso(map); 863 - if (dso && !dso__hit(dso)) { 864 - dso__set_hit(dso); 865 - tool__inject_build_id(tool, sample, machine, 866 - mmap_evsel, misc, dso__long_name(dso), dso, 867 - map__flags(map)); 857 + if (inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY) { 858 + if (dso && !dso__hit(dso)) { 859 + dso__set_hit(dso); 860 + tool__inject_build_id(tool, sample, machine, 861 + mmap_evsel, misc, dso__long_name(dso), dso, 862 + map__flags(map)); 863 + } 864 + } else if (inject->build_id_style == BID_RWS__MMAP2_BUILDID_LAZY) { 865 + if (!map__hit(map)) { 866 + const struct build_id null_bid = { .size = 0 }; 867 + const struct build_id *bid = dso ? dso__bid(dso) : &null_bid; 868 + const char *filename = dso ? dso__long_name(dso) : ""; 869 + 870 + map__set_hit(map); 871 + perf_event__synthesize_mmap2_build_id(tool, sample, machine, 872 + perf_event__repipe, 873 + mmap_evsel, 874 + misc, 875 + sample->pid, sample->tid, 876 + map__start(map), 877 + map__end(map) - map__start(map), 878 + map__pgoff(map), 879 + bid, 880 + map__prot(map), 881 + map__flags(map), 882 + filename); 883 + } 868 884 } 869 885 return 0; 870 886 } 871 887 872 888 struct mark_dso_hit_args { 889 + const struct perf_inject *inject; 873 890 const struct perf_tool *tool; 874 891 struct perf_sample *sample; 875 892 struct machine *machine; ··· 904 875 struct mark_dso_hit_args *args = data; 905 876 struct map *map = node->ms.map; 906 877 907 - return mark_dso_hit(args->tool, args->sample, args->machine, 878 + return mark_dso_hit(args->inject, args->tool, args->sample, args->machine, 908 879 args->mmap_evsel, map, /*sample_in_dso=*/false); 909 880 } 910 881 ··· 917 888 struct thread *thread; 918 889 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 919 890 struct mark_dso_hit_args args = { 891 + .inject = inject, 920 892 .tool = tool, 921 893 /* 922 894 * Use the parsed sample data of the sample event, which will ··· 937 907 } 938 908 939 909 if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) { 940 - mark_dso_hit(tool, sample, machine, args.mmap_evsel, al.map, 910 + mark_dso_hit(inject, tool, sample, machine, args.mmap_evsel, al.map, 941 911 /*sample_in_dso=*/true); 942 912 } 943 913 ··· 2185 2155 #endif 2186 2156 } 2187 2157 2188 - if (inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY) { 2158 + if (inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY || 2159 + inject->build_id_style == BID_RWS__MMAP2_BUILDID_LAZY) { 2189 2160 inject->tool.sample = perf_event__inject_buildid; 2190 2161 } else if (inject->sched_stat) { 2191 2162 struct evsel *evsel; ··· 2369 2338 const char *known_build_ids = NULL; 2370 2339 bool build_ids; 2371 2340 bool build_id_all; 2341 + bool mmap2_build_ids; 2372 2342 bool mmap2_build_id_all; 2373 2343 2374 2344 struct option options[] = { ··· 2377 2345 "Inject build-ids into the output stream"), 2378 2346 OPT_BOOLEAN(0, "buildid-all", &build_id_all, 2379 2347 "Inject build-ids of all DSOs into the output stream"), 2348 + OPT_BOOLEAN('B', "mmap2-buildids", &mmap2_build_ids, 2349 + "Drop unused mmap events, make others mmap2 with build IDs"), 2380 2350 OPT_BOOLEAN(0, "mmap2-buildid-all", &mmap2_build_id_all, 2381 2351 "Rewrite all mmap events as mmap2 events with build IDs"), 2382 2352 OPT_STRING(0, "known-build-ids", &known_build_ids, ··· 2477 2443 return -1; 2478 2444 } 2479 2445 } 2446 + if (mmap2_build_ids) 2447 + inject.build_id_style = BID_RWS__MMAP2_BUILDID_LAZY; 2480 2448 if (mmap2_build_id_all) 2481 2449 inject.build_id_style = BID_RWS__MMAP2_BUILDID_ALL; 2482 2450 if (build_ids) ··· 2489 2453 data.path = inject.input_name; 2490 2454 2491 2455 ordered_events = inject.jit_mode || inject.sched_stat || 2492 - (inject.build_id_style == BID_RWS__INJECT_HEADER_LAZY); 2456 + inject.build_id_style == BID_RWS__INJECT_HEADER_LAZY || 2457 + inject.build_id_style == BID_RWS__MMAP2_BUILDID_LAZY; 2493 2458 perf_tool__init(&inject.tool, ordered_events); 2494 2459 inject.tool.sample = perf_event__repipe_sample; 2495 2460 inject.tool.read = perf_event__repipe_sample; ··· 2569 2532 } 2570 2533 } 2571 2534 2572 - if (inject.build_id_style == BID_RWS__INJECT_HEADER_LAZY) { 2535 + if (inject.build_id_style == BID_RWS__INJECT_HEADER_LAZY || 2536 + inject.build_id_style == BID_RWS__MMAP2_BUILDID_LAZY) { 2573 2537 /* 2574 2538 * to make sure the mmap records are ordered correctly 2575 2539 * and so that the correct especially due to jitted code
+1
tools/perf/tests/shell/pipe_test.sh
··· 116 116 } 117 117 118 118 test_record_report 119 + test_inject_bids -B 119 120 test_inject_bids -b 120 121 test_inject_bids --buildid-all 121 122 test_inject_bids --mmap2-buildid-all
+1
tools/perf/util/map.c
··· 116 116 map__set_mapping_type(map, MAPPING_TYPE__DSO); 117 117 assert(map__erange_warned(map) == false); 118 118 assert(map__priv(map) == false); 119 + assert(map__hit(map) == false); 119 120 } 120 121 121 122 struct map *map__new(struct machine *machine, u64 start, u64 len,
+11
tools/perf/util/map.h
··· 35 35 enum mapping_type mapping_type:8; 36 36 bool erange_warned; 37 37 bool priv; 38 + bool hit; 38 39 }; 39 40 40 41 struct kmap; ··· 82 81 static inline bool map__priv(const struct map *map) 83 82 { 84 83 return RC_CHK_ACCESS(map)->priv; 84 + } 85 + 86 + static inline bool map__hit(const struct map *map) 87 + { 88 + return RC_CHK_ACCESS(map)->hit; 85 89 } 86 90 87 91 static inline refcount_t *map__refcnt(struct map *map) ··· 291 285 static inline void map__set_priv(struct map *map) 292 286 { 293 287 RC_CHK_ACCESS(map)->priv = true; 288 + } 289 + 290 + static inline void map__set_hit(struct map *map) 291 + { 292 + RC_CHK_ACCESS(map)->hit = true; 294 293 } 295 294 296 295 static inline void map__set_erange_warned(struct map *map)