Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Support for libpfm4 event encoding.
0004  *
0005  * Copyright 2020 Google LLC.
0006  */
0007 #include "util/cpumap.h"
0008 #include "util/debug.h"
0009 #include "util/event.h"
0010 #include "util/evlist.h"
0011 #include "util/evsel.h"
0012 #include "util/parse-events.h"
0013 #include "util/pmu.h"
0014 #include "util/pfm.h"
0015 
0016 #include <string.h>
0017 #include <linux/kernel.h>
0018 #include <perfmon/pfmlib_perf_event.h>
0019 
0020 static void libpfm_initialize(void)
0021 {
0022     int ret;
0023 
0024     ret = pfm_initialize();
0025     if (ret != PFM_SUCCESS) {
0026         ui__warning("libpfm failed to initialize: %s\n",
0027             pfm_strerror(ret));
0028     }
0029 }
0030 
0031 int parse_libpfm_events_option(const struct option *opt, const char *str,
0032             int unset __maybe_unused)
0033 {
0034     struct evlist *evlist = *(struct evlist **)opt->value;
0035     struct perf_event_attr attr;
0036     struct perf_pmu *pmu;
0037     struct evsel *evsel, *grp_leader = NULL;
0038     char *p, *q, *p_orig;
0039     const char *sep;
0040     int grp_evt = -1;
0041     int ret;
0042 
0043     libpfm_initialize();
0044 
0045     p_orig = p = strdup(str);
0046     if (!p)
0047         return -1;
0048     /*
0049      * force loading of the PMU list
0050      */
0051     perf_pmu__scan(NULL);
0052 
0053     for (q = p; strsep(&p, ",{}"); q = p) {
0054         sep = p ? str + (p - p_orig - 1) : "";
0055         if (*sep == '{') {
0056             if (grp_evt > -1) {
0057                 ui__error(
0058                     "nested event groups not supported\n");
0059                 goto error;
0060             }
0061             grp_evt++;
0062         }
0063 
0064         /* no event */
0065         if (*q == '\0') {
0066             if (*sep == '}') {
0067                 if (grp_evt < 0) {
0068                     ui__error("cannot close a non-existing event group\n");
0069                     goto error;
0070                 }
0071                 grp_evt--;
0072             }
0073             continue;
0074         }
0075 
0076         memset(&attr, 0, sizeof(attr));
0077         event_attr_init(&attr);
0078 
0079         ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3,
0080                         &attr, NULL, NULL);
0081 
0082         if (ret != PFM_SUCCESS) {
0083             ui__error("failed to parse event %s : %s\n", str,
0084                   pfm_strerror(ret));
0085             goto error;
0086         }
0087 
0088         pmu = perf_pmu__find_by_type((unsigned int)attr.type);
0089         evsel = parse_events__add_event(evlist->core.nr_entries,
0090                         &attr, q, /*metric_id=*/NULL,
0091                         pmu);
0092         if (evsel == NULL)
0093             goto error;
0094 
0095         evsel->is_libpfm_event = true;
0096 
0097         evlist__add(evlist, evsel);
0098 
0099         if (grp_evt == 0)
0100             grp_leader = evsel;
0101 
0102         if (grp_evt > -1) {
0103             evsel__set_leader(evsel, grp_leader);
0104             grp_leader->core.nr_members++;
0105             grp_evt++;
0106         }
0107 
0108         if (*sep == '}') {
0109             if (grp_evt < 0) {
0110                 ui__error(
0111                    "cannot close a non-existing event group\n");
0112                 goto error;
0113             }
0114             evlist->core.nr_groups++;
0115             grp_leader = NULL;
0116             grp_evt = -1;
0117         }
0118     }
0119     free(p_orig);
0120     return 0;
0121 error:
0122     free(p_orig);
0123     return -1;
0124 }
0125 
0126 static const char *srcs[PFM_ATTR_CTRL_MAX] = {
0127     [PFM_ATTR_CTRL_UNKNOWN] = "???",
0128     [PFM_ATTR_CTRL_PMU] = "PMU",
0129     [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
0130 };
0131 
0132 static void
0133 print_attr_flags(pfm_event_attr_info_t *info)
0134 {
0135     int n = 0;
0136 
0137     if (info->is_dfl) {
0138         printf("[default] ");
0139         n++;
0140     }
0141 
0142     if (info->is_precise) {
0143         printf("[precise] ");
0144         n++;
0145     }
0146 
0147     if (!n)
0148         printf("- ");
0149 }
0150 
0151 static void
0152 print_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc)
0153 {
0154     pfm_event_attr_info_t ainfo;
0155     const char *src;
0156     int j, ret;
0157 
0158     ainfo.size = sizeof(ainfo);
0159 
0160     printf("  %s\n", info->name);
0161     printf("    [%s]\n", info->desc);
0162     if (long_desc) {
0163         if (info->equiv)
0164             printf("      Equiv: %s\n", info->equiv);
0165 
0166         printf("      Code  : 0x%"PRIx64"\n", info->code);
0167     }
0168     pfm_for_each_event_attr(j, info) {
0169         ret = pfm_get_event_attr_info(info->idx, j,
0170                           PFM_OS_PERF_EVENT_EXT, &ainfo);
0171         if (ret != PFM_SUCCESS)
0172             continue;
0173 
0174         if (ainfo.type == PFM_ATTR_UMASK) {
0175             printf("      %s:%s\n", info->name, ainfo.name);
0176             printf("        [%s]\n", ainfo.desc);
0177         }
0178 
0179         if (!long_desc)
0180             continue;
0181 
0182         if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
0183             ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
0184 
0185         src = srcs[ainfo.ctrl];
0186         switch (ainfo.type) {
0187         case PFM_ATTR_UMASK:
0188             printf("        Umask : 0x%02"PRIx64" : %s: ",
0189                 ainfo.code, src);
0190             print_attr_flags(&ainfo);
0191             putchar('\n');
0192             break;
0193         case PFM_ATTR_MOD_BOOL:
0194             printf("      Modif : %s: [%s] : %s (boolean)\n", src,
0195                 ainfo.name, ainfo.desc);
0196             break;
0197         case PFM_ATTR_MOD_INTEGER:
0198             printf("      Modif : %s: [%s] : %s (integer)\n", src,
0199                 ainfo.name, ainfo.desc);
0200             break;
0201         case PFM_ATTR_NONE:
0202         case PFM_ATTR_RAW_UMASK:
0203         case PFM_ATTR_MAX:
0204         default:
0205             printf("      Attr  : %s: [%s] : %s\n", src,
0206                 ainfo.name, ainfo.desc);
0207         }
0208     }
0209 }
0210 
0211 /*
0212  * list all pmu::event:umask, pmu::event
0213  * printed events may not be all valid combinations of umask for an event
0214  */
0215 static void
0216 print_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
0217 {
0218     pfm_event_attr_info_t ainfo;
0219     int j, ret;
0220     bool has_umask = false;
0221 
0222     ainfo.size = sizeof(ainfo);
0223 
0224     pfm_for_each_event_attr(j, info) {
0225         ret = pfm_get_event_attr_info(info->idx, j,
0226                           PFM_OS_PERF_EVENT_EXT, &ainfo);
0227         if (ret != PFM_SUCCESS)
0228             continue;
0229 
0230         if (ainfo.type != PFM_ATTR_UMASK)
0231             continue;
0232 
0233         printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
0234         has_umask = true;
0235     }
0236     if (!has_umask)
0237         printf("%s::%s\n", pinfo->name, info->name);
0238 }
0239 
0240 void print_libpfm_events(bool name_only, bool long_desc)
0241 {
0242     pfm_event_info_t info;
0243     pfm_pmu_info_t pinfo;
0244     int i, p, ret;
0245 
0246     libpfm_initialize();
0247 
0248     /* initialize to zero to indicate ABI version */
0249     info.size  = sizeof(info);
0250     pinfo.size = sizeof(pinfo);
0251 
0252     if (!name_only)
0253         puts("\nList of pre-defined events (to be used in --pfm-events):\n");
0254 
0255     pfm_for_all_pmus(p) {
0256         bool printed_pmu = false;
0257 
0258         ret = pfm_get_pmu_info(p, &pinfo);
0259         if (ret != PFM_SUCCESS)
0260             continue;
0261 
0262         /* only print events that are supported by host HW */
0263         if (!pinfo.is_present)
0264             continue;
0265 
0266         /* handled by perf directly */
0267         if (pinfo.pmu == PFM_PMU_PERF_EVENT)
0268             continue;
0269 
0270         for (i = pinfo.first_event; i != -1;
0271              i = pfm_get_event_next(i)) {
0272 
0273             ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT,
0274                         &info);
0275             if (ret != PFM_SUCCESS)
0276                 continue;
0277 
0278             if (!name_only && !printed_pmu) {
0279                 printf("%s:\n", pinfo.name);
0280                 printed_pmu = true;
0281             }
0282 
0283             if (!name_only)
0284                 print_libpfm_events_detailed(&info, long_desc);
0285             else
0286                 print_libpfm_events_raw(&pinfo, &info);
0287         }
0288         if (!name_only && printed_pmu)
0289             putchar('\n');
0290     }
0291 }