18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for libpfm4 event encoding. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2020 Google LLC. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include "util/cpumap.h" 88c2ecf20Sopenharmony_ci#include "util/debug.h" 98c2ecf20Sopenharmony_ci#include "util/event.h" 108c2ecf20Sopenharmony_ci#include "util/evlist.h" 118c2ecf20Sopenharmony_ci#include "util/evsel.h" 128c2ecf20Sopenharmony_ci#include "util/parse-events.h" 138c2ecf20Sopenharmony_ci#include "util/pmu.h" 148c2ecf20Sopenharmony_ci#include "util/pfm.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <string.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <perfmon/pfmlib_perf_event.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void libpfm_initialize(void) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci int ret; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci ret = pfm_initialize(); 258c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) { 268c2ecf20Sopenharmony_ci ui__warning("libpfm failed to initialize: %s\n", 278c2ecf20Sopenharmony_ci pfm_strerror(ret)); 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciint parse_libpfm_events_option(const struct option *opt, const char *str, 328c2ecf20Sopenharmony_ci int unset __maybe_unused) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct evlist *evlist = *(struct evlist **)opt->value; 358c2ecf20Sopenharmony_ci struct perf_event_attr attr; 368c2ecf20Sopenharmony_ci struct perf_pmu *pmu; 378c2ecf20Sopenharmony_ci struct evsel *evsel, *grp_leader = NULL; 388c2ecf20Sopenharmony_ci char *p, *q, *p_orig; 398c2ecf20Sopenharmony_ci const char *sep; 408c2ecf20Sopenharmony_ci int grp_evt = -1; 418c2ecf20Sopenharmony_ci int ret; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci libpfm_initialize(); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci p_orig = p = strdup(str); 468c2ecf20Sopenharmony_ci if (!p) 478c2ecf20Sopenharmony_ci return -1; 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * force loading of the PMU list 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci perf_pmu__scan(NULL); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (q = p; strsep(&p, ",{}"); q = p) { 548c2ecf20Sopenharmony_ci sep = p ? str + (p - p_orig - 1) : ""; 558c2ecf20Sopenharmony_ci if (*sep == '{') { 568c2ecf20Sopenharmony_ci if (grp_evt > -1) { 578c2ecf20Sopenharmony_ci ui__error( 588c2ecf20Sopenharmony_ci "nested event groups not supported\n"); 598c2ecf20Sopenharmony_ci goto error; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci grp_evt++; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* no event */ 658c2ecf20Sopenharmony_ci if (*q == '\0') 668c2ecf20Sopenharmony_ci continue; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 698c2ecf20Sopenharmony_ci event_attr_init(&attr); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3, 728c2ecf20Sopenharmony_ci &attr, NULL, NULL); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) { 758c2ecf20Sopenharmony_ci ui__error("failed to parse event %s : %s\n", str, 768c2ecf20Sopenharmony_ci pfm_strerror(ret)); 778c2ecf20Sopenharmony_ci goto error; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci pmu = perf_pmu__find_by_type((unsigned int)attr.type); 818c2ecf20Sopenharmony_ci evsel = parse_events__add_event(evlist->core.nr_entries, 828c2ecf20Sopenharmony_ci &attr, q, pmu); 838c2ecf20Sopenharmony_ci if (evsel == NULL) 848c2ecf20Sopenharmony_ci goto error; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci evsel->is_libpfm_event = true; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci evlist__add(evlist, evsel); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (grp_evt == 0) 918c2ecf20Sopenharmony_ci grp_leader = evsel; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (grp_evt > -1) { 948c2ecf20Sopenharmony_ci evsel->leader = grp_leader; 958c2ecf20Sopenharmony_ci grp_leader->core.nr_members++; 968c2ecf20Sopenharmony_ci grp_evt++; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (*sep == '}') { 1008c2ecf20Sopenharmony_ci if (grp_evt < 0) { 1018c2ecf20Sopenharmony_ci ui__error( 1028c2ecf20Sopenharmony_ci "cannot close a non-existing event group\n"); 1038c2ecf20Sopenharmony_ci goto error; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci evlist->nr_groups++; 1068c2ecf20Sopenharmony_ci grp_leader = NULL; 1078c2ecf20Sopenharmony_ci grp_evt = -1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_cierror: 1128c2ecf20Sopenharmony_ci free(p_orig); 1138c2ecf20Sopenharmony_ci return -1; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const char *srcs[PFM_ATTR_CTRL_MAX] = { 1178c2ecf20Sopenharmony_ci [PFM_ATTR_CTRL_UNKNOWN] = "???", 1188c2ecf20Sopenharmony_ci [PFM_ATTR_CTRL_PMU] = "PMU", 1198c2ecf20Sopenharmony_ci [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event", 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void 1238c2ecf20Sopenharmony_ciprint_attr_flags(pfm_event_attr_info_t *info) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int n = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (info->is_dfl) { 1288c2ecf20Sopenharmony_ci printf("[default] "); 1298c2ecf20Sopenharmony_ci n++; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (info->is_precise) { 1338c2ecf20Sopenharmony_ci printf("[precise] "); 1348c2ecf20Sopenharmony_ci n++; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (!n) 1388c2ecf20Sopenharmony_ci printf("- "); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void 1428c2ecf20Sopenharmony_ciprint_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci pfm_event_attr_info_t ainfo; 1458c2ecf20Sopenharmony_ci const char *src; 1468c2ecf20Sopenharmony_ci int j, ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ainfo.size = sizeof(ainfo); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci printf(" %s\n", info->name); 1518c2ecf20Sopenharmony_ci printf(" [%s]\n", info->desc); 1528c2ecf20Sopenharmony_ci if (long_desc) { 1538c2ecf20Sopenharmony_ci if (info->equiv) 1548c2ecf20Sopenharmony_ci printf(" Equiv: %s\n", info->equiv); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci printf(" Code : 0x%"PRIx64"\n", info->code); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci pfm_for_each_event_attr(j, info) { 1598c2ecf20Sopenharmony_ci ret = pfm_get_event_attr_info(info->idx, j, 1608c2ecf20Sopenharmony_ci PFM_OS_PERF_EVENT_EXT, &ainfo); 1618c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) 1628c2ecf20Sopenharmony_ci continue; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (ainfo.type == PFM_ATTR_UMASK) { 1658c2ecf20Sopenharmony_ci printf(" %s:%s\n", info->name, ainfo.name); 1668c2ecf20Sopenharmony_ci printf(" [%s]\n", ainfo.desc); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!long_desc) 1708c2ecf20Sopenharmony_ci continue; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) 1738c2ecf20Sopenharmony_ci ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci src = srcs[ainfo.ctrl]; 1768c2ecf20Sopenharmony_ci switch (ainfo.type) { 1778c2ecf20Sopenharmony_ci case PFM_ATTR_UMASK: 1788c2ecf20Sopenharmony_ci printf(" Umask : 0x%02"PRIx64" : %s: ", 1798c2ecf20Sopenharmony_ci ainfo.code, src); 1808c2ecf20Sopenharmony_ci print_attr_flags(&ainfo); 1818c2ecf20Sopenharmony_ci putchar('\n'); 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case PFM_ATTR_MOD_BOOL: 1848c2ecf20Sopenharmony_ci printf(" Modif : %s: [%s] : %s (boolean)\n", src, 1858c2ecf20Sopenharmony_ci ainfo.name, ainfo.desc); 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case PFM_ATTR_MOD_INTEGER: 1888c2ecf20Sopenharmony_ci printf(" Modif : %s: [%s] : %s (integer)\n", src, 1898c2ecf20Sopenharmony_ci ainfo.name, ainfo.desc); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case PFM_ATTR_NONE: 1928c2ecf20Sopenharmony_ci case PFM_ATTR_RAW_UMASK: 1938c2ecf20Sopenharmony_ci case PFM_ATTR_MAX: 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci printf(" Attr : %s: [%s] : %s\n", src, 1968c2ecf20Sopenharmony_ci ainfo.name, ainfo.desc); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * list all pmu::event:umask, pmu::event 2038c2ecf20Sopenharmony_ci * printed events may not be all valid combinations of umask for an event 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic void 2068c2ecf20Sopenharmony_ciprint_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci pfm_event_attr_info_t ainfo; 2098c2ecf20Sopenharmony_ci int j, ret; 2108c2ecf20Sopenharmony_ci bool has_umask = false; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ainfo.size = sizeof(ainfo); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci pfm_for_each_event_attr(j, info) { 2158c2ecf20Sopenharmony_ci ret = pfm_get_event_attr_info(info->idx, j, 2168c2ecf20Sopenharmony_ci PFM_OS_PERF_EVENT_EXT, &ainfo); 2178c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) 2188c2ecf20Sopenharmony_ci continue; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (ainfo.type != PFM_ATTR_UMASK) 2218c2ecf20Sopenharmony_ci continue; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name); 2248c2ecf20Sopenharmony_ci has_umask = true; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci if (!has_umask) 2278c2ecf20Sopenharmony_ci printf("%s::%s\n", pinfo->name, info->name); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_civoid print_libpfm_events(bool name_only, bool long_desc) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci pfm_event_info_t info; 2338c2ecf20Sopenharmony_ci pfm_pmu_info_t pinfo; 2348c2ecf20Sopenharmony_ci int i, p, ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci libpfm_initialize(); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* initialize to zero to indicate ABI version */ 2398c2ecf20Sopenharmony_ci info.size = sizeof(info); 2408c2ecf20Sopenharmony_ci pinfo.size = sizeof(pinfo); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!name_only) 2438c2ecf20Sopenharmony_ci puts("\nList of pre-defined events (to be used in --pfm-events):\n"); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci pfm_for_all_pmus(p) { 2468c2ecf20Sopenharmony_ci bool printed_pmu = false; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = pfm_get_pmu_info(p, &pinfo); 2498c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) 2508c2ecf20Sopenharmony_ci continue; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* only print events that are supported by host HW */ 2538c2ecf20Sopenharmony_ci if (!pinfo.is_present) 2548c2ecf20Sopenharmony_ci continue; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* handled by perf directly */ 2578c2ecf20Sopenharmony_ci if (pinfo.pmu == PFM_PMU_PERF_EVENT) 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci for (i = pinfo.first_event; i != -1; 2618c2ecf20Sopenharmony_ci i = pfm_get_event_next(i)) { 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT, 2648c2ecf20Sopenharmony_ci &info); 2658c2ecf20Sopenharmony_ci if (ret != PFM_SUCCESS) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (!name_only && !printed_pmu) { 2698c2ecf20Sopenharmony_ci printf("%s:\n", pinfo.name); 2708c2ecf20Sopenharmony_ci printed_pmu = true; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!name_only) 2748c2ecf20Sopenharmony_ci print_libpfm_events_detailed(&info, long_desc); 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci print_libpfm_events_raw(&pinfo, &info); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci if (!name_only && printed_pmu) 2798c2ecf20Sopenharmony_ci putchar('\n'); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 282