Message ID | 20250210165108.95894-4-irogers@google.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | perf: Support multiple system call tables in the build | expand |
Context | Check | Description |
---|---|---|
bjorn/pre-ci_am | success | Success |
bjorn/build-rv32-defconfig | success | build-rv32-defconfig |
bjorn/build-rv64-clang-allmodconfig | success | build-rv64-clang-allmodconfig |
bjorn/build-rv64-gcc-allmodconfig | success | build-rv64-gcc-allmodconfig |
bjorn/build-rv64-nommu-k210-defconfig | success | build-rv64-nommu-k210-defconfig |
bjorn/build-rv64-nommu-k210-virt | success | build-rv64-nommu-k210-virt |
bjorn/checkpatch | warning | checkpatch |
bjorn/dtb-warn-rv64 | success | dtb-warn-rv64 |
bjorn/header-inline | success | header-inline |
bjorn/kdoc | success | kdoc |
bjorn/module-param | success | module-param |
bjorn/verify-fixes | success | verify-fixes |
bjorn/verify-signedoff | success | verify-signedoff |
On Mon, Feb 10, 2025 at 08:51:04AM -0800, Ian Rogers wrote: > The syscalltbl held entries of system call name and number pairs, > generated from a native syscalltbl at start up. As there are gaps in > the system call number there is a notion of index into the > table. Going forward we want the system call table to be identifiable > by a machine type, for example, i386 vs x86-64. Change the interface > to the syscalltbl so (1) a (currently unused machine type of EM_HOST) > is passed (2) the index to syscall number and system call name mapping > is computed at build time. > > Two tables are used for this, an array of system call number to name, > an array of system call numbers sorted by the system call name. The > sorted array doesn't store strings in part to save memory and > relocations. The index notion is carried forward and is an index into > the sorted array of system call numbers, the data structures are > opaque (held only in syscalltbl.c), and so the number of indices for a > machine type is exposed as a new API. > > The arrays are computed in the syscalltbl.sh script and so no start-up > time computation and storage is necessary. Thank you for also generating the sorted table, that is a very nice addition. Reviewed-by: Charlie Jenkins <charlie@rivosinc.com> Tested-by: Charlie Jenkins <charlie@rivosinc.com> > > Signed-off-by: Ian Rogers <irogers@google.com> > Reviewed-by: Howard Chu <howardchu95@gmail.com> > --- > tools/perf/builtin-trace.c | 88 +++++++++++++----------- > tools/perf/scripts/syscalltbl.sh | 36 ++++------ > tools/perf/util/syscalltbl.c | 113 ++++++++++--------------------- > tools/perf/util/syscalltbl.h | 22 ++---- > 4 files changed, 103 insertions(+), 156 deletions(-) > > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c > index 916a51df236b..4b77c2ab3dba 100644 > --- a/tools/perf/builtin-trace.c > +++ b/tools/perf/builtin-trace.c > @@ -143,7 +143,6 @@ struct syscall_fmt { > > struct trace { > struct perf_tool tool; > - struct syscalltbl *sctbl; > struct { > /** Sorted sycall numbers used by the trace. */ > struct syscall *table; > @@ -2100,7 +2099,7 @@ static int syscall__read_info(struct syscall *sc, struct trace *trace) > return 0; > } > > - name = syscalltbl__name(trace->sctbl, sc->id); > + name = syscalltbl__name(sc->e_machine, sc->id); > if (name == NULL) { > sc->nonexistent = true; > return -EEXIST; > @@ -2200,10 +2199,14 @@ static int trace__validate_ev_qualifier(struct trace *trace) > > strlist__for_each_entry(pos, trace->ev_qualifier) { > const char *sc = pos->s; > - int id = syscalltbl__id(trace->sctbl, sc), match_next = -1; > + /* > + * TODO: Assume more than the validation/warnings are all for > + * the same binary type as perf. > + */ > + int id = syscalltbl__id(EM_HOST, sc), match_next = -1; > > if (id < 0) { > - id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next); > + id = syscalltbl__strglobmatch_first(EM_HOST, sc, &match_next); > if (id >= 0) > goto matches; > > @@ -2223,7 +2226,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) > continue; > > while (1) { > - id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next); > + id = syscalltbl__strglobmatch_next(EM_HOST, sc, &match_next); > if (id < 0) > break; > if (nr_allocated == nr_used) { > @@ -2677,6 +2680,7 @@ static int trace__sys_enter(struct trace *trace, struct evsel *evsel, > int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; > int augmented_args_size = 0; > void *augmented_args = NULL; > + /* TODO: get e_machine from thread. */ > struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); > struct thread_trace *ttrace; > > @@ -2751,6 +2755,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, > struct thread_trace *ttrace; > struct thread *thread; > int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; > + /* TODO: get e_machine from thread. */ > struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); > char msg[1024]; > void *args, *augmented_args = NULL; > @@ -2826,6 +2831,7 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel, > struct thread *thread; > int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0, printed = 0; > int alignment = trace->args_alignment; > + /* TODO: get e_machine from thread. */ > struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); > struct thread_trace *ttrace; > > @@ -3179,6 +3185,7 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel, > > if (evsel == trace->syscalls.events.bpf_output) { > int id = perf_evsel__sc_tp_uint(evsel, id, sample); > + /* TODO: get e_machine from thread. */ > struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); > > if (sc) { > @@ -3682,9 +3689,9 @@ static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace, str > return trace->skel->progs.syscall_unaugmented; > } > > -static void trace__init_syscall_bpf_progs(struct trace *trace, int id) > +static void trace__init_syscall_bpf_progs(struct trace *trace, int e_machine, int id) > { > - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); > + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); > > if (sc == NULL) > return; > @@ -3693,22 +3700,22 @@ static void trace__init_syscall_bpf_progs(struct trace *trace, int id) > sc->bpf_prog.sys_exit = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_exit : NULL, "exit"); > } > > -static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int id) > +static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int e_machine, int id) > { > - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); > + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); > return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); > } > > -static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id) > +static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int e_machine, int id) > { > - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); > + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); > return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); > } > > -static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int key, unsigned int *beauty_array) > +static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int e_machine, int key, unsigned int *beauty_array) > { > struct tep_format_field *field; > - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, key); > + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key); > const struct btf_type *bt; > char *struct_offset, *tmp, name[32]; > bool can_augment = false; > @@ -3804,9 +3811,9 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace > return NULL; > > try_to_find_pair: > - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { > - int id = syscalltbl__id_at_idx(trace->sctbl, i); > - struct syscall *pair = trace__syscall_info(trace, NULL, EM_HOST, id); > + for (int i = 0, num_idx = syscalltbl__num_idx(sc->e_machine); i < num_idx; ++i) { > + int id = syscalltbl__id_at_idx(sc->e_machine, i); > + struct syscall *pair = trace__syscall_info(trace, NULL, sc->e_machine, id); > struct bpf_program *pair_prog; > bool is_candidate = false; > > @@ -3890,7 +3897,7 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace > return NULL; > } > > -static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) > +static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace, int e_machine) > { > int map_enter_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_enter); > int map_exit_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_exit); > @@ -3898,27 +3905,27 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) > int err = 0; > unsigned int beauty_array[6]; > > - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { > - int prog_fd, key = syscalltbl__id_at_idx(trace->sctbl, i); > + for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) { > + int prog_fd, key = syscalltbl__id_at_idx(e_machine, i); > > if (!trace__syscall_enabled(trace, key)) > continue; > > - trace__init_syscall_bpf_progs(trace, key); > + trace__init_syscall_bpf_progs(trace, e_machine, key); > > // It'll get at least the "!raw_syscalls:unaugmented" > - prog_fd = trace__bpf_prog_sys_enter_fd(trace, key); > + prog_fd = trace__bpf_prog_sys_enter_fd(trace, e_machine, key); > err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY); > if (err) > break; > - prog_fd = trace__bpf_prog_sys_exit_fd(trace, key); > + prog_fd = trace__bpf_prog_sys_exit_fd(trace, e_machine, key); > err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY); > if (err) > break; > > /* use beauty_map to tell BPF how many bytes to collect, set beauty_map's value here */ > memset(beauty_array, 0, sizeof(beauty_array)); > - err = trace__bpf_sys_enter_beauty_map(trace, key, (unsigned int *)beauty_array); > + err = trace__bpf_sys_enter_beauty_map(trace, e_machine, key, (unsigned int *)beauty_array); > if (err) > continue; > err = bpf_map_update_elem(beauty_map_fd, &key, beauty_array, BPF_ANY); > @@ -3954,9 +3961,9 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) > * first and second arg (this one on the raw_syscalls:sys_exit prog > * array tail call, then that one will be used. > */ > - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { > - int key = syscalltbl__id_at_idx(trace->sctbl, i); > - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, key); > + for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) { > + int key = syscalltbl__id_at_idx(e_machine, i); > + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key); > struct bpf_program *pair_prog; > int prog_fd; > > @@ -4393,8 +4400,13 @@ static int trace__run(struct trace *trace, int argc, const char **argv) > goto out_error_mem; > > #ifdef HAVE_BPF_SKEL > - if (trace->skel && trace->skel->progs.sys_enter) > - trace__init_syscalls_bpf_prog_array_maps(trace); > + if (trace->skel && trace->skel->progs.sys_enter) { > + /* > + * TODO: Initialize for all host binary machine types, not just > + * those matching the perf binary. > + */ > + trace__init_syscalls_bpf_prog_array_maps(trace, EM_HOST); > + } > #endif > > if (trace->ev_qualifier_ids.nr > 0) { > @@ -4419,7 +4431,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) > * So just disable this beautifier (SCA_FD, SCA_FDAT) when 'close' is > * not in use. > */ > - trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(trace->sctbl, "close")); > + /* TODO: support for more than just perf binary machine type close. */ > + trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(EM_HOST, "close")); > > err = trace__expand_filters(trace, &evsel); > if (err) > @@ -4692,8 +4705,7 @@ DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs, > entry->msecs = stats ? (u64)stats->stats.n * (avg_stats(&stats->stats) / NSEC_PER_MSEC) : 0; > } > > -static size_t thread__dump_stats(struct thread_trace *ttrace, > - struct trace *trace, FILE *fp) > +static size_t thread__dump_stats(struct thread_trace *ttrace, struct trace *trace, int e_machine, FILE *fp) > { > size_t printed = 0; > struct syscall *sc; > @@ -4721,7 +4733,7 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, > pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0; > avg /= NSEC_PER_MSEC; > > - sc = trace__syscall_info(trace, /*evsel=*/NULL, EM_HOST, > + sc = trace__syscall_info(trace, /*evsel=*/NULL, e_machine, > syscall_stats_entry->syscall); > if (!sc) > continue; > @@ -4771,7 +4783,8 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac > else if (fputc('\n', fp) != EOF) > ++printed; > > - printed += thread__dump_stats(ttrace, trace, fp); > + /* TODO: get e_machine from thread. */ > + printed += thread__dump_stats(ttrace, trace, EM_HOST, fp); > > return printed; > } > @@ -5003,8 +5016,9 @@ static int trace__parse_events_option(const struct option *opt, const char *str, > *sep = '\0'; > > list = 0; > - if (syscalltbl__id(trace->sctbl, s) >= 0 || > - syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { > + /* TODO: support for more than just perf binary machine type syscalls. */ > + if (syscalltbl__id(EM_HOST, s) >= 0 || > + syscalltbl__strglobmatch_first(EM_HOST, s, &idx) >= 0) { > list = 1; > goto do_concat; > } > @@ -5140,7 +5154,6 @@ static void trace__exit(struct trace *trace) > syscall__exit(&trace->syscalls.table[i]); > zfree(&trace->syscalls.table); > } > - syscalltbl__delete(trace->sctbl); > zfree(&trace->perfconfig_events); > } > > @@ -5286,9 +5299,8 @@ int cmd_trace(int argc, const char **argv) > sigaction(SIGCHLD, &sigchld_act, NULL); > > trace.evlist = evlist__new(); > - trace.sctbl = syscalltbl__new(); > > - if (trace.evlist == NULL || trace.sctbl == NULL) { > + if (trace.evlist == NULL) { > pr_err("Not enough memory to run!\n"); > err = -ENOMEM; > goto out; > diff --git a/tools/perf/scripts/syscalltbl.sh b/tools/perf/scripts/syscalltbl.sh > index 1ce0d5aa8b50..a39b3013b103 100755 > --- a/tools/perf/scripts/syscalltbl.sh > +++ b/tools/perf/scripts/syscalltbl.sh > @@ -50,37 +50,27 @@ fi > infile="$1" > outfile="$2" > > -nxt=0 > - > -syscall_macro() { > - nr="$1" > - name="$2" > - > - echo " [$nr] = \"$name\"," > -} > - > -emit() { > - nr="$1" > - entry="$2" > - > - syscall_macro "$nr" "$entry" > -} > - > -echo "static const char *const syscalltbl[] = {" > $outfile > - > sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX) > grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n > $sorted_table > > -max_nr=0 > +echo "static const char *const syscall_num_to_name[] = {" > $outfile > # the params are: nr abi name entry compat > # use _ for intentionally unused variables according to SC2034 > while read nr _ name _ _; do > - emit "$nr" "$name" >> $outfile > - max_nr=$nr > + echo " [$nr] = \"$name\"," >> $outfile > done < $sorted_table > +echo "};" >> $outfile > > -rm -f $sorted_table > +echo "static const uint16_t syscall_sorted_names[] = {" >> $outfile > > +# When sorting by name, add a suffix of 0s upto 20 characters so that system > +# calls that differ with a numerical suffix don't sort before those > +# without. This default behavior of sort differs from that of strcmp used at > +# runtime. Use sed to strip the trailing 0s suffix afterwards. > +grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | awk '{printf $3; for (i = length($3); i < 20; i++) { printf "0"; }; print " " $1}'| sort | sed 's/\([a-zA-Z1-9]\+\)0\+ \([0-9]\+\)/\1 \2/' > $sorted_table > +while read name nr; do > + echo " $nr, /* $name */" >> $outfile > +done < $sorted_table > echo "};" >> $outfile > > -echo "#define SYSCALLTBL_MAX_ID ${max_nr}" >> $outfile > +rm -f $sorted_table > diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c > index 2f76241494c8..760ac4d0869f 100644 > --- a/tools/perf/util/syscalltbl.c > +++ b/tools/perf/util/syscalltbl.c > @@ -9,6 +9,7 @@ > #include <stdlib.h> > #include <asm/bitsperlong.h> > #include <linux/compiler.h> > +#include <linux/kernel.h> > #include <linux/zalloc.h> > > #include <string.h> > @@ -20,112 +21,66 @@ > #include <asm/syscalls_32.h> > #endif > > -const int syscalltbl_native_max_id = SYSCALLTBL_MAX_ID; > -static const char *const *syscalltbl_native = syscalltbl; > +const char *syscalltbl__name(int e_machine __maybe_unused, int id) > +{ > + if (id >= 0 && id <= (int)ARRAY_SIZE(syscall_num_to_name)) > + return syscall_num_to_name[id]; > + return NULL; > +} > > -struct syscall { > - int id; > +struct syscall_cmp_key { > const char *name; > + const char *const *tbl; > }; > > static int syscallcmpname(const void *vkey, const void *ventry) > { > - const char *key = vkey; > - const struct syscall *entry = ventry; > + const struct syscall_cmp_key *key = vkey; > + const uint16_t *entry = ventry; > > - return strcmp(key, entry->name); > + return strcmp(key->name, key->tbl[*entry]); > } > > -static int syscallcmp(const void *va, const void *vb) > +int syscalltbl__id(int e_machine __maybe_unused, const char *name) > { > - const struct syscall *a = va, *b = vb; > - > - return strcmp(a->name, b->name); > + struct syscall_cmp_key key = { > + .name = name, > + .tbl = syscall_num_to_name, > + }; > + const int *id = bsearch(&key, syscall_sorted_names, > + ARRAY_SIZE(syscall_sorted_names), > + sizeof(syscall_sorted_names[0]), > + syscallcmpname); > + > + return id ? *id : -1; > } > > -static int syscalltbl__init_native(struct syscalltbl *tbl) > +int syscalltbl__num_idx(int e_machine __maybe_unused) > { > - int nr_entries = 0, i, j; > - struct syscall *entries; > - > - for (i = 0; i <= syscalltbl_native_max_id; ++i) > - if (syscalltbl_native[i]) > - ++nr_entries; > - > - entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries); > - if (tbl->syscalls.entries == NULL) > - return -1; > - > - for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) { > - if (syscalltbl_native[i]) { > - entries[j].name = syscalltbl_native[i]; > - entries[j].id = i; > - ++j; > - } > - } > - > - qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); > - tbl->syscalls.nr_entries = nr_entries; > - tbl->syscalls.max_id = syscalltbl_native_max_id; > - return 0; > + return ARRAY_SIZE(syscall_sorted_names); > } > > -struct syscalltbl *syscalltbl__new(void) > +int syscalltbl__id_at_idx(int e_machine __maybe_unused, int idx) > { > - struct syscalltbl *tbl = malloc(sizeof(*tbl)); > - if (tbl) { > - if (syscalltbl__init_native(tbl)) { > - free(tbl); > - return NULL; > - } > - } > - return tbl; > -} > - > -void syscalltbl__delete(struct syscalltbl *tbl) > -{ > - zfree(&tbl->syscalls.entries); > - free(tbl); > -} > - > -const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id) > -{ > - return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL; > -} > - > -int syscalltbl__id(struct syscalltbl *tbl, const char *name) > -{ > - struct syscall *sc = bsearch(name, tbl->syscalls.entries, > - tbl->syscalls.nr_entries, sizeof(*sc), > - syscallcmpname); > - > - return sc ? sc->id : -1; > -} > - > -int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx) > -{ > - struct syscall *syscalls = tbl->syscalls.entries; > - > - return idx < tbl->syscalls.nr_entries ? syscalls[idx].id : -1; > + return syscall_sorted_names[idx]; > } > > -int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx) > +int syscalltbl__strglobmatch_next(int e_machine __maybe_unused, const char *syscall_glob, int *idx) > { > - int i; > - struct syscall *syscalls = tbl->syscalls.entries; > + for (int i = *idx + 1; i < (int)ARRAY_SIZE(syscall_sorted_names); ++i) { > + const char *name = syscall_num_to_name[syscall_sorted_names[i]]; > > - for (i = *idx + 1; i < tbl->syscalls.nr_entries; ++i) { > - if (strglobmatch(syscalls[i].name, syscall_glob)) { > + if (strglobmatch(name, syscall_glob)) { > *idx = i; > - return syscalls[i].id; > + return syscall_sorted_names[i]; > } > } > > return -1; > } > > -int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx) > +int syscalltbl__strglobmatch_first(int e_machine, const char *syscall_glob, int *idx) > { > *idx = -1; > - return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx); > + return syscalltbl__strglobmatch_next(e_machine, syscall_glob, idx); > } > diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h > index 362411a6d849..2bb628eff367 100644 > --- a/tools/perf/util/syscalltbl.h > +++ b/tools/perf/util/syscalltbl.h > @@ -2,22 +2,12 @@ > #ifndef __PERF_SYSCALLTBL_H > #define __PERF_SYSCALLTBL_H > > -struct syscalltbl { > - struct { > - int max_id; > - int nr_entries; > - void *entries; > - } syscalls; > -}; > +const char *syscalltbl__name(int e_machine, int id); > +int syscalltbl__id(int e_machine, const char *name); > +int syscalltbl__num_idx(int e_machine); > +int syscalltbl__id_at_idx(int e_machine, int idx); > > -struct syscalltbl *syscalltbl__new(void); > -void syscalltbl__delete(struct syscalltbl *tbl); > - > -const char *syscalltbl__name(const struct syscalltbl *tbl, int id); > -int syscalltbl__id(struct syscalltbl *tbl, const char *name); > -int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx); > - > -int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx); > -int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx); > +int syscalltbl__strglobmatch_first(int e_machine, const char *syscall_glob, int *idx); > +int syscalltbl__strglobmatch_next(int e_machine, const char *syscall_glob, int *idx); > > #endif /* __PERF_SYSCALLTBL_H */ > -- > 2.48.1.502.g6dc24dfdaf-goog >
On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote: > The syscalltbl held entries of system call name and number pairs, > generated from a native syscalltbl at start up. As there are gaps in > the system call number there is a notion of index into the > table. Going forward we want the system call table to be identifiable > by a machine type, for example, i386 vs x86-64. Change the interface > to the syscalltbl so (1) a (currently unused machine type of EM_HOST) > is passed (2) the index to syscall number and system call name mapping > is computed at build time. > > Two tables are used for this, an array of system call number to name, > an array of system call numbers sorted by the system call name. The > sorted array doesn't store strings in part to save memory and > relocations. The index notion is carried forward and is an index into > the sorted array of system call numbers, the data structures are > opaque (held only in syscalltbl.c), and so the number of indices for a > machine type is exposed as a new API. > > The arrays are computed in the syscalltbl.sh script and so no start-up > time computation and storage is necessary. > > Signed-off-by: Ian Rogers <irogers@google.com> > Reviewed-by: Howard Chu <howardchu95@gmail.com> Your changes look fine to me, but I noticed one part that may be wrong before and after your patch: > > -const int syscalltbl_native_max_id = SYSCALLTBL_MAX_ID; > -static const char *const *syscalltbl_native = syscalltbl; > +const char *syscalltbl__name(int e_machine __maybe_unused, int id) > +{ > + if (id >= 0 && id <= (int)ARRAY_SIZE(syscall_num_to_name)) > + return syscall_num_to_name[id]; > + return NULL; > +} The syscall numbers on mips (and previously on ia64) are offset by a large number depending on the ABI (o32/n32/n64). I assume what we want here is to have the small numbers without the offset in syscall_num_to_name[], but that requires adding the offset during the lookup. Can you check if this is handled correctly? Arnd
On Mon, Feb 10, 2025 at 11:48 PM Arnd Bergmann <arnd@arndb.de> wrote: > > On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote: > > The syscalltbl held entries of system call name and number pairs, > > generated from a native syscalltbl at start up. As there are gaps in > > the system call number there is a notion of index into the > > table. Going forward we want the system call table to be identifiable > > by a machine type, for example, i386 vs x86-64. Change the interface > > to the syscalltbl so (1) a (currently unused machine type of EM_HOST) > > is passed (2) the index to syscall number and system call name mapping > > is computed at build time. > > > > Two tables are used for this, an array of system call number to name, > > an array of system call numbers sorted by the system call name. The > > sorted array doesn't store strings in part to save memory and > > relocations. The index notion is carried forward and is an index into > > the sorted array of system call numbers, the data structures are > > opaque (held only in syscalltbl.c), and so the number of indices for a > > machine type is exposed as a new API. > > > > The arrays are computed in the syscalltbl.sh script and so no start-up > > time computation and storage is necessary. > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > Reviewed-by: Howard Chu <howardchu95@gmail.com> > > Your changes look fine to me, but I noticed one part that may > be wrong before and after your patch: > > > > > -const int syscalltbl_native_max_id = SYSCALLTBL_MAX_ID; > > -static const char *const *syscalltbl_native = syscalltbl; > > +const char *syscalltbl__name(int e_machine __maybe_unused, int id) > > +{ > > + if (id >= 0 && id <= (int)ARRAY_SIZE(syscall_num_to_name)) > > + return syscall_num_to_name[id]; > > + return NULL; > > +} > > The syscall numbers on mips (and previously on ia64) are offset by > a large number depending on the ABI (o32/n32/n64). I assume what > we want here is to have the small numbers without the offset in > syscall_num_to_name[], but that requires adding the offset during > the lookup. Can you check if this is handled correctly? Thanks Arnd! I agree the tables are large and can be sparse, they'll also be full of relocations. MIPS doesn't look like an outlier to me here: ``` #if defined(ALL_SYSCALLTBL) || defined(__mips__) static const char *const syscall_num_to_name_EM_MIPS[] = { [0] = "read", [1] = "write", [2] = "open", ... [465] = "listxattrat", [466] = "removexattrat", }; ``` For contrast x86: ``` #if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__) static const char *const syscall_num_to_name_EM_386[] = { [0] = "restart_syscall", [1] = "exit", [2] = "fork", ... [464] = "getxattrat", [465] = "listxattrat", [466] = "removexattrat", }; ``` Looking through the tables I see alpha having the highest number syscall with 572 being mseal. I don't think this is great but in the current code (on x86-64) we have in arch/x86/include/generated/asm/syscalls_64.h: ``` static const char *const syscalltbl[] = { [0] = "read", [1] = "write", [2] = "open", ... [465] = "listxattrat", [466] = "removexattrat", }; #define SYSCALLTBL_MAX_ID 466 ``` So the change is carrying forward a bad behavior, the table is still only around 4kb. We could be more aggressive in compressing the strings and pointers, for example how we compress the perf events and metrics. I think it is getting out-of-scope here as that logic is written in python, with the aid of lots of dictionaries, whilst this code is currently a shell script. It becomes more of an issue if we enable all of the tables in the build at once. Thanks, Ian
On Tue, Feb 11, 2025, at 17:18, Ian Rogers wrote: > On Mon, Feb 10, 2025 at 11:48 PM Arnd Bergmann <arnd@arndb.de> wrote: >> The syscall numbers on mips (and previously on ia64) are offset by >> a large number depending on the ABI (o32/n32/n64). I assume what >> we want here is to have the small numbers without the offset in >> syscall_num_to_name[], but that requires adding the offset during >> the lookup. Can you check if this is handled correctly? > > Thanks Arnd! I agree the tables are large and can be sparse, they'll > also be full of relocations. MIPS doesn't look like an outlier to me > here: Sorry, I should have been clearer what I meant, see arch/mips/include/uapi/asm/unistd.h: #if _MIPS_SIM == _MIPS_SIM_NABI32 #define __NR_Linux 6000 #include <asm/unistd_n32.h> #endif and arch/mips/include/generated/uapi/asm/unistd_n32.h #define __NR_read (__NR_Linux + 0) #define __NR_write (__NR_Linux + 1) #define __NR_open (__NR_Linux + 2) These offsets are 4000/5000/6000 respectively. > ``` > #if defined(ALL_SYSCALLTBL) || defined(__mips__) > static const char *const syscall_num_to_name_EM_MIPS[] = { > [0] = "read", > [1] = "write", > [2] = "open", > ... > [465] = "listxattrat", > [466] = "removexattrat", > }; This means the array is not sparse, but the numbers here do not match the syscall number argument register. The question is whether tracing on mips adds the same per-ABI offset again, or if it tries and fails to look up index 6002 for 'open'. Arnd
On Tue, Feb 11, 2025 at 8:34 AM Arnd Bergmann <arnd@arndb.de> wrote: > > On Tue, Feb 11, 2025, at 17:18, Ian Rogers wrote: > > On Mon, Feb 10, 2025 at 11:48 PM Arnd Bergmann <arnd@arndb.de> wrote: > > >> The syscall numbers on mips (and previously on ia64) are offset by > >> a large number depending on the ABI (o32/n32/n64). I assume what > >> we want here is to have the small numbers without the offset in > >> syscall_num_to_name[], but that requires adding the offset during > >> the lookup. Can you check if this is handled correctly? > > > > Thanks Arnd! I agree the tables are large and can be sparse, they'll > > also be full of relocations. MIPS doesn't look like an outlier to me > > here: > > Sorry, I should have been clearer what I meant, see > arch/mips/include/uapi/asm/unistd.h: > > #if _MIPS_SIM == _MIPS_SIM_NABI32 > #define __NR_Linux 6000 > #include <asm/unistd_n32.h> > #endif > > and > arch/mips/include/generated/uapi/asm/unistd_n32.h > > #define __NR_read (__NR_Linux + 0) > #define __NR_write (__NR_Linux + 1) > #define __NR_open (__NR_Linux + 2) > > These offsets are 4000/5000/6000 respectively. > > > ``` > > #if defined(ALL_SYSCALLTBL) || defined(__mips__) > > static const char *const syscall_num_to_name_EM_MIPS[] = { > > [0] = "read", > > [1] = "write", > > [2] = "open", > > ... > > [465] = "listxattrat", > > [466] = "removexattrat", > > }; > > This means the array is not sparse, but the numbers > here do not match the syscall number argument register. > > The question is whether tracing on mips adds the same > per-ABI offset again, or if it tries and fails to look > up index 6002 for 'open'. Thanks for clarifying. I believe it will use 6002 and be broken. I believe that'd be true without these changes too. I'm not testing on MIPS so it'd be nice to have a fix targeted at making it work. Ideally we wouldn't use __NR_Linux and instead fudge the id/system call number based on e_machine/e_flags. I think it is follow on work, especially because I don't find MIPS a very motivating use-case. Thanks, Ian
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 916a51df236b..4b77c2ab3dba 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -143,7 +143,6 @@ struct syscall_fmt { struct trace { struct perf_tool tool; - struct syscalltbl *sctbl; struct { /** Sorted sycall numbers used by the trace. */ struct syscall *table; @@ -2100,7 +2099,7 @@ static int syscall__read_info(struct syscall *sc, struct trace *trace) return 0; } - name = syscalltbl__name(trace->sctbl, sc->id); + name = syscalltbl__name(sc->e_machine, sc->id); if (name == NULL) { sc->nonexistent = true; return -EEXIST; @@ -2200,10 +2199,14 @@ static int trace__validate_ev_qualifier(struct trace *trace) strlist__for_each_entry(pos, trace->ev_qualifier) { const char *sc = pos->s; - int id = syscalltbl__id(trace->sctbl, sc), match_next = -1; + /* + * TODO: Assume more than the validation/warnings are all for + * the same binary type as perf. + */ + int id = syscalltbl__id(EM_HOST, sc), match_next = -1; if (id < 0) { - id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next); + id = syscalltbl__strglobmatch_first(EM_HOST, sc, &match_next); if (id >= 0) goto matches; @@ -2223,7 +2226,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) continue; while (1) { - id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next); + id = syscalltbl__strglobmatch_next(EM_HOST, sc, &match_next); if (id < 0) break; if (nr_allocated == nr_used) { @@ -2677,6 +2680,7 @@ static int trace__sys_enter(struct trace *trace, struct evsel *evsel, int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; int augmented_args_size = 0; void *augmented_args = NULL; + /* TODO: get e_machine from thread. */ struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); struct thread_trace *ttrace; @@ -2751,6 +2755,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, struct thread_trace *ttrace; struct thread *thread; int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; + /* TODO: get e_machine from thread. */ struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); char msg[1024]; void *args, *augmented_args = NULL; @@ -2826,6 +2831,7 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel, struct thread *thread; int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0, printed = 0; int alignment = trace->args_alignment; + /* TODO: get e_machine from thread. */ struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); struct thread_trace *ttrace; @@ -3179,6 +3185,7 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel, if (evsel == trace->syscalls.events.bpf_output) { int id = perf_evsel__sc_tp_uint(evsel, id, sample); + /* TODO: get e_machine from thread. */ struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); if (sc) { @@ -3682,9 +3689,9 @@ static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace, str return trace->skel->progs.syscall_unaugmented; } -static void trace__init_syscall_bpf_progs(struct trace *trace, int id) +static void trace__init_syscall_bpf_progs(struct trace *trace, int e_machine, int id) { - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); if (sc == NULL) return; @@ -3693,22 +3700,22 @@ static void trace__init_syscall_bpf_progs(struct trace *trace, int id) sc->bpf_prog.sys_exit = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_exit : NULL, "exit"); } -static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int id) +static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int e_machine, int id) { - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); } -static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id) +static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int e_machine, int id) { - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, id); + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id); return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); } -static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int key, unsigned int *beauty_array) +static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int e_machine, int key, unsigned int *beauty_array) { struct tep_format_field *field; - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, key); + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key); const struct btf_type *bt; char *struct_offset, *tmp, name[32]; bool can_augment = false; @@ -3804,9 +3811,9 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace return NULL; try_to_find_pair: - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { - int id = syscalltbl__id_at_idx(trace->sctbl, i); - struct syscall *pair = trace__syscall_info(trace, NULL, EM_HOST, id); + for (int i = 0, num_idx = syscalltbl__num_idx(sc->e_machine); i < num_idx; ++i) { + int id = syscalltbl__id_at_idx(sc->e_machine, i); + struct syscall *pair = trace__syscall_info(trace, NULL, sc->e_machine, id); struct bpf_program *pair_prog; bool is_candidate = false; @@ -3890,7 +3897,7 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace return NULL; } -static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) +static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace, int e_machine) { int map_enter_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_enter); int map_exit_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_exit); @@ -3898,27 +3905,27 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) int err = 0; unsigned int beauty_array[6]; - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { - int prog_fd, key = syscalltbl__id_at_idx(trace->sctbl, i); + for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) { + int prog_fd, key = syscalltbl__id_at_idx(e_machine, i); if (!trace__syscall_enabled(trace, key)) continue; - trace__init_syscall_bpf_progs(trace, key); + trace__init_syscall_bpf_progs(trace, e_machine, key); // It'll get at least the "!raw_syscalls:unaugmented" - prog_fd = trace__bpf_prog_sys_enter_fd(trace, key); + prog_fd = trace__bpf_prog_sys_enter_fd(trace, e_machine, key); err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY); if (err) break; - prog_fd = trace__bpf_prog_sys_exit_fd(trace, key); + prog_fd = trace__bpf_prog_sys_exit_fd(trace, e_machine, key); err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY); if (err) break; /* use beauty_map to tell BPF how many bytes to collect, set beauty_map's value here */ memset(beauty_array, 0, sizeof(beauty_array)); - err = trace__bpf_sys_enter_beauty_map(trace, key, (unsigned int *)beauty_array); + err = trace__bpf_sys_enter_beauty_map(trace, e_machine, key, (unsigned int *)beauty_array); if (err) continue; err = bpf_map_update_elem(beauty_map_fd, &key, beauty_array, BPF_ANY); @@ -3954,9 +3961,9 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) * first and second arg (this one on the raw_syscalls:sys_exit prog * array tail call, then that one will be used. */ - for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) { - int key = syscalltbl__id_at_idx(trace->sctbl, i); - struct syscall *sc = trace__syscall_info(trace, NULL, EM_HOST, key); + for (int i = 0, num_idx = syscalltbl__num_idx(e_machine); i < num_idx; ++i) { + int key = syscalltbl__id_at_idx(e_machine, i); + struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, key); struct bpf_program *pair_prog; int prog_fd; @@ -4393,8 +4400,13 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out_error_mem; #ifdef HAVE_BPF_SKEL - if (trace->skel && trace->skel->progs.sys_enter) - trace__init_syscalls_bpf_prog_array_maps(trace); + if (trace->skel && trace->skel->progs.sys_enter) { + /* + * TODO: Initialize for all host binary machine types, not just + * those matching the perf binary. + */ + trace__init_syscalls_bpf_prog_array_maps(trace, EM_HOST); + } #endif if (trace->ev_qualifier_ids.nr > 0) { @@ -4419,7 +4431,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) * So just disable this beautifier (SCA_FD, SCA_FDAT) when 'close' is * not in use. */ - trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(trace->sctbl, "close")); + /* TODO: support for more than just perf binary machine type close. */ + trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(EM_HOST, "close")); err = trace__expand_filters(trace, &evsel); if (err) @@ -4692,8 +4705,7 @@ DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs, entry->msecs = stats ? (u64)stats->stats.n * (avg_stats(&stats->stats) / NSEC_PER_MSEC) : 0; } -static size_t thread__dump_stats(struct thread_trace *ttrace, - struct trace *trace, FILE *fp) +static size_t thread__dump_stats(struct thread_trace *ttrace, struct trace *trace, int e_machine, FILE *fp) { size_t printed = 0; struct syscall *sc; @@ -4721,7 +4733,7 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0; avg /= NSEC_PER_MSEC; - sc = trace__syscall_info(trace, /*evsel=*/NULL, EM_HOST, + sc = trace__syscall_info(trace, /*evsel=*/NULL, e_machine, syscall_stats_entry->syscall); if (!sc) continue; @@ -4771,7 +4783,8 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac else if (fputc('\n', fp) != EOF) ++printed; - printed += thread__dump_stats(ttrace, trace, fp); + /* TODO: get e_machine from thread. */ + printed += thread__dump_stats(ttrace, trace, EM_HOST, fp); return printed; } @@ -5003,8 +5016,9 @@ static int trace__parse_events_option(const struct option *opt, const char *str, *sep = '\0'; list = 0; - if (syscalltbl__id(trace->sctbl, s) >= 0 || - syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { + /* TODO: support for more than just perf binary machine type syscalls. */ + if (syscalltbl__id(EM_HOST, s) >= 0 || + syscalltbl__strglobmatch_first(EM_HOST, s, &idx) >= 0) { list = 1; goto do_concat; } @@ -5140,7 +5154,6 @@ static void trace__exit(struct trace *trace) syscall__exit(&trace->syscalls.table[i]); zfree(&trace->syscalls.table); } - syscalltbl__delete(trace->sctbl); zfree(&trace->perfconfig_events); } @@ -5286,9 +5299,8 @@ int cmd_trace(int argc, const char **argv) sigaction(SIGCHLD, &sigchld_act, NULL); trace.evlist = evlist__new(); - trace.sctbl = syscalltbl__new(); - if (trace.evlist == NULL || trace.sctbl == NULL) { + if (trace.evlist == NULL) { pr_err("Not enough memory to run!\n"); err = -ENOMEM; goto out; diff --git a/tools/perf/scripts/syscalltbl.sh b/tools/perf/scripts/syscalltbl.sh index 1ce0d5aa8b50..a39b3013b103 100755 --- a/tools/perf/scripts/syscalltbl.sh +++ b/tools/perf/scripts/syscalltbl.sh @@ -50,37 +50,27 @@ fi infile="$1" outfile="$2" -nxt=0 - -syscall_macro() { - nr="$1" - name="$2" - - echo " [$nr] = \"$name\"," -} - -emit() { - nr="$1" - entry="$2" - - syscall_macro "$nr" "$entry" -} - -echo "static const char *const syscalltbl[] = {" > $outfile - sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX) grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n > $sorted_table -max_nr=0 +echo "static const char *const syscall_num_to_name[] = {" > $outfile # the params are: nr abi name entry compat # use _ for intentionally unused variables according to SC2034 while read nr _ name _ _; do - emit "$nr" "$name" >> $outfile - max_nr=$nr + echo " [$nr] = \"$name\"," >> $outfile done < $sorted_table +echo "};" >> $outfile -rm -f $sorted_table +echo "static const uint16_t syscall_sorted_names[] = {" >> $outfile +# When sorting by name, add a suffix of 0s upto 20 characters so that system +# calls that differ with a numerical suffix don't sort before those +# without. This default behavior of sort differs from that of strcmp used at +# runtime. Use sed to strip the trailing 0s suffix afterwards. +grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | awk '{printf $3; for (i = length($3); i < 20; i++) { printf "0"; }; print " " $1}'| sort | sed 's/\([a-zA-Z1-9]\+\)0\+ \([0-9]\+\)/\1 \2/' > $sorted_table +while read name nr; do + echo " $nr, /* $name */" >> $outfile +done < $sorted_table echo "};" >> $outfile -echo "#define SYSCALLTBL_MAX_ID ${max_nr}" >> $outfile +rm -f $sorted_table diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index 2f76241494c8..760ac4d0869f 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -9,6 +9,7 @@ #include <stdlib.h> #include <asm/bitsperlong.h> #include <linux/compiler.h> +#include <linux/kernel.h> #include <linux/zalloc.h> #include <string.h> @@ -20,112 +21,66 @@ #include <asm/syscalls_32.h> #endif -const int syscalltbl_native_max_id = SYSCALLTBL_MAX_ID; -static const char *const *syscalltbl_native = syscalltbl; +const char *syscalltbl__name(int e_machine __maybe_unused, int id) +{ + if (id >= 0 && id <= (int)ARRAY_SIZE(syscall_num_to_name)) + return syscall_num_to_name[id]; + return NULL; +} -struct syscall { - int id; +struct syscall_cmp_key { const char *name; + const char *const *tbl; }; static int syscallcmpname(const void *vkey, const void *ventry) { - const char *key = vkey; - const struct syscall *entry = ventry; + const struct syscall_cmp_key *key = vkey; + const uint16_t *entry = ventry; - return strcmp(key, entry->name); + return strcmp(key->name, key->tbl[*entry]); } -static int syscallcmp(const void *va, const void *vb) +int syscalltbl__id(int e_machine __maybe_unused, const char *name) { - const struct syscall *a = va, *b = vb; - - return strcmp(a->name, b->name); + struct syscall_cmp_key key = { + .name = name, + .tbl = syscall_num_to_name, + }; + const int *id = bsearch(&key, syscall_sorted_names, + ARRAY_SIZE(syscall_sorted_names), + sizeof(syscall_sorted_names[0]), + syscallcmpname); + + return id ? *id : -1; } -static int syscalltbl__init_native(struct syscalltbl *tbl) +int syscalltbl__num_idx(int e_machine __maybe_unused) { - int nr_entries = 0, i, j; - struct syscall *entries; - - for (i = 0; i <= syscalltbl_native_max_id; ++i) - if (syscalltbl_native[i]) - ++nr_entries; - - entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries); - if (tbl->syscalls.entries == NULL) - return -1; - - for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) { - if (syscalltbl_native[i]) { - entries[j].name = syscalltbl_native[i]; - entries[j].id = i; - ++j; - } - } - - qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); - tbl->syscalls.nr_entries = nr_entries; - tbl->syscalls.max_id = syscalltbl_native_max_id; - return 0; + return ARRAY_SIZE(syscall_sorted_names); } -struct syscalltbl *syscalltbl__new(void) +int syscalltbl__id_at_idx(int e_machine __maybe_unused, int idx) { - struct syscalltbl *tbl = malloc(sizeof(*tbl)); - if (tbl) { - if (syscalltbl__init_native(tbl)) { - free(tbl); - return NULL; - } - } - return tbl; -} - -void syscalltbl__delete(struct syscalltbl *tbl) -{ - zfree(&tbl->syscalls.entries); - free(tbl); -} - -const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id) -{ - return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL; -} - -int syscalltbl__id(struct syscalltbl *tbl, const char *name) -{ - struct syscall *sc = bsearch(name, tbl->syscalls.entries, - tbl->syscalls.nr_entries, sizeof(*sc), - syscallcmpname); - - return sc ? sc->id : -1; -} - -int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx) -{ - struct syscall *syscalls = tbl->syscalls.entries; - - return idx < tbl->syscalls.nr_entries ? syscalls[idx].id : -1; + return syscall_sorted_names[idx]; } -int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx) +int syscalltbl__strglobmatch_next(int e_machine __maybe_unused, const char *syscall_glob, int *idx) { - int i; - struct syscall *syscalls = tbl->syscalls.entries; + for (int i = *idx + 1; i < (int)ARRAY_SIZE(syscall_sorted_names); ++i) { + const char *name = syscall_num_to_name[syscall_sorted_names[i]]; - for (i = *idx + 1; i < tbl->syscalls.nr_entries; ++i) { - if (strglobmatch(syscalls[i].name, syscall_glob)) { + if (strglobmatch(name, syscall_glob)) { *idx = i; - return syscalls[i].id; + return syscall_sorted_names[i]; } } return -1; } -int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx) +int syscalltbl__strglobmatch_first(int e_machine, const char *syscall_glob, int *idx) { *idx = -1; - return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx); + return syscalltbl__strglobmatch_next(e_machine, syscall_glob, idx); } diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h index 362411a6d849..2bb628eff367 100644 --- a/tools/perf/util/syscalltbl.h +++ b/tools/perf/util/syscalltbl.h @@ -2,22 +2,12 @@ #ifndef __PERF_SYSCALLTBL_H #define __PERF_SYSCALLTBL_H -struct syscalltbl { - struct { - int max_id; - int nr_entries; - void *entries; - } syscalls; -}; +const char *syscalltbl__name(int e_machine, int id); +int syscalltbl__id(int e_machine, const char *name); +int syscalltbl__num_idx(int e_machine); +int syscalltbl__id_at_idx(int e_machine, int idx); -struct syscalltbl *syscalltbl__new(void); -void syscalltbl__delete(struct syscalltbl *tbl); - -const char *syscalltbl__name(const struct syscalltbl *tbl, int id); -int syscalltbl__id(struct syscalltbl *tbl, const char *name); -int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx); - -int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx); -int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx); +int syscalltbl__strglobmatch_first(int e_machine, const char *syscall_glob, int *idx); +int syscalltbl__strglobmatch_next(int e_machine, const char *syscall_glob, int *idx); #endif /* __PERF_SYSCALLTBL_H */