Skip to content

Commit ae39ba1

Browse files
captain5050acmel
authored andcommitted
perf inject: Fix build ID injection
Build ID injection wasn't inserting a sample ID and aligning events to 64 bytes rather than 8. No sample ID means events are unordered and two different build_id events for the same path, as happens when a file is replaced, can't be differentiated. Add in sample ID insertion for the build_id events alongside some refactoring. The refactoring better aligns the function arguments for different use cases, such as synthesizing build_id events without needing to have a dso. The misc bits are explicitly passed as with callchains the maps/dsos may span user and kernel land, so using sample->cpumode isn't good enough. Signed-off-by: Ian Rogers <[email protected]> Acked-by: Namhyung Kim <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Anne Macedo <[email protected]> Cc: Casey Chen <[email protected]> Cc: Colin Ian King <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Sun Haiyong <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 0264878 commit ae39ba1

File tree

4 files changed

+175
-55
lines changed

4 files changed

+175
-55
lines changed

tools/perf/builtin-inject.c

Lines changed: 131 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct perf_inject {
130130
struct perf_file_section secs[HEADER_FEAT_BITS];
131131
struct guest_session guest_session;
132132
struct strlist *known_build_ids;
133+
const struct evsel *mmap_evsel;
133134
};
134135

135136
struct event_entry {
@@ -138,8 +139,13 @@ struct event_entry {
138139
union perf_event event[];
139140
};
140141

141-
static int dso__inject_build_id(struct dso *dso, const struct perf_tool *tool,
142-
struct machine *machine, u8 cpumode, u32 flags);
142+
static int tool__inject_build_id(const struct perf_tool *tool,
143+
struct perf_sample *sample,
144+
struct machine *machine,
145+
const struct evsel *evsel,
146+
__u16 misc,
147+
const char *filename,
148+
struct dso *dso, u32 flags);
143149

144150
static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
145151
{
@@ -422,6 +428,28 @@ static struct dso *findnew_dso(int pid, int tid, const char *filename,
422428
return dso;
423429
}
424430

431+
/*
432+
* The evsel used for the sample ID for mmap events. Typically stashed when
433+
* processing mmap events. If not stashed, search the evlist for the first mmap
434+
* gathering event.
435+
*/
436+
static const struct evsel *inject__mmap_evsel(struct perf_inject *inject)
437+
{
438+
struct evsel *pos;
439+
440+
if (inject->mmap_evsel)
441+
return inject->mmap_evsel;
442+
443+
evlist__for_each_entry(inject->session->evlist, pos) {
444+
if (pos->core.attr.mmap) {
445+
inject->mmap_evsel = pos;
446+
return pos;
447+
}
448+
}
449+
pr_err("No mmap events found\n");
450+
return NULL;
451+
}
452+
425453
static int perf_event__repipe_common_mmap(const struct perf_tool *tool,
426454
union perf_event *event,
427455
struct perf_sample *sample,
@@ -469,12 +497,28 @@ static int perf_event__repipe_common_mmap(const struct perf_tool *tool,
469497
}
470498

471499
if (dso && !dso__hit(dso)) {
472-
dso__set_hit(dso);
473-
dso__inject_build_id(dso, tool, machine, sample->cpumode, flags);
500+
struct evsel *evsel = evlist__event2evsel(inject->session->evlist, event);
501+
502+
if (evsel) {
503+
dso__set_hit(dso);
504+
tool__inject_build_id(tool, sample, machine, evsel,
505+
/*misc=*/sample->cpumode,
506+
filename, dso, flags);
507+
}
474508
}
475509
} else {
510+
int err;
511+
512+
/*
513+
* Remember the evsel for lazy build id generation. It is used
514+
* for the sample id header type.
515+
*/
516+
if (inject->build_id_style == BID_RWS__INJECT_HEADER_LAZY &&
517+
!inject->mmap_evsel)
518+
inject->mmap_evsel = evlist__event2evsel(inject->session->evlist, event);
519+
476520
/* Create the thread, map, etc. Not done for the unordered inject all case. */
477-
int err = perf_event_process(tool, event, sample, machine);
521+
err = perf_event_process(tool, event, sample, machine);
478522

479523
if (err) {
480524
dso__put(dso);
@@ -667,58 +711,95 @@ static bool perf_inject__lookup_known_build_id(struct perf_inject *inject,
667711
return false;
668712
}
669713

670-
static int dso__inject_build_id(struct dso *dso, const struct perf_tool *tool,
671-
struct machine *machine, u8 cpumode, u32 flags)
714+
static int tool__inject_build_id(const struct perf_tool *tool,
715+
struct perf_sample *sample,
716+
struct machine *machine,
717+
const struct evsel *evsel,
718+
__u16 misc,
719+
const char *filename,
720+
struct dso *dso, u32 flags)
672721
{
673-
struct perf_inject *inject = container_of(tool, struct perf_inject,
674-
tool);
722+
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
675723
int err;
676724

677-
if (is_anon_memory(dso__long_name(dso)) || flags & MAP_HUGETLB)
725+
if (is_anon_memory(filename) || flags & MAP_HUGETLB)
678726
return 0;
679-
if (is_no_dso_memory(dso__long_name(dso)))
727+
if (is_no_dso_memory(filename))
680728
return 0;
681729

682730
if (inject->known_build_ids != NULL &&
683731
perf_inject__lookup_known_build_id(inject, dso))
684732
return 1;
685733

686734
if (dso__read_build_id(dso) < 0) {
687-
pr_debug("no build_id found for %s\n", dso__long_name(dso));
735+
pr_debug("no build_id found for %s\n", filename);
688736
return -1;
689737
}
690738

691-
err = perf_event__synthesize_build_id(tool, dso, cpumode,
692-
perf_event__repipe, machine);
739+
err = perf_event__synthesize_build_id(tool, sample, machine,
740+
perf_event__repipe,
741+
evsel, misc, dso__bid(dso),
742+
filename);
693743
if (err) {
694-
pr_err("Can't synthesize build_id event for %s\n", dso__long_name(dso));
744+
pr_err("Can't synthesize build_id event for %s\n", filename);
695745
return -1;
696746
}
697747

698748
return 0;
699749
}
700750

751+
static int mark_dso_hit(const struct perf_tool *tool,
752+
struct perf_sample *sample,
753+
struct machine *machine,
754+
const struct evsel *mmap_evsel,
755+
struct map *map, bool sample_in_dso)
756+
{
757+
struct dso *dso;
758+
u16 misc = sample->cpumode;
759+
760+
if (!map)
761+
return 0;
762+
763+
if (!sample_in_dso) {
764+
u16 guest_mask = PERF_RECORD_MISC_GUEST_KERNEL |
765+
PERF_RECORD_MISC_GUEST_USER;
766+
767+
if ((misc & guest_mask) != 0) {
768+
misc &= PERF_RECORD_MISC_HYPERVISOR;
769+
misc |= __map__is_kernel(map)
770+
? PERF_RECORD_MISC_GUEST_KERNEL
771+
: PERF_RECORD_MISC_GUEST_USER;
772+
} else {
773+
misc &= PERF_RECORD_MISC_HYPERVISOR;
774+
misc |= __map__is_kernel(map)
775+
? PERF_RECORD_MISC_KERNEL
776+
: PERF_RECORD_MISC_USER;
777+
}
778+
}
779+
dso = map__dso(map);
780+
if (dso && !dso__hit(dso)) {
781+
dso__set_hit(dso);
782+
tool__inject_build_id(tool, sample, machine,
783+
mmap_evsel, misc, dso__long_name(dso), dso,
784+
map__flags(map));
785+
}
786+
return 0;
787+
}
788+
701789
struct mark_dso_hit_args {
702790
const struct perf_tool *tool;
791+
struct perf_sample *sample;
703792
struct machine *machine;
704-
u8 cpumode;
793+
const struct evsel *mmap_evsel;
705794
};
706795

707796
static int mark_dso_hit_callback(struct callchain_cursor_node *node, void *data)
708797
{
709798
struct mark_dso_hit_args *args = data;
710799
struct map *map = node->ms.map;
711800

712-
if (map) {
713-
struct dso *dso = map__dso(map);
714-
715-
if (dso && !dso__hit(dso)) {
716-
dso__set_hit(dso);
717-
dso__inject_build_id(dso, args->tool, args->machine,
718-
args->cpumode, map__flags(map));
719-
}
720-
}
721-
return 0;
801+
return mark_dso_hit(args->tool, args->sample, args->machine,
802+
args->mmap_evsel, map, /*sample_in_dso=*/false);
722803
}
723804

724805
int perf_event__inject_buildid(const struct perf_tool *tool, union perf_event *event,
@@ -728,10 +809,16 @@ int perf_event__inject_buildid(const struct perf_tool *tool, union perf_event *e
728809
{
729810
struct addr_location al;
730811
struct thread *thread;
812+
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
731813
struct mark_dso_hit_args args = {
732814
.tool = tool,
815+
/*
816+
* Use the parsed sample data of the sample event, which will
817+
* have a later timestamp than the mmap event.
818+
*/
819+
.sample = sample,
733820
.machine = machine,
734-
.cpumode = sample->cpumode,
821+
.mmap_evsel = inject__mmap_evsel(inject),
735822
};
736823

737824
addr_location__init(&al);
@@ -743,13 +830,8 @@ int perf_event__inject_buildid(const struct perf_tool *tool, union perf_event *e
743830
}
744831

745832
if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
746-
struct dso *dso = map__dso(al.map);
747-
748-
if (!dso__hit(dso)) {
749-
dso__set_hit(dso);
750-
dso__inject_build_id(dso, tool, machine,
751-
sample->cpumode, map__flags(al.map));
752-
}
833+
mark_dso_hit(tool, sample, machine, args.mmap_evsel, al.map,
834+
/*sample_in_dso=*/true);
753835
}
754836

755837
sample__for_each_callchain_node(thread, evsel, sample, PERF_MAX_STACK_DEPTH,
@@ -1159,17 +1241,27 @@ static int process_build_id(const struct perf_tool *tool,
11591241
static int synthesize_build_id(struct perf_inject *inject, struct dso *dso, pid_t machine_pid)
11601242
{
11611243
struct machine *machine = perf_session__findnew_machine(inject->session, machine_pid);
1162-
u8 cpumode = dso__is_in_kernel_space(dso) ?
1163-
PERF_RECORD_MISC_GUEST_KERNEL :
1164-
PERF_RECORD_MISC_GUEST_USER;
1244+
struct perf_sample synth_sample = {
1245+
.pid = -1,
1246+
.tid = -1,
1247+
.time = -1,
1248+
.stream_id = -1,
1249+
.cpu = -1,
1250+
.period = 1,
1251+
.cpumode = dso__is_in_kernel_space(dso)
1252+
? PERF_RECORD_MISC_GUEST_KERNEL
1253+
: PERF_RECORD_MISC_GUEST_USER,
1254+
};
11651255

11661256
if (!machine)
11671257
return -ENOMEM;
11681258

11691259
dso__set_hit(dso);
11701260

1171-
return perf_event__synthesize_build_id(&inject->tool, dso, cpumode,
1172-
process_build_id, machine);
1261+
return perf_event__synthesize_build_id(&inject->tool, &synth_sample, machine,
1262+
process_build_id, inject__mmap_evsel(inject),
1263+
/*misc=*/synth_sample.cpumode,
1264+
dso__bid(dso), dso__long_name(dso));
11731265
}
11741266

11751267
static int guest_session__add_build_ids_cb(struct dso *dso, void *data)

tools/perf/util/build-id.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,16 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid
277277
struct perf_record_header_build_id b;
278278
size_t len;
279279

280-
len = name_len + 1;
281-
len = PERF_ALIGN(len, NAME_ALIGN);
280+
len = sizeof(b) + name_len + 1;
281+
len = PERF_ALIGN(len, sizeof(u64));
282282

283283
memset(&b, 0, sizeof(b));
284284
memcpy(&b.data, bid->data, bid->size);
285285
b.size = (u8) bid->size;
286286
misc |= PERF_RECORD_MISC_BUILD_ID_SIZE;
287287
b.pid = pid;
288288
b.header.misc = misc;
289-
b.header.size = sizeof(b) + len;
289+
b.header.size = len;
290290

291291
err = do_write(fd, &b, sizeof(b));
292292
if (err < 0)

tools/perf/util/synthetic-events.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,28 +2225,48 @@ int perf_event__synthesize_tracing_data(const struct perf_tool *tool, int fd, st
22252225
}
22262226
#endif
22272227

2228-
int perf_event__synthesize_build_id(const struct perf_tool *tool, struct dso *pos, u16 misc,
2229-
perf_event__handler_t process, struct machine *machine)
2228+
int perf_event__synthesize_build_id(const struct perf_tool *tool,
2229+
struct perf_sample *sample,
2230+
struct machine *machine,
2231+
perf_event__handler_t process,
2232+
const struct evsel *evsel,
2233+
__u16 misc,
2234+
const struct build_id *bid,
2235+
const char *filename)
22302236
{
22312237
union perf_event ev;
22322238
size_t len;
22332239

2234-
if (!dso__hit(pos))
2235-
return 0;
2240+
len = sizeof(ev.build_id) + strlen(filename) + 1;
2241+
len = PERF_ALIGN(len, sizeof(u64));
22362242

2237-
memset(&ev, 0, sizeof(ev));
2243+
memset(&ev, 0, len);
22382244

2239-
len = dso__long_name_len(pos) + 1;
2240-
len = PERF_ALIGN(len, NAME_ALIGN);
2241-
ev.build_id.size = min(dso__bid(pos)->size, sizeof(dso__bid(pos)->data));
2242-
memcpy(&ev.build_id.build_id, dso__bid(pos)->data, ev.build_id.size);
2245+
ev.build_id.size = min(bid->size, sizeof(ev.build_id.build_id));
2246+
memcpy(ev.build_id.build_id, bid->data, ev.build_id.size);
22432247
ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
22442248
ev.build_id.header.misc = misc | PERF_RECORD_MISC_BUILD_ID_SIZE;
22452249
ev.build_id.pid = machine->pid;
2246-
ev.build_id.header.size = sizeof(ev.build_id) + len;
2247-
memcpy(&ev.build_id.filename, dso__long_name(pos), dso__long_name_len(pos));
2250+
ev.build_id.header.size = len;
2251+
strcpy(ev.build_id.filename, filename);
2252+
2253+
if (evsel) {
2254+
void *array = &ev;
2255+
int ret;
22482256

2249-
return process(tool, &ev, NULL, machine);
2257+
array += ev.header.size;
2258+
ret = perf_event__synthesize_id_sample(array, evsel->core.attr.sample_type, sample);
2259+
if (ret < 0)
2260+
return ret;
2261+
2262+
if (ret & 7) {
2263+
pr_err("Bad id sample size %d\n", ret);
2264+
return -EINVAL;
2265+
}
2266+
2267+
ev.header.size += ret;
2268+
}
2269+
return process(tool, &ev, sample, machine);
22502270
}
22512271

22522272
int perf_event__synthesize_stat_events(struct perf_stat_config *config, const struct perf_tool *tool,

tools/perf/util/synthetic-events.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <perf/cpumap.h>
1010

1111
struct auxtrace_record;
12+
struct build_id;
1213
struct dso;
1314
struct evlist;
1415
struct evsel;
@@ -45,7 +46,14 @@ typedef int (*perf_event__handler_t)(const struct perf_tool *tool, union perf_ev
4546

4647
int perf_event__synthesize_attrs(const struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process);
4748
int perf_event__synthesize_attr(const struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process);
48-
int perf_event__synthesize_build_id(const struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine);
49+
int perf_event__synthesize_build_id(const struct perf_tool *tool,
50+
struct perf_sample *sample,
51+
struct machine *machine,
52+
perf_event__handler_t process,
53+
const struct evsel *evsel,
54+
__u16 misc,
55+
const struct build_id *bid,
56+
const char *filename);
4957
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);
5058
int perf_event__synthesize_event_update_cpus(const struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
5159
int perf_event__synthesize_event_update_name(const struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);

0 commit comments

Comments
 (0)