linux/tools/perf/util/pfm.c
<<
>>
Prefs
   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
  20static 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
  31int 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;
 111error:
 112        free(p_orig);
 113        return -1;
 114}
 115
 116static 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
 122static void
 123print_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
 141static void
 142print_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 */
 205static void
 206print_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
 230void 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