[PATCH 10/10] perf inject: Add --buildid-mmap2 option to fix failed build ids

From: Jiri Olsa
Date: Tue Jun 22 2021 - 11:40:02 EST


Adding --buildid-mmap2 option that tried to fix failed build ids
in mmap2 events.

Record data with --buildid-mmap option:

# perf record --buildid-mmap ...
...
[ perf record: Woken up 1 times to write data ]
[ perf record: Failed to parse 4 build ids]
[ perf record: Captured and wrote 0.008 MB perf.data ]

Check if there's only build id fault reported:

# perf report --header-only
...
# build id mmap stats: FAULTS 4, LOST 0, NOT FIXED

There is, check the stats:

# perf report --stat

Aggregated stats:
TOTAL events: 104
....
BUILD_ID fails: 4 (14.3%)

Yep, let's fix it:

# perf inject --buildid-mmap2 -i perf.data -o perf-fixed.data

And verify:

# perf report -i perf-fixed.data --stats

Aggregated stats:
TOTAL events: 104
....

Good, let's see how many we fixed:

# perf report --header-only -i perf-fixed.data
...
# build id mmap stats: FAULTS 4, LOST 0, FIXED(4)

Signed-off-by: Jiri Olsa <jolsa@xxxxxxxxxx>
---
tools/perf/Documentation/perf-inject.txt | 3 ++
tools/perf/builtin-inject.c | 45 ++++++++++++++++++++++--
2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 91108fe3ad5f..172d6942ca68 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -30,6 +30,9 @@ OPTIONS
--buildid-all:
Inject build-ids of all DSOs into the output stream

+--buildid-mmap2:
+ Resolve failed buildids in MMAP2 events.
+
-v::
--verbose::
Be more verbose.
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5d6f583e2cd3..5c6c37c581ca 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -40,6 +40,7 @@ struct perf_inject {
struct perf_session *session;
bool build_ids;
bool build_id_all;
+ bool build_id_mmap2;
bool sched_stat;
bool have_auxtrace;
bool strip;
@@ -389,13 +390,43 @@ static int perf_event__repipe_buildid_mmap(struct perf_tool *tool,
return perf_event__repipe(tool, event, sample, machine);
}

+static bool mmap2_fix_buildid(union perf_event *event, struct build_id *bid)
+{
+ struct perf_record_mmap2 *mmap2 = &event->mmap2;
+
+ /*
+ * Filter maps that should have build id, but do not carry one.
+ */
+ if (!is_buildid_memory(mmap2->filename) ||
+ mmap2->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)
+ return false;
+
+ return filename__read_build_id(mmap2->filename, bid) > 0 ? true : false;
+}
+
static int perf_event__repipe_mmap2(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
+ struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
+ union perf_event *tmp = NULL;
+ struct build_id bid;
int err;

+ if (inject->build_id_mmap2 && mmap2_fix_buildid(event, &bid)) {
+ tmp = memdup(event, event->header.size);
+ if (!tmp)
+ return -ENOMEM;
+ memcpy(tmp->mmap2.build_id, bid.data, sizeof(bid.data));
+ tmp->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;
+ tmp->mmap2.build_id_size = (u8) bid.size;
+ tmp->mmap2.__reserved_1 = 0;
+ tmp->mmap2.__reserved_2 = 0;
+ event = tmp;
+ inject->session->header.env.build_id_mmap.fixed++;
+ }
+
err = perf_event__process_mmap2(tool, event, sample, machine);
perf_event__repipe(tool, event, sample, machine);

@@ -411,6 +442,7 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
dso__put(dso);
}

+ free(tmp);
return err;
}

@@ -764,7 +796,8 @@ static int __cmd_inject(struct perf_inject *inject)
signal(SIGINT, sig_handler);

if (inject->build_ids || inject->sched_stat ||
- inject->itrace_synth_opts.set || inject->build_id_all) {
+ inject->itrace_synth_opts.set || inject->build_id_all ||
+ inject->build_id_mmap2) {
inject->tool.mmap = perf_event__repipe_mmap;
inject->tool.mmap2 = perf_event__repipe_mmap2;
inject->tool.fork = perf_event__repipe_fork;
@@ -916,13 +949,15 @@ int cmd_inject(int argc, const char **argv)
.mode = PERF_DATA_MODE_READ,
.use_stdio = true,
};
- int ret;
+ int ret = -1;

struct option options[] = {
OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
"Inject build-ids into the output stream"),
OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all,
"Inject build-ids of all DSOs into the output stream"),
+ OPT_BOOLEAN(0, "buildid-mmap2", &inject.build_id_mmap2,
+ "Resolve failed buildids in MMAP2 events"),
OPT_STRING('i', "input", &inject.input_name, "file",
"input file name"),
OPT_STRING('o', "output", &inject.output.path, "file",
@@ -995,6 +1030,12 @@ int cmd_inject(int argc, const char **argv)
if (IS_ERR(inject.session))
return PTR_ERR(inject.session);

+ if (inject.build_id_mmap2 &&
+ !perf_header__has_feat(&inject.session->header, HEADER_BUILD_ID_MMAP)) {
+ pr_err("The data does not have HEADER_BUILD_ID_MMAP, exiting..\n");
+ goto out_delete;
+ }
+
if (zstd_init(&(inject.session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed.\n");

--
2.31.1