0001
0002 #include <linux/err.h>
0003 #include <linux/zalloc.h>
0004 #include <errno.h>
0005 #include <sys/types.h>
0006 #include <sys/stat.h>
0007 #include <fcntl.h>
0008 #include <sys/param.h>
0009 #include "evlist.h"
0010 #include "evsel.h"
0011 #include "parse-events.h"
0012 #include "parse-events-hybrid.h"
0013 #include "debug.h"
0014 #include "pmu.h"
0015 #include "pmu-hybrid.h"
0016 #include "perf.h"
0017
0018 static void config_hybrid_attr(struct perf_event_attr *attr,
0019 int type, int pmu_type)
0020 {
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 attr->type = type;
0036 attr->config = (attr->config & PERF_HW_EVENT_MASK) |
0037 ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
0038 }
0039
0040 static int create_event_hybrid(__u32 config_type, int *idx,
0041 struct list_head *list,
0042 struct perf_event_attr *attr, const char *name,
0043 const char *metric_id,
0044 struct list_head *config_terms,
0045 struct perf_pmu *pmu)
0046 {
0047 struct evsel *evsel;
0048 __u32 type = attr->type;
0049 __u64 config = attr->config;
0050
0051 config_hybrid_attr(attr, config_type, pmu->type);
0052
0053
0054
0055
0056
0057
0058
0059 if (attr->type == PERF_TYPE_HW_CACHE
0060 && !is_event_supported(attr->type, attr->config))
0061 return 0;
0062
0063 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
0064 pmu, config_terms);
0065 if (evsel) {
0066 evsel->pmu_name = strdup(pmu->name);
0067 if (!evsel->pmu_name)
0068 return -ENOMEM;
0069 } else
0070 return -ENOMEM;
0071 attr->type = type;
0072 attr->config = config;
0073 return 0;
0074 }
0075
0076 static int pmu_cmp(struct parse_events_state *parse_state,
0077 struct perf_pmu *pmu)
0078 {
0079 if (parse_state->evlist && parse_state->evlist->hybrid_pmu_name)
0080 return strcmp(parse_state->evlist->hybrid_pmu_name, pmu->name);
0081
0082 if (parse_state->hybrid_pmu_name)
0083 return strcmp(parse_state->hybrid_pmu_name, pmu->name);
0084
0085 return 0;
0086 }
0087
0088 static int add_hw_hybrid(struct parse_events_state *parse_state,
0089 struct list_head *list, struct perf_event_attr *attr,
0090 const char *name, const char *metric_id,
0091 struct list_head *config_terms)
0092 {
0093 struct perf_pmu *pmu;
0094 int ret;
0095
0096 perf_pmu__for_each_hybrid_pmu(pmu) {
0097 LIST_HEAD(terms);
0098
0099 if (pmu_cmp(parse_state, pmu))
0100 continue;
0101
0102 copy_config_terms(&terms, config_terms);
0103 ret = create_event_hybrid(PERF_TYPE_HARDWARE,
0104 &parse_state->idx, list, attr, name,
0105 metric_id, &terms, pmu);
0106 free_config_terms(&terms);
0107 if (ret)
0108 return ret;
0109 }
0110
0111 return 0;
0112 }
0113
0114 static int create_raw_event_hybrid(int *idx, struct list_head *list,
0115 struct perf_event_attr *attr,
0116 const char *name,
0117 const char *metric_id,
0118 struct list_head *config_terms,
0119 struct perf_pmu *pmu)
0120 {
0121 struct evsel *evsel;
0122
0123 attr->type = pmu->type;
0124 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
0125 pmu, config_terms);
0126 if (evsel)
0127 evsel->pmu_name = strdup(pmu->name);
0128 else
0129 return -ENOMEM;
0130
0131 return 0;
0132 }
0133
0134 static int add_raw_hybrid(struct parse_events_state *parse_state,
0135 struct list_head *list, struct perf_event_attr *attr,
0136 const char *name, const char *metric_id,
0137 struct list_head *config_terms)
0138 {
0139 struct perf_pmu *pmu;
0140 int ret;
0141
0142 perf_pmu__for_each_hybrid_pmu(pmu) {
0143 LIST_HEAD(terms);
0144
0145 if (pmu_cmp(parse_state, pmu))
0146 continue;
0147
0148 copy_config_terms(&terms, config_terms);
0149 ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
0150 name, metric_id, &terms, pmu);
0151 free_config_terms(&terms);
0152 if (ret)
0153 return ret;
0154 }
0155
0156 return 0;
0157 }
0158
0159 int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
0160 struct list_head *list,
0161 struct perf_event_attr *attr,
0162 const char *name, const char *metric_id,
0163 struct list_head *config_terms,
0164 bool *hybrid)
0165 {
0166 *hybrid = false;
0167 if (attr->type == PERF_TYPE_SOFTWARE)
0168 return 0;
0169
0170 if (!perf_pmu__has_hybrid())
0171 return 0;
0172
0173 *hybrid = true;
0174 if (attr->type != PERF_TYPE_RAW) {
0175 return add_hw_hybrid(parse_state, list, attr, name, metric_id,
0176 config_terms);
0177 }
0178
0179 return add_raw_hybrid(parse_state, list, attr, name, metric_id,
0180 config_terms);
0181 }
0182
0183 int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
0184 struct perf_event_attr *attr,
0185 const char *name,
0186 const char *metric_id,
0187 struct list_head *config_terms,
0188 bool *hybrid,
0189 struct parse_events_state *parse_state)
0190 {
0191 struct perf_pmu *pmu;
0192 int ret;
0193
0194 *hybrid = false;
0195 if (!perf_pmu__has_hybrid())
0196 return 0;
0197
0198 *hybrid = true;
0199 perf_pmu__for_each_hybrid_pmu(pmu) {
0200 LIST_HEAD(terms);
0201
0202 if (pmu_cmp(parse_state, pmu))
0203 continue;
0204
0205 copy_config_terms(&terms, config_terms);
0206 ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
0207 attr, name, metric_id, &terms, pmu);
0208 free_config_terms(&terms);
0209 if (ret)
0210 return ret;
0211 }
0212
0213 return 0;
0214 }