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

Configure Feed

Select the types of activity you want to include in your feed.

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/Z9YHCzINiu4uBQ8B@google.com/
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 <irogers@google.com>
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Link: https://lore.kernel.org/r/20250319050741.269828-13-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
ccc60dce 95b802ca

+54 -35
+54 -35
tools/perf/builtin-trace.c
··· 151 151 struct perf_tool tool; 152 152 struct { 153 153 /** Sorted sycall numbers used by the trace. */ 154 - struct syscall *table; 154 + struct syscall **table; 155 155 /** Size of table. */ 156 156 size_t table_size; 157 157 struct { ··· 2473 2473 return printed; 2474 2474 } 2475 2475 2476 - static void syscall__init(struct syscall *sc, int e_machine, int id) 2476 + static struct syscall *syscall__new(int e_machine, int id) 2477 2477 { 2478 - memset(sc, 0, sizeof(*sc)); 2478 + struct syscall *sc = zalloc(sizeof(*sc)); 2479 + 2480 + if (!sc) 2481 + return NULL; 2482 + 2479 2483 sc->e_machine = e_machine; 2480 2484 sc->id = id; 2485 + return sc; 2481 2486 } 2482 2487 2483 - static void syscall__exit(struct syscall *sc) 2488 + static void syscall__delete(struct syscall *sc) 2484 2489 { 2485 2490 if (!sc) 2486 2491 return; 2487 2492 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; 2489 2505 } 2490 2506 2491 2507 static int syscall__cmp(const void *va, const void *vb) 2492 2508 { 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); 2494 2511 2495 2512 if (a->e_machine != b->e_machine) 2496 2513 return a->e_machine - b->e_machine; ··· 2521 2504 .e_machine = e_machine, 2522 2505 .id = id, 2523 2506 }; 2524 - struct syscall *sc, *tmp; 2507 + struct syscall *sc, **tmp; 2525 2508 2526 2509 if (trace->syscalls.table) { 2527 - sc = bsearch(&key, trace->syscalls.table, trace->syscalls.table_size, 2528 - sizeof(struct syscall), syscall__cmp); 2529 - if (sc) 2530 - return sc; 2510 + struct syscall **sc_entry = bsearch(&key, trace->syscalls.table, 2511 + trace->syscalls.table_size, 2512 + sizeof(trace->syscalls.table[0]), 2513 + syscall__bsearch_cmp); 2514 + 2515 + if (sc_entry) 2516 + return *sc_entry; 2531 2517 } 2532 2518 2533 - tmp = reallocarray(trace->syscalls.table, trace->syscalls.table_size + 1, 2534 - sizeof(struct syscall)); 2535 - if (!tmp) 2519 + sc = syscall__new(e_machine, id); 2520 + if (!sc) 2536 2521 return NULL; 2537 2522 2523 + tmp = reallocarray(trace->syscalls.table, trace->syscalls.table_size + 1, 2524 + sizeof(trace->syscalls.table[0])); 2525 + if (!tmp) { 2526 + syscall__delete(sc); 2527 + return NULL; 2528 + } 2529 + 2538 2530 trace->syscalls.table = tmp; 2539 - sc = &trace->syscalls.table[trace->syscalls.table_size++]; 2540 - syscall__init(sc, e_machine, id); 2541 - qsort(trace->syscalls.table, trace->syscalls.table_size, sizeof(struct syscall), 2531 + trace->syscalls.table[trace->syscalls.table_size++] = sc; 2532 + qsort(trace->syscalls.table, trace->syscalls.table_size, sizeof(trace->syscalls.table[0]), 2542 2533 syscall__cmp); 2543 - sc = bsearch(&key, trace->syscalls.table, trace->syscalls.table_size, 2544 - sizeof(struct syscall), syscall__cmp); 2545 2534 return sc; 2546 2535 } 2547 2536 ··· 3878 3855 return -1; 3879 3856 } 3880 3857 3881 - static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *_sc) 3858 + static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, 3859 + struct syscall *sc) 3882 3860 { 3883 - struct syscall sc = *_sc; /* Copy as trace__syscall_info may invalidate pointer. */ 3884 3861 struct tep_format_field *field, *candidate_field; 3885 3862 /* 3886 3863 * We're only interested in syscalls that have a pointer: 3887 3864 */ 3888 - for (field = sc.args; field; field = field->next) { 3865 + for (field = sc->args; field; field = field->next) { 3889 3866 if (field->flags & TEP_FIELD_IS_POINTER) 3890 3867 goto try_to_find_pair; 3891 3868 } ··· 3893 3870 return NULL; 3894 3871 3895 3872 try_to_find_pair: 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 - /* calling trace__syscall_info() may invalidate '_sc' */ 3899 - struct syscall *pair = trace__syscall_info(trace, NULL, sc.e_machine, id); 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 + struct syscall *pair = trace__syscall_info(trace, NULL, sc->e_machine, id); 3900 3876 struct bpf_program *pair_prog; 3901 3877 bool is_candidate = false; 3902 3878 3903 - if (pair == NULL || pair->id == sc.id || 3879 + if (pair == NULL || pair->id == sc->id || 3904 3880 pair->bpf_prog.sys_enter == trace->skel->progs.syscall_unaugmented) 3905 3881 continue; 3906 3882 3907 - for (field = sc.args, candidate_field = pair->args; 3883 + for (field = sc->args, candidate_field = pair->args; 3908 3884 field && candidate_field; field = field->next, candidate_field = candidate_field->next) { 3909 3885 bool is_pointer = field->flags & TEP_FIELD_IS_POINTER, 3910 3886 candidate_is_pointer = candidate_field->flags & TEP_FIELD_IS_POINTER; ··· 3970 3948 goto next_candidate; 3971 3949 } 3972 3950 3973 - pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name, sc.name); 3951 + pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name, 3952 + sc->name); 3974 3953 return pair_prog; 3975 3954 next_candidate: 3976 3955 continue; ··· 4067 4044 pair_prog = trace__find_usable_bpf_prog_entry(trace, sc); 4068 4045 if (pair_prog == NULL) 4069 4046 continue; 4070 - /* 4071 - * Get syscall info again as find usable entry above might 4072 - * modify the syscall table and shuffle it. 4073 - */ 4074 - sc = trace__syscall_info(trace, NULL, e_machine, key); 4047 + 4075 4048 sc->bpf_prog.sys_enter = pair_prog; 4076 4049 4077 4050 /* ··· 5335 5316 zfree(&trace->ev_qualifier_ids.entries); 5336 5317 if (trace->syscalls.table) { 5337 5318 for (size_t i = 0; i < trace->syscalls.table_size; i++) 5338 - syscall__exit(&trace->syscalls.table[i]); 5319 + syscall__delete(trace->syscalls.table[i]); 5339 5320 zfree(&trace->syscalls.table); 5340 5321 } 5341 5322 zfree(&trace->perfconfig_events);