1d002aab8SIan Rogers // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2d002aab8SIan Rogers #include "tp_pmu.h" 3*45b6e281SIan Rogers #include "pmus.h" 4d002aab8SIan Rogers #include <api/fs/fs.h> 5d002aab8SIan Rogers #include <api/fs/tracing_path.h> 6d002aab8SIan Rogers #include <api/io_dir.h> 7d002aab8SIan Rogers #include <linux/kernel.h> 8d002aab8SIan Rogers #include <errno.h> 9d002aab8SIan Rogers #include <string.h> 10d002aab8SIan Rogers 11d002aab8SIan Rogers int tp_pmu__id(const char *sys, const char *name) 12d002aab8SIan Rogers { 13d002aab8SIan Rogers char *tp_dir = get_events_file(sys); 14d002aab8SIan Rogers char path[PATH_MAX]; 15d002aab8SIan Rogers int id, err; 16d002aab8SIan Rogers 17d002aab8SIan Rogers if (!tp_dir) 18d002aab8SIan Rogers return -1; 19d002aab8SIan Rogers 20d002aab8SIan Rogers scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name); 21d002aab8SIan Rogers put_events_file(tp_dir); 22d002aab8SIan Rogers err = filename__read_int(path, &id); 23d002aab8SIan Rogers if (err) 24d002aab8SIan Rogers return err; 25d002aab8SIan Rogers 26d002aab8SIan Rogers return id; 27d002aab8SIan Rogers } 28d002aab8SIan Rogers 29d002aab8SIan Rogers 30d002aab8SIan Rogers int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb) 31d002aab8SIan Rogers { 32d002aab8SIan Rogers char *evt_path; 33d002aab8SIan Rogers struct io_dirent64 *evt_ent; 34d002aab8SIan Rogers struct io_dir evt_dir; 35d002aab8SIan Rogers int ret = 0; 36d002aab8SIan Rogers 37d002aab8SIan Rogers evt_path = get_events_file(sys); 38d002aab8SIan Rogers if (!evt_path) 39d002aab8SIan Rogers return -errno; 40d002aab8SIan Rogers 41d002aab8SIan Rogers io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 42d002aab8SIan Rogers if (evt_dir.dirfd < 0) { 43d002aab8SIan Rogers ret = -errno; 44d002aab8SIan Rogers put_events_file(evt_path); 45d002aab8SIan Rogers return ret; 46d002aab8SIan Rogers } 47d002aab8SIan Rogers put_events_file(evt_path); 48d002aab8SIan Rogers 49d002aab8SIan Rogers while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) { 50d002aab8SIan Rogers if (!strcmp(evt_ent->d_name, ".") 51d002aab8SIan Rogers || !strcmp(evt_ent->d_name, "..") 52d002aab8SIan Rogers || !strcmp(evt_ent->d_name, "enable") 53d002aab8SIan Rogers || !strcmp(evt_ent->d_name, "filter")) 54d002aab8SIan Rogers continue; 55d002aab8SIan Rogers 56d002aab8SIan Rogers ret = cb(state, sys, evt_ent->d_name); 57d002aab8SIan Rogers if (ret) 58d002aab8SIan Rogers break; 59d002aab8SIan Rogers } 60d002aab8SIan Rogers close(evt_dir.dirfd); 61d002aab8SIan Rogers return ret; 62d002aab8SIan Rogers } 63d002aab8SIan Rogers 64d002aab8SIan Rogers int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb) 65d002aab8SIan Rogers { 66d002aab8SIan Rogers struct io_dirent64 *events_ent; 67d002aab8SIan Rogers struct io_dir events_dir; 68d002aab8SIan Rogers int ret = 0; 69d002aab8SIan Rogers char *events_dir_path = get_tracing_file("events"); 70d002aab8SIan Rogers 71d002aab8SIan Rogers if (!events_dir_path) 72d002aab8SIan Rogers return -errno; 73d002aab8SIan Rogers 74d002aab8SIan Rogers io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 75d002aab8SIan Rogers if (events_dir.dirfd < 0) { 76d002aab8SIan Rogers ret = -errno; 77d002aab8SIan Rogers put_events_file(events_dir_path); 78d002aab8SIan Rogers return ret; 79d002aab8SIan Rogers } 80d002aab8SIan Rogers put_events_file(events_dir_path); 81d002aab8SIan Rogers 82d002aab8SIan Rogers while (!ret && (events_ent = io_dir__readdir(&events_dir))) { 83d002aab8SIan Rogers if (!strcmp(events_ent->d_name, ".") || 84d002aab8SIan Rogers !strcmp(events_ent->d_name, "..") || 85d002aab8SIan Rogers !strcmp(events_ent->d_name, "enable") || 86d002aab8SIan Rogers !strcmp(events_ent->d_name, "header_event") || 87d002aab8SIan Rogers !strcmp(events_ent->d_name, "header_page")) 88d002aab8SIan Rogers continue; 89d002aab8SIan Rogers 90d002aab8SIan Rogers ret = cb(state, events_ent->d_name); 91d002aab8SIan Rogers if (ret) 92d002aab8SIan Rogers break; 93d002aab8SIan Rogers } 94d002aab8SIan Rogers close(events_dir.dirfd); 95d002aab8SIan Rogers return ret; 96d002aab8SIan Rogers } 97*45b6e281SIan Rogers 98*45b6e281SIan Rogers bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu) 99*45b6e281SIan Rogers { 100*45b6e281SIan Rogers return pmu->type == PERF_TYPE_TRACEPOINT; 101*45b6e281SIan Rogers } 102*45b6e281SIan Rogers 103*45b6e281SIan Rogers struct for_each_event_args { 104*45b6e281SIan Rogers void *state; 105*45b6e281SIan Rogers pmu_event_callback cb; 106*45b6e281SIan Rogers const struct perf_pmu *pmu; 107*45b6e281SIan Rogers }; 108*45b6e281SIan Rogers 109*45b6e281SIan Rogers static int for_each_event_cb(void *state, const char *sys_name, const char *evt_name) 110*45b6e281SIan Rogers { 111*45b6e281SIan Rogers struct for_each_event_args *args = state; 112*45b6e281SIan Rogers char name[2 * FILENAME_MAX + 2]; 113*45b6e281SIan Rogers /* 16 possible hex digits and 22 other characters and \0. */ 114*45b6e281SIan Rogers char encoding[16 + 22]; 115*45b6e281SIan Rogers char *format = NULL; 116*45b6e281SIan Rogers size_t format_size; 117*45b6e281SIan Rogers struct pmu_event_info info = { 118*45b6e281SIan Rogers .pmu = args->pmu, 119*45b6e281SIan Rogers .pmu_name = args->pmu->name, 120*45b6e281SIan Rogers .event_type_desc = "Tracepoint event", 121*45b6e281SIan Rogers }; 122*45b6e281SIan Rogers char *tp_dir = get_events_file(sys_name); 123*45b6e281SIan Rogers char path[PATH_MAX]; 124*45b6e281SIan Rogers int id, err; 125*45b6e281SIan Rogers 126*45b6e281SIan Rogers if (!tp_dir) 127*45b6e281SIan Rogers return -1; 128*45b6e281SIan Rogers 129*45b6e281SIan Rogers scnprintf(path, sizeof(path), "%s/%s/id", tp_dir, evt_name); 130*45b6e281SIan Rogers err = filename__read_int(path, &id); 131*45b6e281SIan Rogers if (err == 0) { 132*45b6e281SIan Rogers snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%x/", id); 133*45b6e281SIan Rogers info.encoding_desc = encoding; 134*45b6e281SIan Rogers } 135*45b6e281SIan Rogers 136*45b6e281SIan Rogers scnprintf(path, sizeof(path), "%s/%s/format", tp_dir, evt_name); 137*45b6e281SIan Rogers put_events_file(tp_dir); 138*45b6e281SIan Rogers err = filename__read_str(path, &format, &format_size); 139*45b6e281SIan Rogers if (err == 0) { 140*45b6e281SIan Rogers info.long_desc = format; 141*45b6e281SIan Rogers for (size_t i = 0 ; i < format_size; i++) { 142*45b6e281SIan Rogers /* Swap tabs to spaces due to some rendering issues. */ 143*45b6e281SIan Rogers if (format[i] == '\t') 144*45b6e281SIan Rogers format[i] = ' '; 145*45b6e281SIan Rogers } 146*45b6e281SIan Rogers } 147*45b6e281SIan Rogers snprintf(name, sizeof(name), "%s:%s", sys_name, evt_name); 148*45b6e281SIan Rogers info.name = name; 149*45b6e281SIan Rogers err = args->cb(args->state, &info); 150*45b6e281SIan Rogers free(format); 151*45b6e281SIan Rogers return err; 152*45b6e281SIan Rogers } 153*45b6e281SIan Rogers 154*45b6e281SIan Rogers static int for_each_event_sys_cb(void *state, const char *sys_name) 155*45b6e281SIan Rogers { 156*45b6e281SIan Rogers return tp_pmu__for_each_tp_event(sys_name, state, for_each_event_cb); 157*45b6e281SIan Rogers } 158*45b6e281SIan Rogers 159*45b6e281SIan Rogers int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb) 160*45b6e281SIan Rogers { 161*45b6e281SIan Rogers struct for_each_event_args args = { 162*45b6e281SIan Rogers .state = state, 163*45b6e281SIan Rogers .cb = cb, 164*45b6e281SIan Rogers .pmu = pmu, 165*45b6e281SIan Rogers }; 166*45b6e281SIan Rogers 167*45b6e281SIan Rogers return tp_pmu__for_each_tp_sys(&args, for_each_event_sys_cb); 168*45b6e281SIan Rogers } 169*45b6e281SIan Rogers 170*45b6e281SIan Rogers static int num_events_cb(void *state, const char *sys_name __maybe_unused, 171*45b6e281SIan Rogers const char *evt_name __maybe_unused) 172*45b6e281SIan Rogers { 173*45b6e281SIan Rogers size_t *count = state; 174*45b6e281SIan Rogers 175*45b6e281SIan Rogers (*count)++; 176*45b6e281SIan Rogers return 0; 177*45b6e281SIan Rogers } 178*45b6e281SIan Rogers 179*45b6e281SIan Rogers static int num_events_sys_cb(void *state, const char *sys_name) 180*45b6e281SIan Rogers { 181*45b6e281SIan Rogers return tp_pmu__for_each_tp_event(sys_name, state, num_events_cb); 182*45b6e281SIan Rogers } 183*45b6e281SIan Rogers 184*45b6e281SIan Rogers size_t tp_pmu__num_events(struct perf_pmu *pmu __maybe_unused) 185*45b6e281SIan Rogers { 186*45b6e281SIan Rogers size_t count = 0; 187*45b6e281SIan Rogers 188*45b6e281SIan Rogers tp_pmu__for_each_tp_sys(&count, num_events_sys_cb); 189*45b6e281SIan Rogers return count; 190*45b6e281SIan Rogers } 191*45b6e281SIan Rogers 192*45b6e281SIan Rogers bool tp_pmu__have_event(struct perf_pmu *pmu __maybe_unused, const char *name) 193*45b6e281SIan Rogers { 194*45b6e281SIan Rogers char *dup_name, *colon; 195*45b6e281SIan Rogers int id; 196*45b6e281SIan Rogers 197*45b6e281SIan Rogers colon = strchr(name, ':'); 198*45b6e281SIan Rogers if (colon == NULL) 199*45b6e281SIan Rogers return false; 200*45b6e281SIan Rogers 201*45b6e281SIan Rogers dup_name = strdup(name); 202*45b6e281SIan Rogers if (!dup_name) 203*45b6e281SIan Rogers return false; 204*45b6e281SIan Rogers 205*45b6e281SIan Rogers colon = dup_name + (colon - name); 206*45b6e281SIan Rogers *colon = '\0'; 207*45b6e281SIan Rogers id = tp_pmu__id(dup_name, colon + 1); 208*45b6e281SIan Rogers free(dup_name); 209*45b6e281SIan Rogers return id >= 0; 210*45b6e281SIan Rogers } 211