1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for libpfm4 event encoding. 4 * 5 * Copyright 2020 Google LLC. 6 */ 7 #include "util/cpumap.h" 8 #include "util/debug.h" 9 #include "util/event.h" 10 #include "util/evlist.h" 11 #include "util/evsel.h" 12 #include "util/parse-events.h" 13 #include "util/pmu.h" 14 #include "util/pfm.h" 15 16 #include <string.h> 17 #include <linux/kernel.h> 18 #include <perfmon/pfmlib_perf_event.h> 19 20 static void libpfm_initialize(void) 21 { 22 int ret; 23 24 ret = pfm_initialize(); 25 if (ret != PFM_SUCCESS) { 26 ui__warning("libpfm failed to initialize: %s\n", 27 pfm_strerror(ret)); 28 } 29 } 30 31 int parse_libpfm_events_option(const struct option *opt, const char *str, 32 int unset __maybe_unused) 33 { 34 struct evlist *evlist = *(struct evlist **)opt->value; 35 struct perf_event_attr attr; 36 struct perf_pmu *pmu; 37 struct evsel *evsel, *grp_leader = NULL; 38 char *p, *q, *p_orig; 39 const char *sep; 40 int grp_evt = -1; 41 int ret; 42 43 libpfm_initialize(); 44 45 p_orig = p = strdup(str); 46 if (!p) 47 return -1; 48 /* 49 * force loading of the PMU list 50 */ 51 perf_pmu__scan(NULL); 52 53 for (q = p; strsep(&p, ",{}"); q = p) { 54 sep = p ? str + (p - p_orig - 1) : ""; 55 if (*sep == '{') { 56 if (grp_evt > -1) { 57 ui__error( 58 "nested event groups not supported\n"); 59 goto error; 60 } 61 grp_evt++; 62 } 63 64 /* no event */ 65 if (*q == '\0') 66 continue; 67 68 memset(&attr, 0, sizeof(attr)); 69 event_attr_init(&attr); 70 71 ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3, 72 &attr, NULL, NULL); 73 74 if (ret != PFM_SUCCESS) { 75 ui__error("failed to parse event %s : %s\n", str, 76 pfm_strerror(ret)); 77 goto error; 78 } 79 80 pmu = perf_pmu__find_by_type((unsigned int)attr.type); 81 evsel = parse_events__add_event(evlist->core.nr_entries, 82 &attr, q, pmu); 83 if (evsel == NULL) 84 goto error; 85 86 evsel->is_libpfm_event = true; 87 88 evlist__add(evlist, evsel); 89 90 if (grp_evt == 0) 91 grp_leader = evsel; 92 93 if (grp_evt > -1) { 94 evsel->leader = grp_leader; 95 grp_leader->core.nr_members++; 96 grp_evt++; 97 } 98 99 if (*sep == '}') { 100 if (grp_evt < 0) { 101 ui__error( 102 "cannot close a non-existing event group\n"); 103 goto error; 104 } 105 evlist->nr_groups++; 106 grp_leader = NULL; 107 grp_evt = -1; 108 } 109 } 110 return 0; 111 error: 112 free(p_orig); 113 return -1; 114 } 115 116 static const char *srcs[PFM_ATTR_CTRL_MAX] = { 117 [PFM_ATTR_CTRL_UNKNOWN] = "???", 118 [PFM_ATTR_CTRL_PMU] = "PMU", 119 [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event", 120 }; 121 122 static void 123 print_attr_flags(pfm_event_attr_info_t *info) 124 { 125 int n = 0; 126 127 if (info->is_dfl) { 128 printf("[default] "); 129 n++; 130 } 131 132 if (info->is_precise) { 133 printf("[precise] "); 134 n++; 135 } 136 137 if (!n) 138 printf("- "); 139 } 140 141 static void 142 print_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc) 143 { 144 pfm_event_attr_info_t ainfo; 145 const char *src; 146 int j, ret; 147 148 ainfo.size = sizeof(ainfo); 149 150 printf(" %s\n", info->name); 151 printf(" [%s]\n", info->desc); 152 if (long_desc) { 153 if (info->equiv) 154 printf(" Equiv: %s\n", info->equiv); 155 156 printf(" Code : 0x%"PRIx64"\n", info->code); 157 } 158 pfm_for_each_event_attr(j, info) { 159 ret = pfm_get_event_attr_info(info->idx, j, 160 PFM_OS_PERF_EVENT_EXT, &ainfo); 161 if (ret != PFM_SUCCESS) 162 continue; 163 164 if (ainfo.type == PFM_ATTR_UMASK) { 165 printf(" %s:%s\n", info->name, ainfo.name); 166 printf(" [%s]\n", ainfo.desc); 167 } 168 169 if (!long_desc) 170 continue; 171 172 if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) 173 ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN; 174 175 src = srcs[ainfo.ctrl]; 176 switch (ainfo.type) { 177 case PFM_ATTR_UMASK: 178 printf(" Umask : 0x%02"PRIx64" : %s: ", 179 ainfo.code, src); 180 print_attr_flags(&ainfo); 181 putchar('\n'); 182 break; 183 case PFM_ATTR_MOD_BOOL: 184 printf(" Modif : %s: [%s] : %s (boolean)\n", src, 185 ainfo.name, ainfo.desc); 186 break; 187 case PFM_ATTR_MOD_INTEGER: 188 printf(" Modif : %s: [%s] : %s (integer)\n", src, 189 ainfo.name, ainfo.desc); 190 break; 191 case PFM_ATTR_NONE: 192 case PFM_ATTR_RAW_UMASK: 193 case PFM_ATTR_MAX: 194 default: 195 printf(" Attr : %s: [%s] : %s\n", src, 196 ainfo.name, ainfo.desc); 197 } 198 } 199 } 200 201 /* 202 * list all pmu::event:umask, pmu::event 203 * printed events may not be all valid combinations of umask for an event 204 */ 205 static void 206 print_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info) 207 { 208 pfm_event_attr_info_t ainfo; 209 int j, ret; 210 bool has_umask = false; 211 212 ainfo.size = sizeof(ainfo); 213 214 pfm_for_each_event_attr(j, info) { 215 ret = pfm_get_event_attr_info(info->idx, j, 216 PFM_OS_PERF_EVENT_EXT, &ainfo); 217 if (ret != PFM_SUCCESS) 218 continue; 219 220 if (ainfo.type != PFM_ATTR_UMASK) 221 continue; 222 223 printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name); 224 has_umask = true; 225 } 226 if (!has_umask) 227 printf("%s::%s\n", pinfo->name, info->name); 228 } 229 230 void print_libpfm_events(bool name_only, bool long_desc) 231 { 232 pfm_event_info_t info; 233 pfm_pmu_info_t pinfo; 234 int i, p, ret; 235 236 libpfm_initialize(); 237 238 /* initialize to zero to indicate ABI version */ 239 info.size = sizeof(info); 240 pinfo.size = sizeof(pinfo); 241 242 if (!name_only) 243 puts("\nList of pre-defined events (to be used in --pfm-events):\n"); 244 245 pfm_for_all_pmus(p) { 246 bool printed_pmu = false; 247 248 ret = pfm_get_pmu_info(p, &pinfo); 249 if (ret != PFM_SUCCESS) 250 continue; 251 252 /* only print events that are supported by host HW */ 253 if (!pinfo.is_present) 254 continue; 255 256 /* handled by perf directly */ 257 if (pinfo.pmu == PFM_PMU_PERF_EVENT) 258 continue; 259 260 for (i = pinfo.first_event; i != -1; 261 i = pfm_get_event_next(i)) { 262 263 ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT, 264 &info); 265 if (ret != PFM_SUCCESS) 266 continue; 267 268 if (!name_only && !printed_pmu) { 269 printf("%s:\n", pinfo.name); 270 printed_pmu = true; 271 } 272 273 if (!name_only) 274 print_libpfm_events_detailed(&info, long_desc); 275 else 276 print_libpfm_events_raw(&pinfo, &info); 277 } 278 if (!name_only && printed_pmu) 279 putchar('\n'); 280 } 281 } 282