parse-events-hybrid.c (5133B)
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->evlist && parse_state->evlist->hybrid_pmu_name) 67 return strcmp(parse_state->evlist->hybrid_pmu_name, pmu->name); 68 69 if (parse_state->hybrid_pmu_name) 70 return strcmp(parse_state->hybrid_pmu_name, pmu->name); 71 72 return 0; 73} 74 75static int add_hw_hybrid(struct parse_events_state *parse_state, 76 struct list_head *list, struct perf_event_attr *attr, 77 const char *name, const char *metric_id, 78 struct list_head *config_terms) 79{ 80 struct perf_pmu *pmu; 81 int ret; 82 83 perf_pmu__for_each_hybrid_pmu(pmu) { 84 LIST_HEAD(terms); 85 86 if (pmu_cmp(parse_state, pmu)) 87 continue; 88 89 copy_config_terms(&terms, config_terms); 90 ret = create_event_hybrid(PERF_TYPE_HARDWARE, 91 &parse_state->idx, list, attr, name, 92 metric_id, &terms, pmu); 93 free_config_terms(&terms); 94 if (ret) 95 return ret; 96 } 97 98 return 0; 99} 100 101static int create_raw_event_hybrid(int *idx, struct list_head *list, 102 struct perf_event_attr *attr, 103 const char *name, 104 const char *metric_id, 105 struct list_head *config_terms, 106 struct perf_pmu *pmu) 107{ 108 struct evsel *evsel; 109 110 attr->type = pmu->type; 111 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id, 112 pmu, config_terms); 113 if (evsel) 114 evsel->pmu_name = strdup(pmu->name); 115 else 116 return -ENOMEM; 117 118 return 0; 119} 120 121static int add_raw_hybrid(struct parse_events_state *parse_state, 122 struct list_head *list, struct perf_event_attr *attr, 123 const char *name, const char *metric_id, 124 struct list_head *config_terms) 125{ 126 struct perf_pmu *pmu; 127 int ret; 128 129 perf_pmu__for_each_hybrid_pmu(pmu) { 130 LIST_HEAD(terms); 131 132 if (pmu_cmp(parse_state, pmu)) 133 continue; 134 135 copy_config_terms(&terms, config_terms); 136 ret = create_raw_event_hybrid(&parse_state->idx, list, attr, 137 name, metric_id, &terms, pmu); 138 free_config_terms(&terms); 139 if (ret) 140 return ret; 141 } 142 143 return 0; 144} 145 146int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state, 147 struct list_head *list, 148 struct perf_event_attr *attr, 149 const char *name, const char *metric_id, 150 struct list_head *config_terms, 151 bool *hybrid) 152{ 153 *hybrid = false; 154 if (attr->type == PERF_TYPE_SOFTWARE) 155 return 0; 156 157 if (!perf_pmu__has_hybrid()) 158 return 0; 159 160 *hybrid = true; 161 if (attr->type != PERF_TYPE_RAW) { 162 return add_hw_hybrid(parse_state, list, attr, name, metric_id, 163 config_terms); 164 } 165 166 return add_raw_hybrid(parse_state, list, attr, name, metric_id, 167 config_terms); 168} 169 170int parse_events__add_cache_hybrid(struct list_head *list, int *idx, 171 struct perf_event_attr *attr, 172 const char *name, 173 const char *metric_id, 174 struct list_head *config_terms, 175 bool *hybrid, 176 struct parse_events_state *parse_state) 177{ 178 struct perf_pmu *pmu; 179 int ret; 180 181 *hybrid = false; 182 if (!perf_pmu__has_hybrid()) 183 return 0; 184 185 *hybrid = true; 186 perf_pmu__for_each_hybrid_pmu(pmu) { 187 LIST_HEAD(terms); 188 189 if (pmu_cmp(parse_state, pmu)) 190 continue; 191 192 copy_config_terms(&terms, config_terms); 193 ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list, 194 attr, name, metric_id, &terms, pmu); 195 free_config_terms(&terms); 196 if (ret) 197 return ret; 198 } 199 200 return 0; 201}