^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/zalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <subcmd/pager.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <stdbool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <dirent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <api/fs/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <locale.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <regex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <perf/cpumap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "evsel.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "pmu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "parse-events.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "header.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "string2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "strbuf.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "fncache.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct perf_pmu perf_pmu__fake;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct perf_pmu_format {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int perf_pmu_parse(struct list_head *list, char *name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) extern FILE *perf_pmu_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static LIST_HEAD(pmus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Parse & process all the sysfs attributes located under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * the directory specified in 'dir' parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int perf_pmu__format_parse(char *dir, struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct dirent *evt_ent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) DIR *format_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) format_dir = opendir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (!format_dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) while (!ret && (evt_ent = readdir(format_dir))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) char *name = evt_ent->d_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!strcmp(name, ".") || !strcmp(name, ".."))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) snprintf(path, PATH_MAX, "%s/%s", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) file = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (!file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) perf_pmu_in = file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = perf_pmu_parse(head, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) closedir(format_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Reading/parsing the default pmu format definition, which should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * located at:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int pmu_format(const char *name, struct list_head *format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) snprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (!file_available(path))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (perf_pmu__format_parse(path, format))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int perf_pmu__convert_scale(const char *scale, char **end, double *sval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) char *lc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * save current locale
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) lc = setlocale(LC_NUMERIC, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * The lc string may be allocated in static storage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * so get a dynamic copy to make it survive setlocale
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * call below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) lc = strdup(lc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!lc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * force to C locale to ensure kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * scale string is converted correctly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * kernel uses default C locale.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) setlocale(LC_NUMERIC, "C");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *sval = strtod(scale, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* restore locale */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) setlocale(LC_NUMERIC, lc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) free(lc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct stat st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ssize_t sret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) char scale[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int fd, ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (fstat(fd, &st) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) sret = read(fd, scale, sizeof(scale)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (sret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (scale[sret - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) scale[sret - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) scale[sret] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ret = perf_pmu__convert_scale(scale, NULL, &alias->scale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ssize_t sret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sret = read(fd, alias->unit, UNIT_MAX_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (sret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (alias->unit[sret - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) alias->unit[sret - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) alias->unit[sret] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) alias->unit[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) alias->per_pkg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) char *dir, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) alias->snapshot = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static void perf_pmu_assign_str(char *name, const char *field, char **old_str,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) char **new_str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (!*old_str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) goto set_new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (*new_str) { /* Have new string, check with old */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (strcasecmp(*old_str, *new_str))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) pr_debug("alias %s differs in field '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) name, field);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) zfree(old_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) } else /* Nothing new --> keep old string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) set_new:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) *old_str = *new_str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) *new_str = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static void perf_pmu_update_alias(struct perf_pmu_alias *old,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct perf_pmu_alias *newalias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) &newalias->long_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) &newalias->metric_expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) &newalias->metric_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) old->scale = newalias->scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) old->per_pkg = newalias->per_pkg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) old->snapshot = newalias->snapshot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) memcpy(old->unit, newalias->unit, sizeof(old->unit));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /* Delete an alias entry. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) zfree(&newalias->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) zfree(&newalias->desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) zfree(&newalias->long_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) zfree(&newalias->topic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) zfree(&newalias->str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) zfree(&newalias->metric_expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) zfree(&newalias->metric_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) parse_events_terms__purge(&newalias->terms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) free(newalias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* Merge an alias, search in alias list. If this name is already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * present merge both of them to combine all information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct list_head *alist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct perf_pmu_alias *a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) list_for_each_entry(a, alist, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (!strcasecmp(newalias->name, a->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) perf_pmu_update_alias(a, newalias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) perf_pmu_free_alias(newalias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) char *desc, char *val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) char *long_desc, char *topic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) char *unit, char *perpkg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) char *metric_expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) char *metric_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) char *deprecated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct parse_events_term *term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct perf_pmu_alias *alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) int num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) char newval[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) alias = malloc(sizeof(*alias));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (!alias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) INIT_LIST_HEAD(&alias->terms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) alias->scale = 1.0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) alias->unit[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) alias->per_pkg = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) alias->snapshot = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) alias->deprecated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) ret = parse_events_terms(&alias->terms, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) pr_err("Cannot parse alias %s: %d\n", val, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) free(alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* Scan event and remove leading zeroes, spaces, newlines, some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * platforms have terms specified as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * event=0x0091 (read from files ../<PMU>/events/<FILE>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * and terms specified as event=0x91 (read from JSON files).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * Rebuild string to make alias->str member comparable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) memset(newval, 0, sizeof(newval));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) list_for_each_entry(term, &alias->terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) ret += scnprintf(newval + ret, sizeof(newval) - ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ",");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ret += scnprintf(newval + ret, sizeof(newval) - ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) "%s=%#x", term->config, term->val.num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) ret += scnprintf(newval + ret, sizeof(newval) - ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) "%s=%s", term->config, term->val.str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) alias->name = strdup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * load unit name and scale if available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) perf_pmu__parse_unit(alias, dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) perf_pmu__parse_scale(alias, dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) perf_pmu__parse_per_pkg(alias, dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) perf_pmu__parse_snapshot(alias, dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) alias->metric_name = metric_name ? strdup(metric_name): NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) alias->desc = desc ? strdup(desc) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) alias->long_desc = long_desc ? strdup(long_desc) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) desc ? strdup(desc) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) alias->topic = topic ? strdup(topic) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (unit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) alias->str = strdup(newval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (deprecated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) alias->deprecated = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (!perf_pmu_merge_alias(alias, list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) list_add_tail(&alias->list, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) char buf[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = fread(buf, 1, sizeof(buf), file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) buf[ret] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /* Remove trailing newline from sysfs file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) strim(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) NULL, NULL, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) static inline bool pmu_alias_info_file(char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) len = strlen(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (len > 5 && !strcmp(name + len - 5, ".unit"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (len > 6 && !strcmp(name + len - 6, ".scale"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * Process all the sysfs attributes located under the directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * specified in 'dir' parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static int pmu_aliases_parse(char *dir, struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct dirent *evt_ent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) DIR *event_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) event_dir = opendir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (!event_dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) while ((evt_ent = readdir(event_dir))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) char *name = evt_ent->d_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (!strcmp(name, ".") || !strcmp(name, ".."))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * skip info files parsed in perf_pmu__new_alias()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (pmu_alias_info_file(name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) scnprintf(path, PATH_MAX, "%s/%s", dir, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) file = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (!file) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) pr_debug("Cannot open %s\n", path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (perf_pmu__new_alias(head, dir, name, file) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) pr_debug("Cannot set up %s\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) closedir(event_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * Reading the pmu event aliases definition, which should be located at:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static int pmu_aliases(const char *name, struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) snprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) "%s/bus/event_source/devices/%s/events", sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (!file_available(path))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (pmu_aliases_parse(path, head))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static int pmu_alias_terms(struct perf_pmu_alias *alias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct list_head *terms)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) struct parse_events_term *term, *cloned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) LIST_HEAD(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) list_for_each_entry(term, &alias->terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) ret = parse_events_term__clone(&cloned, term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) parse_events_terms__purge(&list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * Weak terms don't override command line options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * which we don't want for implicit terms in aliases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) cloned->weak = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) list_add_tail(&cloned->list, &list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) list_splice(&list, terms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * Reading/parsing the default pmu type value, which should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * located at:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) static int pmu_type(const char *name, __u32 *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) snprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (access(path, R_OK) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) file = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (!file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (1 != fscanf(file, "%u", type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /* Add all pmus in sysfs to pmu list: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) static void pmu_read_sysfs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) DIR *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) struct dirent *dent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) snprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) dir = opendir(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (!dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) while ((dent = readdir(dir))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /* add to static LIST_HEAD(pmus): */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) perf_pmu__find(dent->d_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) closedir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static struct perf_cpu_map *__pmu_cpumask(const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) struct perf_cpu_map *cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) file = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) cpus = perf_cpu_map__read(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * may have a "cpus" file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) static struct perf_cpu_map *pmu_cpumask(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct perf_cpu_map *cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) const char *templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) CPUS_TEMPLATE_UNCORE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) CPUS_TEMPLATE_CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) const char **template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) for (template = templates; *template; template++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) snprintf(path, PATH_MAX, *template, sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) cpus = __pmu_cpumask(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) static bool pmu_is_uncore(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) const char *sysfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) return file_available(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * PMU CORE devices have different name other than cpu in sysfs on some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * Looking for possible sysfs files to identify the arm core device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static int is_arm_pmu_core(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /* Look for cpu sysfs (specific to arm) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) sysfs, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return file_available(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) char *cpuid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) static bool printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) cpuid = getenv("PERF_CPUID");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (cpuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) cpuid = strdup(cpuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (!cpuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) cpuid = get_cpuid_str(pmu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (!cpuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (!printed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) pr_debug("Using CPUID %s\n", cpuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) printed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return cpuid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) struct pmu_events_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) char *cpuid = perf_pmu__getcpuid(pmu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) /* on some platforms which uses cpus map, cpuid can be NULL for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * PMUs other than CORE PMUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (!cpuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) map = &pmu_events_map[i++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (!map->table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) map = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (!strcmp_cpuid_str(map->cpuid, cpuid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) free(cpuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) return map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) char *tmp = NULL, *tok, *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) str = strdup(pmu_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (!str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) * uncore alias may be from different PMU with common prefix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) tok = strtok_r(str, ",", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (strncmp(pmu_name, tok, strlen(tok))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) * Match more complex aliases where the alias name is a comma-delimited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * list of tokens, orderly contained in the matching PMU name.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * match "socket" in "socketX_pmunameY" and then "pmuname" in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * "pmunameY".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) name = strstr(name, tok);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (!name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) res = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) free(str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) * From the pmu_events_map, find the table of PMU events that corresponds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) * to the current running CPU. Then, add all PMU events from that table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) * as aliases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) struct pmu_events_map *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) const char *name = pmu->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) * Found a matching PMU events table. Create aliases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct pmu_event *pe = &map->table[i++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) const char *pname = pe->pmu ? pe->pmu : cpu_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) if (!pe->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (pe->metric_group || pe->metric_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (pmu_is_uncore(name) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) pmu_uncore_alias_match(pname, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) goto new_alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (strcmp(pname, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) new_alias:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) /* need type casts to override 'const' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) __perf_pmu__new_alias(head, NULL, (char *)pe->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) (char *)pe->desc, (char *)pe->event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) (char *)pe->long_desc, (char *)pe->topic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) (char *)pe->unit, (char *)pe->perpkg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) (char *)pe->metric_expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) (char *)pe->metric_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) (char *)pe->deprecated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) struct pmu_events_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) map = perf_pmu__find_map(pmu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (!map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) pmu_add_cpu_aliases_map(head, pmu, map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct perf_event_attr * __weak
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) static int pmu_max_precise(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) int max_precise = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) scnprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) "bus/event_source/devices/%s/caps/max_precise",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) sysfs__read_int(path, &max_precise);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return max_precise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static struct perf_pmu *pmu_lookup(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) LIST_HEAD(format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) LIST_HEAD(aliases);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) __u32 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * The pmu data we store & need consists of the pmu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * type value and format definitions. Load both right
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) * now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (pmu_format(name, &format))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) * Check the type first to avoid unnecessary work.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (pmu_type(name, &type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (pmu_aliases(name, &aliases))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) pmu = zalloc(sizeof(*pmu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (!pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) pmu->cpus = pmu_cpumask(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) pmu->name = strdup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) pmu->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) pmu->is_uncore = pmu_is_uncore(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) pmu->max_precise = pmu_max_precise(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) pmu_add_cpu_aliases(&aliases, pmu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) INIT_LIST_HEAD(&pmu->format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) INIT_LIST_HEAD(&pmu->aliases);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) INIT_LIST_HEAD(&pmu->caps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) list_splice(&format, &pmu->format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) list_splice(&aliases, &pmu->aliases);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) list_add_tail(&pmu->list, &pmus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) pmu->default_config = perf_pmu__get_default_config(pmu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) static struct perf_pmu *pmu_find(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) list_for_each_entry(pmu, &pmus, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) if (!strcmp(pmu->name, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) struct perf_pmu *perf_pmu__find_by_type(unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) list_for_each_entry(pmu, &pmus, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (pmu->type == type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) * pmu iterator: If pmu is NULL, we start at the begin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * otherwise return the next pmu. Returns NULL on end.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) if (!pmu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) pmu_read_sysfs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) pmu = list_prepare_entry(pmu, &pmus, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) list_for_each_entry_continue(pmu, &pmus, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) struct perf_pmu *evsel__find_pmu(struct evsel *evsel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct perf_pmu *pmu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) while ((pmu = perf_pmu__scan(pmu)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) if (pmu->type == evsel->core.attr.type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) bool evsel__is_aux_event(struct evsel *evsel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) struct perf_pmu *pmu = evsel__find_pmu(evsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) return pmu && pmu->auxtrace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) struct perf_pmu *perf_pmu__find(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) * Once PMU is loaded it stays in the list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) * so we keep us from multiple reading/parsing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) * the pmu format definitions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) pmu = pmu_find(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) if (pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) return pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) return pmu_lookup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) static struct perf_pmu_format *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) pmu_find_format(struct list_head *formats, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) struct perf_pmu_format *format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) list_for_each_entry(format, formats, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (!strcmp(format->name, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) __u64 perf_pmu__format_bits(struct list_head *formats, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) struct perf_pmu_format *format = pmu_find_format(formats, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) __u64 bits = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) int fbit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (!format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) bits |= 1ULL << fbit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) return bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) int perf_pmu__format_type(struct list_head *formats, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) struct perf_pmu_format *format = pmu_find_format(formats, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (!format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return format->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * Sets value based on the format definition (format parameter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) * and unformated value (value parameter).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) bool zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) unsigned long fbit, vbit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (!test_bit(fbit, format))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) if (value & (1llu << vbit++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) *v |= (1llu << fbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) else if (zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) *v &= ~(1llu << fbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) static __u64 pmu_format_max_value(const unsigned long *format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) int w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) if (!w)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (w < 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) return (1ULL << w) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * Term is a string term, and might be a param-term. Try to look up it's value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * in the remaining terms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) * - We have a term like "base-or-format-term=param-term",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * - We need to find the value supplied for "param-term" (with param-term named
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) * in a config string) later on in the term list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) static int pmu_resolve_param_term(struct parse_events_term *term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) struct list_head *head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) __u64 *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) struct parse_events_term *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) list_for_each_entry(t, head_terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) t->config && !strcmp(t->config, term->config)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) t->used = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) *value = t->val.num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (verbose > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) printf("Required parameter '%s' not specified\n", term->config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) static char *pmu_formats_string(struct list_head *formats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) struct perf_pmu_format *format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) char *str = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) struct strbuf buf = STRBUF_INIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) unsigned i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (!formats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) /* sysfs exported terms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) list_for_each_entry(format, formats, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) str = strbuf_detach(&buf, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) strbuf_release(&buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) return str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) * Setup one of config[12] attr members based on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) * user input data - term parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) static int pmu_config_term(const char *pmu_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) struct list_head *formats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) struct perf_event_attr *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) struct parse_events_term *term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) struct list_head *head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) bool zero, struct parse_events_error *err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) struct perf_pmu_format *format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) __u64 *vp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) __u64 val, max_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) * If this is a parameter we've already used for parameterized-eval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) * skip it in normal eval.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (term->used)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) * Hardcoded terms should be already in, so nothing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) * to be done for them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (parse_events__is_hardcoded_term(term))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) format = pmu_find_format(formats, term->config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) if (!format) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) char *pmu_term = pmu_formats_string(formats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) char *unknown_term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) char *help_msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) if (asprintf(&unknown_term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) "unknown term '%s' for pmu '%s'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) term->config, pmu_name) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) unknown_term = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) help_msg = parse_events_formats_error_string(pmu_term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) parse_events__handle_error(err, term->err_term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) unknown_term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) help_msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) pr_debug("%s (%s)\n", unknown_term, help_msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) free(unknown_term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) free(pmu_term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) switch (format->value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) case PERF_PMU_FORMAT_VALUE_CONFIG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) vp = &attr->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) case PERF_PMU_FORMAT_VALUE_CONFIG1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) vp = &attr->config1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) case PERF_PMU_FORMAT_VALUE_CONFIG2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) vp = &attr->config2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * Either directly use a numeric term, or try to translate string terms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * using event parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) if (term->no_value &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) parse_events__handle_error(err, term->err_val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) strdup("no value assigned for term"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) val = term->val.num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) if (strcmp(term->val.str, "?")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) if (verbose > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) pr_info("Invalid sysfs entry %s=%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) term->config, term->val.str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) parse_events__handle_error(err, term->err_val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) strdup("expected numeric value"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) if (pmu_resolve_param_term(term, head_terms, &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) max_val = pmu_format_max_value(format->bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if (val > max_val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) char *err_str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) parse_events__handle_error(err, term->err_val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) asprintf(&err_str,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) "value too big for format, maximum is %llu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) (unsigned long long)max_val) < 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) ? strdup("value too big for format")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) : err_str,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) * Assume we don't care if !err, in which case the value will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) * silently truncated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) pmu_format_value(format->bits, val, vp, zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) struct perf_event_attr *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) struct list_head *head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) bool zero, struct parse_events_error *err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) struct parse_events_term *term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) list_for_each_entry(term, head_terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) if (pmu_config_term(pmu_name, formats, attr, term, head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) zero, err))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) * Configures event's 'attr' parameter based on the:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) * 1) users input - specified in terms parameter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) * 2) pmu format definitions - specified by pmu parameter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) struct list_head *head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) struct parse_events_error *err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) bool zero = !!pmu->default_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) attr->type = pmu->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) return perf_pmu__config_terms(pmu->name, &pmu->format, attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) head_terms, zero, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) struct parse_events_term *term)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) struct perf_pmu_alias *alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) if (parse_events__is_hardcoded_term(term))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) if (term->val.num != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) if (pmu_find_format(&pmu->format, term->config))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) name = term->config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) if (strcasecmp(term->config, "event"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) name = term->val.str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) list_for_each_entry(alias, &pmu->aliases, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (!strcasecmp(alias->name, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) return alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) static int check_info_data(struct perf_pmu_alias *alias,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) struct perf_pmu_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) * Only one term in event definition can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) * define unit, scale and snapshot, fail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) * if there's more than one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) if ((info->unit && alias->unit[0]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) (info->scale && alias->scale) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) (info->snapshot && alias->snapshot))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) if (alias->unit[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) info->unit = alias->unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) if (alias->scale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) info->scale = alias->scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) if (alias->snapshot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) info->snapshot = alias->snapshot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) * Find alias in the terms list and replace it with the terms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) * defined for the alias
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) struct perf_pmu_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) struct parse_events_term *term, *h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) struct perf_pmu_alias *alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) info->per_pkg = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) * Mark unit and scale as not set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) * (different from default values, see below)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) info->unit = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) info->scale = 0.0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) info->snapshot = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) info->metric_expr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) info->metric_name = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) list_for_each_entry_safe(term, h, head_terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) alias = pmu_find_alias(pmu, term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) if (!alias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) ret = pmu_alias_terms(alias, &term->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) ret = check_info_data(alias, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) if (alias->per_pkg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) info->per_pkg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) info->metric_expr = alias->metric_expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) info->metric_name = alias->metric_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) list_del_init(&term->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) parse_events_term__delete(term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) * if no unit or scale foundin aliases, then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) * set defaults as for evsel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * unit cannot left to NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) if (info->unit == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) info->unit = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (info->scale == 0.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) info->scale = 1.0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) int perf_pmu__new_format(struct list_head *list, char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) int config, unsigned long *bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) struct perf_pmu_format *format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) format = zalloc(sizeof(*format));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) if (!format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) format->name = strdup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) format->value = config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) memcpy(format->bits, bits, sizeof(format->bits));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) list_add_tail(&format->list, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) void perf_pmu__set_format(unsigned long *bits, long from, long to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) long b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) if (!to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) to = from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) for (b = from; b <= to; b++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) set_bit(b, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) void perf_pmu__del_formats(struct list_head *formats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) struct perf_pmu_format *fmt, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) list_for_each_entry_safe(fmt, tmp, formats, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) list_del(&fmt->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) free(fmt->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) free(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) static int sub_non_neg(int a, int b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) if (b > a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) return a - b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) struct perf_pmu_alias *alias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) struct parse_events_term *term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) list_for_each_entry(term, &alias->terms, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) used += snprintf(buf + used, sub_non_neg(len, used),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) ",%s=%s", term->config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) term->val.str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (sub_non_neg(len, used) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) buf[used] = '/';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) used++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) if (sub_non_neg(len, used) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) buf[used] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) used++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) buf[len - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) struct perf_pmu_alias *alias)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) struct sevent {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) char *topic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) char *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) char *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) char *metric_expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) char *metric_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) int is_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) static int cmp_sevent(const void *a, const void *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) const struct sevent *as = a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) const struct sevent *bs = b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) /* Put extra events last */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (!!as->desc != !!bs->desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) return !!as->desc - !!bs->desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) if (as->topic && bs->topic) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) int n = strcmp(as->topic, bs->topic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) if (n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) /* Order CPU core events to be first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) if (as->is_cpu != bs->is_cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) return bs->is_cpu - as->is_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) return strcmp(as->name, bs->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) static void wordwrap(char *s, int start, int max, int corr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) int column = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) while (*s) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) int wlen = strcspn(s, " \t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) if (column + wlen >= max && column > start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) printf("\n%*s", start, "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) column = start + corr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) n = printf("%s%.*s", column > start ? " " : "", wlen, s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) if (n <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) s += wlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) column += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) s = skip_spaces(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) bool is_pmu_core(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) return !strcmp(name, "cpu") || is_arm_pmu_core(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) bool long_desc, bool details_flag, bool deprecated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) struct perf_pmu_alias *alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) char buf[1024];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) int printed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) int len, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) struct sevent *aliases;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) int numdesc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) int columns = pager_get_columns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) char *topic = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) pmu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) while ((pmu = perf_pmu__scan(pmu)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) list_for_each_entry(alias, &pmu->aliases, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) len++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) if (pmu->selectable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) len++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) aliases = zalloc(sizeof(struct sevent) * len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) if (!aliases)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) goto out_enomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) pmu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) while ((pmu = perf_pmu__scan(pmu)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) list_for_each_entry(alias, &pmu->aliases, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) char *name = alias->desc ? alias->name :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) format_alias(buf, sizeof(buf), pmu, alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) bool is_cpu = is_pmu_core(pmu->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) if (alias->deprecated && !deprecated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) if (event_glob != NULL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) !(strglobmatch_nocase(name, event_glob) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) (!is_cpu && strglobmatch_nocase(alias->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) event_glob)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) (alias->topic &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) strglobmatch_nocase(alias->topic, event_glob))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) if (is_cpu && !name_only && !alias->desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) name = format_alias_or(buf, sizeof(buf), pmu, alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) aliases[j].name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) if (is_cpu && !name_only && !alias->desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) aliases[j].name = format_alias_or(buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) sizeof(buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) pmu, alias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) aliases[j].name = strdup(aliases[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) if (!aliases[j].name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) goto out_enomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) aliases[j].desc = long_desc ? alias->long_desc :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) alias->desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) aliases[j].topic = alias->topic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) aliases[j].str = alias->str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) aliases[j].pmu = pmu->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) aliases[j].metric_expr = alias->metric_expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) aliases[j].metric_name = alias->metric_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) aliases[j].is_cpu = is_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) j++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) if (pmu->selectable &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) (event_glob == NULL || strglobmatch(pmu->name, event_glob))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) if (asprintf(&s, "%s//", pmu->name) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) goto out_enomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) aliases[j].name = s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) j++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) len = j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) for (j = 0; j < len; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) /* Skip duplicates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) if (name_only) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) printf("%s ", aliases[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) if (aliases[j].desc && !quiet_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (numdesc++ == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) if (aliases[j].topic && (!topic ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) strcmp(topic, aliases[j].topic))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) printf("%s%s:\n", topic ? "\n" : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) aliases[j].topic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) topic = aliases[j].topic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) printf(" %-50s\n", aliases[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) printf("%*s", 8, "[");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) wordwrap(aliases[j].desc, 8, columns, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) printf("]\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) if (details_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) if (aliases[j].metric_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) printf(" MetricName: %s", aliases[j].metric_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) if (aliases[j].metric_expr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) printf(" MetricExpr: %s", aliases[j].metric_expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) putchar('\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) printed++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) if (printed && pager_in_use())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) for (j = 0; j < len; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) zfree(&aliases[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) zfree(&aliases);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) out_enomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) printf("FATAL: not enough memory to print PMU events\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) if (aliases)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) bool pmu_have_event(const char *pname, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) struct perf_pmu *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) struct perf_pmu_alias *alias;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) pmu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) while ((pmu = perf_pmu__scan(pmu)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) if (strcmp(pname, pmu->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) list_for_each_entry(alias, &pmu->aliases, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) if (!strcmp(alias->name, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) const char *sysfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) snprintf(path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) if (!file_available(path))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) return fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) int ret = EOF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) va_start(args, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) file = perf_pmu__open_file(pmu, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) if (file) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) ret = vfscanf(file, fmt, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) static int perf_pmu__new_caps(struct list_head *list, char *name, char *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) struct perf_pmu_caps *caps = zalloc(sizeof(*caps));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) if (!caps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) caps->name = strdup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) if (!caps->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) goto free_caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) caps->value = strndup(value, strlen(value) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) if (!caps->value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) goto free_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) list_add_tail(&caps->list, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) free_name:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) zfree(caps->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) free_caps:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) free(caps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) * Reading/parsing the given pmu capabilities, which should be located at:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) * Return the number of capabilities
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) int perf_pmu__caps_parse(struct perf_pmu *pmu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) struct stat st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) char caps_path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) const char *sysfs = sysfs__mountpoint();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) DIR *caps_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) struct dirent *evt_ent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) int nr_caps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) if (!sysfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) snprintf(caps_path, PATH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) if (stat(caps_path, &st) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) return 0; /* no error if caps does not exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) caps_dir = opendir(caps_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) if (!caps_dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) while ((evt_ent = readdir(caps_dir)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) char path[PATH_MAX + NAME_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) char *name = evt_ent->d_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) char value[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) FILE *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (!strcmp(name, ".") || !strcmp(name, ".."))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) snprintf(path, sizeof(path), "%s/%s", caps_path, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) file = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) if (!file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) if (!fgets(value, sizeof(value), file) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) nr_caps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) fclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) closedir(caps_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) return nr_caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) }