linux/tools/perf/util/parse-events-hybrid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/err.h>
   3#include <linux/zalloc.h>
   4#include <errno.h>
   5#include <sys/types.h>
   6#include <sys/stat.h>
   7#include <fcntl.h>
   8#include <sys/param.h>
   9#include "evlist.h"
  10#include "evsel.h"
  11#include "parse-events.h"
  12#include "parse-events-hybrid.h"
  13#include "debug.h"
  14#include "pmu.h"
  15#include "pmu-hybrid.h"
  16#include "perf.h"
  17
  18static void config_hybrid_attr(struct perf_event_attr *attr,
  19                               int type, int pmu_type)
  20{
  21        /*
  22         * attr.config layout for type PERF_TYPE_HARDWARE and
  23         * PERF_TYPE_HW_CACHE
  24         *
  25         * PERF_TYPE_HARDWARE:                 0xEEEEEEEE000000AA
  26         *                                     AA: hardware event ID
  27         *                                     EEEEEEEE: PMU type ID
  28         * PERF_TYPE_HW_CACHE:                 0xEEEEEEEE00DDCCBB
  29         *                                     BB: hardware cache ID
  30         *                                     CC: hardware cache op ID
  31         *                                     DD: hardware cache op result ID
  32         *                                     EEEEEEEE: PMU type ID
  33         * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
  34         */
  35        attr->type = type;
  36        attr->config = attr->config | ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
  37}
  38
  39static int create_event_hybrid(__u32 config_type, int *idx,
  40                               struct list_head *list,
  41                               struct perf_event_attr *attr, const char *name,
  42                               const char *metric_id,
  43                               struct list_head *config_terms,
  44                               struct perf_pmu *pmu)
  45{
  46        struct evsel *evsel;
  47        __u32 type = attr->type;
  48        __u64 config = attr->config;
  49
  50        config_hybrid_attr(attr, config_type, pmu->type);
  51        evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
  52                                               pmu, config_terms);
  53        if (evsel)
  54                evsel->pmu_name = strdup(pmu->name);
  55        else
  56                return -ENOMEM;
  57
  58        attr->type = type;
  59        attr->config = config;
  60        return 0;
  61}
  62
  63static int pmu_cmp(struct parse_events_state *parse_state,
  64                   struct perf_pmu *pmu)
  65{
  66        if (!parse_state->hybrid_pmu_name)
  67                return 0;
  68
  69        return strcmp(parse_state->hybrid_pmu_name, pmu->name);
  70}
  71
  72static int add_hw_hybrid(struct parse_events_state *parse_state,
  73                         struct list_head *list, struct perf_event_attr *attr,
  74                         const char *name, const char *metric_id,
  75                         struct list_head *config_terms)
  76{
  77        struct perf_pmu *pmu;
  78        int ret;
  79
  80        perf_pmu__for_each_hybrid_pmu(pmu) {
  81                LIST_HEAD(terms);
  82
  83                if (pmu_cmp(parse_state, pmu))
  84                        continue;
  85
  86                copy_config_terms(&terms, config_terms);
  87                ret = create_event_hybrid(PERF_TYPE_HARDWARE,
  88                                          &parse_state->idx, list, attr, name,
  89                                          metric_id, &terms, pmu);
  90                free_config_terms(&terms);
  91                if (ret)
  92                        return ret;
  93        }
  94
  95        return 0;
  96}
  97
  98static int create_raw_event_hybrid(int *idx, struct list_head *list,
  99                                   struct perf_event_attr *attr,
 100                                   const char *name,
 101                                   const char *metric_id,
 102                                   struct list_head *config_terms,
 103                                   struct perf_pmu *pmu)
 104{
 105        struct evsel *evsel;
 106
 107        attr->type = pmu->type;
 108        evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
 109                                               pmu, config_terms);
 110        if (evsel)
 111                evsel->pmu_name = strdup(pmu->name);
 112        else
 113                return -ENOMEM;
 114
 115        return 0;
 116}
 117
 118static int add_raw_hybrid(struct parse_events_state *parse_state,
 119                          struct list_head *list, struct perf_event_attr *attr,
 120                          const char *name, const char *metric_id,
 121                          struct list_head *config_terms)
 122{
 123        struct perf_pmu *pmu;
 124        int ret;
 125
 126        perf_pmu__for_each_hybrid_pmu(pmu) {
 127                LIST_HEAD(terms);
 128
 129                if (pmu_cmp(parse_state, pmu))
 130                        continue;
 131
 132                copy_config_terms(&terms, config_terms);
 133                ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
 134                                              name, metric_id, &terms, pmu);
 135                free_config_terms(&terms);
 136                if (ret)
 137                        return ret;
 138        }
 139
 140        return 0;
 141}
 142
 143int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
 144                                     struct list_head *list,
 145                                     struct perf_event_attr *attr,
 146                                     const char *name, const char *metric_id,
 147                                     struct list_head *config_terms,
 148                                     bool *hybrid)
 149{
 150        *hybrid = false;
 151        if (attr->type == PERF_TYPE_SOFTWARE)
 152                return 0;
 153
 154        if (!perf_pmu__has_hybrid())
 155                return 0;
 156
 157        *hybrid = true;
 158        if (attr->type != PERF_TYPE_RAW) {
 159                return add_hw_hybrid(parse_state, list, attr, name, metric_id,
 160                                     config_terms);
 161        }
 162
 163        return add_raw_hybrid(parse_state, list, attr, name, metric_id,
 164                              config_terms);
 165}
 166
 167int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
 168                                   struct perf_event_attr *attr,
 169                                   const char *name,
 170                                   const char *metric_id,
 171                                   struct list_head *config_terms,
 172                                   bool *hybrid,
 173                                   struct parse_events_state *parse_state)
 174{
 175        struct perf_pmu *pmu;
 176        int ret;
 177
 178        *hybrid = false;
 179        if (!perf_pmu__has_hybrid())
 180                return 0;
 181
 182        *hybrid = true;
 183        perf_pmu__for_each_hybrid_pmu(pmu) {
 184                LIST_HEAD(terms);
 185
 186                if (pmu_cmp(parse_state, pmu))
 187                        continue;
 188
 189                copy_config_terms(&terms, config_terms);
 190                ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
 191                                          attr, name, metric_id, &terms, pmu);
 192                free_config_terms(&terms);
 193                if (ret)
 194                        return ret;
 195        }
 196
 197        return 0;
 198}
 199