// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) #include "tp_pmu.h" #include "pmus.h" #include #include #include #include #include #include int tp_pmu__id(const char *sys, const char *name) { char *tp_dir = get_events_file(sys); char path[PATH_MAX]; int id, err; if (!tp_dir) return -1; scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name); put_events_file(tp_dir); err = filename__read_int(path, &id); if (err) return err; return id; } int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb) { char *evt_path; struct io_dirent64 *evt_ent; struct io_dir evt_dir; int ret = 0; evt_path = get_events_file(sys); if (!evt_path) return -errno; io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); if (evt_dir.dirfd < 0) { ret = -errno; put_events_file(evt_path); return ret; } put_events_file(evt_path); while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) { if (!strcmp(evt_ent->d_name, ".") || !strcmp(evt_ent->d_name, "..") || !strcmp(evt_ent->d_name, "enable") || !strcmp(evt_ent->d_name, "filter")) continue; ret = cb(state, sys, evt_ent->d_name); if (ret) break; } close(evt_dir.dirfd); return ret; } int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb) { struct io_dirent64 *events_ent; struct io_dir events_dir; int ret = 0; char *events_dir_path = get_tracing_file("events"); if (!events_dir_path) return -errno; io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); if (events_dir.dirfd < 0) { ret = -errno; put_events_file(events_dir_path); return ret; } put_events_file(events_dir_path); while (!ret && (events_ent = io_dir__readdir(&events_dir))) { if (!strcmp(events_ent->d_name, ".") || !strcmp(events_ent->d_name, "..") || !strcmp(events_ent->d_name, "enable") || !strcmp(events_ent->d_name, "header_event") || !strcmp(events_ent->d_name, "header_page")) continue; ret = cb(state, events_ent->d_name); if (ret) break; } close(events_dir.dirfd); return ret; } bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu) { return pmu->type == PERF_TYPE_TRACEPOINT; } struct for_each_event_args { void *state; pmu_event_callback cb; const struct perf_pmu *pmu; }; static int for_each_event_cb(void *state, const char *sys_name, const char *evt_name) { struct for_each_event_args *args = state; char name[2 * FILENAME_MAX + 2]; /* 16 possible hex digits and 22 other characters and \0. */ char encoding[16 + 22]; char *format = NULL; size_t format_size; struct pmu_event_info info = { .pmu = args->pmu, .pmu_name = args->pmu->name, .event_type_desc = "Tracepoint event", }; char *tp_dir = get_events_file(sys_name); char path[PATH_MAX]; int id, err; if (!tp_dir) return -1; scnprintf(path, sizeof(path), "%s/%s/id", tp_dir, evt_name); err = filename__read_int(path, &id); if (err == 0) { snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%x/", id); info.encoding_desc = encoding; } scnprintf(path, sizeof(path), "%s/%s/format", tp_dir, evt_name); put_events_file(tp_dir); err = filename__read_str(path, &format, &format_size); if (err == 0) { info.long_desc = format; for (size_t i = 0 ; i < format_size; i++) { /* Swap tabs to spaces due to some rendering issues. */ if (format[i] == '\t') format[i] = ' '; } } snprintf(name, sizeof(name), "%s:%s", sys_name, evt_name); info.name = name; err = args->cb(args->state, &info); free(format); return err; } static int for_each_event_sys_cb(void *state, const char *sys_name) { return tp_pmu__for_each_tp_event(sys_name, state, for_each_event_cb); } int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb) { struct for_each_event_args args = { .state = state, .cb = cb, .pmu = pmu, }; return tp_pmu__for_each_tp_sys(&args, for_each_event_sys_cb); } static int num_events_cb(void *state, const char *sys_name __maybe_unused, const char *evt_name __maybe_unused) { size_t *count = state; (*count)++; return 0; } static int num_events_sys_cb(void *state, const char *sys_name) { return tp_pmu__for_each_tp_event(sys_name, state, num_events_cb); } size_t tp_pmu__num_events(struct perf_pmu *pmu __maybe_unused) { size_t count = 0; tp_pmu__for_each_tp_sys(&count, num_events_sys_cb); return count; } bool tp_pmu__have_event(struct perf_pmu *pmu __maybe_unused, const char *name) { char *dup_name, *colon; int id; colon = strchr(name, ':'); if (colon == NULL) return false; dup_name = strdup(name); if (!dup_name) return false; colon = dup_name + (colon - name); *colon = '\0'; id = tp_pmu__id(dup_name, colon + 1); free(dup_name); return id >= 0; }