diff options
Diffstat (limited to 'tools/perf/util/pmu.c')
| -rw-r--r-- | tools/perf/util/pmu.c | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 67715a42cd6d..8a2229da594f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -9,6 +9,9 @@ | |||
| 9 | #include "util.h" | 9 | #include "util.h" |
| 10 | #include "pmu.h" | 10 | #include "pmu.h" |
| 11 | #include "parse-events.h" | 11 | #include "parse-events.h" |
| 12 | #include "cpumap.h" | ||
| 13 | |||
| 14 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" | ||
| 12 | 15 | ||
| 13 | int perf_pmu_parse(struct list_head *list, char *name); | 16 | int perf_pmu_parse(struct list_head *list, char *name); |
| 14 | extern FILE *perf_pmu_in; | 17 | extern FILE *perf_pmu_in; |
| @@ -69,7 +72,7 @@ static int pmu_format(char *name, struct list_head *format) | |||
| 69 | return -1; | 72 | return -1; |
| 70 | 73 | ||
| 71 | snprintf(path, PATH_MAX, | 74 | snprintf(path, PATH_MAX, |
| 72 | "%s/bus/event_source/devices/%s/format", sysfs, name); | 75 | "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); |
| 73 | 76 | ||
| 74 | if (stat(path, &st) < 0) | 77 | if (stat(path, &st) < 0) |
| 75 | return 0; /* no error if format does not exist */ | 78 | return 0; /* no error if format does not exist */ |
| @@ -206,7 +209,7 @@ static int pmu_type(char *name, __u32 *type) | |||
| 206 | return -1; | 209 | return -1; |
| 207 | 210 | ||
| 208 | snprintf(path, PATH_MAX, | 211 | snprintf(path, PATH_MAX, |
| 209 | "%s/bus/event_source/devices/%s/type", sysfs, name); | 212 | "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); |
| 210 | 213 | ||
| 211 | if (stat(path, &st) < 0) | 214 | if (stat(path, &st) < 0) |
| 212 | return -1; | 215 | return -1; |
| @@ -222,6 +225,62 @@ static int pmu_type(char *name, __u32 *type) | |||
| 222 | return ret; | 225 | return ret; |
| 223 | } | 226 | } |
| 224 | 227 | ||
| 228 | /* Add all pmus in sysfs to pmu list: */ | ||
| 229 | static void pmu_read_sysfs(void) | ||
| 230 | { | ||
| 231 | char path[PATH_MAX]; | ||
| 232 | const char *sysfs; | ||
| 233 | DIR *dir; | ||
| 234 | struct dirent *dent; | ||
| 235 | |||
| 236 | sysfs = sysfs_find_mountpoint(); | ||
| 237 | if (!sysfs) | ||
| 238 | return; | ||
| 239 | |||
| 240 | snprintf(path, PATH_MAX, | ||
| 241 | "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); | ||
| 242 | |||
| 243 | dir = opendir(path); | ||
| 244 | if (!dir) | ||
| 245 | return; | ||
| 246 | |||
| 247 | while ((dent = readdir(dir))) { | ||
| 248 | if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) | ||
| 249 | continue; | ||
| 250 | /* add to static LIST_HEAD(pmus): */ | ||
| 251 | perf_pmu__find(dent->d_name); | ||
| 252 | } | ||
| 253 | |||
| 254 | closedir(dir); | ||
| 255 | } | ||
| 256 | |||
| 257 | static struct cpu_map *pmu_cpumask(char *name) | ||
| 258 | { | ||
| 259 | struct stat st; | ||
| 260 | char path[PATH_MAX]; | ||
| 261 | const char *sysfs; | ||
| 262 | FILE *file; | ||
| 263 | struct cpu_map *cpus; | ||
| 264 | |||
| 265 | sysfs = sysfs_find_mountpoint(); | ||
| 266 | if (!sysfs) | ||
| 267 | return NULL; | ||
| 268 | |||
| 269 | snprintf(path, PATH_MAX, | ||
| 270 | "%s/bus/event_source/devices/%s/cpumask", sysfs, name); | ||
| 271 | |||
| 272 | if (stat(path, &st) < 0) | ||
| 273 | return NULL; | ||
| 274 | |||
| 275 | file = fopen(path, "r"); | ||
| 276 | if (!file) | ||
| 277 | return NULL; | ||
| 278 | |||
| 279 | cpus = cpu_map__read(file); | ||
| 280 | fclose(file); | ||
| 281 | return cpus; | ||
| 282 | } | ||
| 283 | |||
| 225 | static struct perf_pmu *pmu_lookup(char *name) | 284 | static struct perf_pmu *pmu_lookup(char *name) |
| 226 | { | 285 | { |
| 227 | struct perf_pmu *pmu; | 286 | struct perf_pmu *pmu; |
| @@ -244,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
| 244 | if (!pmu) | 303 | if (!pmu) |
| 245 | return NULL; | 304 | return NULL; |
| 246 | 305 | ||
| 306 | pmu->cpus = pmu_cpumask(name); | ||
| 307 | |||
| 247 | pmu_aliases(name, &aliases); | 308 | pmu_aliases(name, &aliases); |
| 248 | 309 | ||
| 249 | INIT_LIST_HEAD(&pmu->format); | 310 | INIT_LIST_HEAD(&pmu->format); |
| @@ -267,6 +328,21 @@ static struct perf_pmu *pmu_find(char *name) | |||
| 267 | return NULL; | 328 | return NULL; |
| 268 | } | 329 | } |
| 269 | 330 | ||
| 331 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) | ||
| 332 | { | ||
| 333 | /* | ||
| 334 | * pmu iterator: If pmu is NULL, we start at the begin, | ||
| 335 | * otherwise return the next pmu. Returns NULL on end. | ||
| 336 | */ | ||
| 337 | if (!pmu) { | ||
| 338 | pmu_read_sysfs(); | ||
| 339 | pmu = list_prepare_entry(pmu, &pmus, list); | ||
| 340 | } | ||
| 341 | list_for_each_entry_continue(pmu, &pmus, list) | ||
| 342 | return pmu; | ||
| 343 | return NULL; | ||
| 344 | } | ||
| 345 | |||
| 270 | struct perf_pmu *perf_pmu__find(char *name) | 346 | struct perf_pmu *perf_pmu__find(char *name) |
| 271 | { | 347 | { |
| 272 | struct perf_pmu *pmu; | 348 | struct perf_pmu *pmu; |
