Skip to content

Commit ccc60dc

Browse files
captain5050namhyung
authored andcommitted
perf trace: Make syscall table stable
Namhyung fixed the syscall table being reallocated and moving by reloading the system call pointer after a move: https://lore.kernel.org/lkml/[email protected]/ This could be brittle so this patch changes the syscall table to be an array of pointers of "struct syscall" that don't move. Remove unnecessary copies and searches with this change. Signed-off-by: Ian Rogers <[email protected]> Reviewed-by: Namhyung Kim <[email protected]> Acked-by: Arnaldo Carvalho de Melo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent 95b802c commit ccc60dc

File tree

1 file changed

+53
-34
lines changed

1 file changed

+53
-34
lines changed

tools/perf/builtin-trace.c

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ struct trace {
151151
struct perf_tool tool;
152152
struct {
153153
/** Sorted sycall numbers used by the trace. */
154-
struct syscall *table;
154+
struct syscall **table;
155155
/** Size of table. */
156156
size_t table_size;
157157
struct {
@@ -2473,24 +2473,41 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
24732473
return printed;
24742474
}
24752475

2476-
static void syscall__init(struct syscall *sc, int e_machine, int id)
2476+
static struct syscall *syscall__new(int e_machine, int id)
24772477
{
2478-
memset(sc, 0, sizeof(*sc));
2478+
struct syscall *sc = zalloc(sizeof(*sc));
2479+
2480+
if (!sc)
2481+
return NULL;
2482+
24792483
sc->e_machine = e_machine;
24802484
sc->id = id;
2485+
return sc;
24812486
}
24822487

2483-
static void syscall__exit(struct syscall *sc)
2488+
static void syscall__delete(struct syscall *sc)
24842489
{
24852490
if (!sc)
24862491
return;
24872492

2488-
zfree(&sc->arg_fmt);
2493+
free(sc->arg_fmt);
2494+
free(sc);
2495+
}
2496+
2497+
static int syscall__bsearch_cmp(const void *key, const void *entry)
2498+
{
2499+
const struct syscall *a = key, *b = *((const struct syscall **)entry);
2500+
2501+
if (a->e_machine != b->e_machine)
2502+
return a->e_machine - b->e_machine;
2503+
2504+
return a->id - b->id;
24892505
}
24902506

24912507
static int syscall__cmp(const void *va, const void *vb)
24922508
{
2493-
const struct syscall *a = va, *b = vb;
2509+
const struct syscall *a = *((const struct syscall **)va);
2510+
const struct syscall *b = *((const struct syscall **)vb);
24942511

24952512
if (a->e_machine != b->e_machine)
24962513
return a->e_machine - b->e_machine;
@@ -2504,27 +2521,33 @@ static struct syscall *trace__find_syscall(struct trace *trace, int e_machine, i
25042521
.e_machine = e_machine,
25052522
.id = id,
25062523
};
2507-
struct syscall *sc, *tmp;
2524+
struct syscall *sc, **tmp;
25082525

25092526
if (trace->syscalls.table) {
2510-
sc = bsearch(&key, trace->syscalls.table, trace->syscalls.table_size,
2511-
sizeof(struct syscall), syscall__cmp);
2512-
if (sc)
2513-
return sc;
2527+
struct syscall **sc_entry = bsearch(&key, trace->syscalls.table,
2528+
trace->syscalls.table_size,
2529+
sizeof(trace->syscalls.table[0]),
2530+
syscall__bsearch_cmp);
2531+
2532+
if (sc_entry)
2533+
return *sc_entry;
25142534
}
25152535

2536+
sc = syscall__new(e_machine, id);
2537+
if (!sc)
2538+
return NULL;
2539+
25162540
tmp = reallocarray(trace->syscalls.table, trace->syscalls.table_size + 1,
2517-
sizeof(struct syscall));
2518-
if (!tmp)
2541+
sizeof(trace->syscalls.table[0]));
2542+
if (!tmp) {
2543+
syscall__delete(sc);
25192544
return NULL;
2545+
}
25202546

25212547
trace->syscalls.table = tmp;
2522-
sc = &trace->syscalls.table[trace->syscalls.table_size++];
2523-
syscall__init(sc, e_machine, id);
2524-
qsort(trace->syscalls.table, trace->syscalls.table_size, sizeof(struct syscall),
2548+
trace->syscalls.table[trace->syscalls.table_size++] = sc;
2549+
qsort(trace->syscalls.table, trace->syscalls.table_size, sizeof(trace->syscalls.table[0]),
25252550
syscall__cmp);
2526-
sc = bsearch(&key, trace->syscalls.table, trace->syscalls.table_size,
2527-
sizeof(struct syscall), syscall__cmp);
25282551
return sc;
25292552
}
25302553

@@ -3855,33 +3878,32 @@ static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int e_machine, i
38553878
return -1;
38563879
}
38573880

3858-
static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *_sc)
3881+
static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace,
3882+
struct syscall *sc)
38593883
{
3860-
struct syscall sc = *_sc; /* Copy as trace__syscall_info may invalidate pointer. */
38613884
struct tep_format_field *field, *candidate_field;
38623885
/*
38633886
* We're only interested in syscalls that have a pointer:
38643887
*/
3865-
for (field = sc.args; field; field = field->next) {
3888+
for (field = sc->args; field; field = field->next) {
38663889
if (field->flags & TEP_FIELD_IS_POINTER)
38673890
goto try_to_find_pair;
38683891
}
38693892

38703893
return NULL;
38713894

38723895
try_to_find_pair:
3873-
for (int i = 0, num_idx = syscalltbl__num_idx(sc.e_machine); i < num_idx; ++i) {
3874-
int id = syscalltbl__id_at_idx(sc.e_machine, i);
3875-
/* calling trace__syscall_info() may invalidate '_sc' */
3876-
struct syscall *pair = trace__syscall_info(trace, NULL, sc.e_machine, id);
3896+
for (int i = 0, num_idx = syscalltbl__num_idx(sc->e_machine); i < num_idx; ++i) {
3897+
int id = syscalltbl__id_at_idx(sc->e_machine, i);
3898+
struct syscall *pair = trace__syscall_info(trace, NULL, sc->e_machine, id);
38773899
struct bpf_program *pair_prog;
38783900
bool is_candidate = false;
38793901

3880-
if (pair == NULL || pair->id == sc.id ||
3902+
if (pair == NULL || pair->id == sc->id ||
38813903
pair->bpf_prog.sys_enter == trace->skel->progs.syscall_unaugmented)
38823904
continue;
38833905

3884-
for (field = sc.args, candidate_field = pair->args;
3906+
for (field = sc->args, candidate_field = pair->args;
38853907
field && candidate_field; field = field->next, candidate_field = candidate_field->next) {
38863908
bool is_pointer = field->flags & TEP_FIELD_IS_POINTER,
38873909
candidate_is_pointer = candidate_field->flags & TEP_FIELD_IS_POINTER;
@@ -3948,7 +3970,8 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace
39483970
goto next_candidate;
39493971
}
39503972

3951-
pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name, sc.name);
3973+
pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name,
3974+
sc->name);
39523975
return pair_prog;
39533976
next_candidate:
39543977
continue;
@@ -4044,11 +4067,7 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace, int e_m
40444067
pair_prog = trace__find_usable_bpf_prog_entry(trace, sc);
40454068
if (pair_prog == NULL)
40464069
continue;
4047-
/*
4048-
* Get syscall info again as find usable entry above might
4049-
* modify the syscall table and shuffle it.
4050-
*/
4051-
sc = trace__syscall_info(trace, NULL, e_machine, key);
4070+
40524071
sc->bpf_prog.sys_enter = pair_prog;
40534072

40544073
/*
@@ -5316,7 +5335,7 @@ static void trace__exit(struct trace *trace)
53165335
zfree(&trace->ev_qualifier_ids.entries);
53175336
if (trace->syscalls.table) {
53185337
for (size_t i = 0; i < trace->syscalls.table_size; i++)
5319-
syscall__exit(&trace->syscalls.table[i]);
5338+
syscall__delete(trace->syscalls.table[i]);
53205339
zfree(&trace->syscalls.table);
53215340
}
53225341
zfree(&trace->perfconfig_events);

0 commit comments

Comments
 (0)