mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
4.6 KiB
190 lines
4.6 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
#include <linux/err.h> |
|
#include <linux/zalloc.h> |
|
#include <errno.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
#include <sys/param.h> |
|
#include "evlist.h" |
|
#include "evsel.h" |
|
#include "parse-events.h" |
|
#include "parse-events-hybrid.h" |
|
#include "debug.h" |
|
#include "pmu.h" |
|
#include "pmu-hybrid.h" |
|
#include "perf.h" |
|
|
|
static void config_hybrid_attr(struct perf_event_attr *attr, |
|
int type, int pmu_type) |
|
{ |
|
/* |
|
* attr.config layout for type PERF_TYPE_HARDWARE and |
|
* PERF_TYPE_HW_CACHE |
|
* |
|
* PERF_TYPE_HARDWARE: 0xEEEEEEEE000000AA |
|
* AA: hardware event ID |
|
* EEEEEEEE: PMU type ID |
|
* PERF_TYPE_HW_CACHE: 0xEEEEEEEE00DDCCBB |
|
* BB: hardware cache ID |
|
* CC: hardware cache op ID |
|
* DD: hardware cache op result ID |
|
* EEEEEEEE: PMU type ID |
|
* If the PMU type ID is 0, the PERF_TYPE_RAW will be applied. |
|
*/ |
|
attr->type = type; |
|
attr->config = attr->config | ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT); |
|
} |
|
|
|
static int create_event_hybrid(__u32 config_type, int *idx, |
|
struct list_head *list, |
|
struct perf_event_attr *attr, char *name, |
|
struct list_head *config_terms, |
|
struct perf_pmu *pmu) |
|
{ |
|
struct evsel *evsel; |
|
__u32 type = attr->type; |
|
__u64 config = attr->config; |
|
|
|
config_hybrid_attr(attr, config_type, pmu->type); |
|
evsel = parse_events__add_event_hybrid(list, idx, attr, name, |
|
pmu, config_terms); |
|
if (evsel) |
|
evsel->pmu_name = strdup(pmu->name); |
|
else |
|
return -ENOMEM; |
|
|
|
attr->type = type; |
|
attr->config = config; |
|
return 0; |
|
} |
|
|
|
static int pmu_cmp(struct parse_events_state *parse_state, |
|
struct perf_pmu *pmu) |
|
{ |
|
if (!parse_state->hybrid_pmu_name) |
|
return 0; |
|
|
|
return strcmp(parse_state->hybrid_pmu_name, pmu->name); |
|
} |
|
|
|
static int add_hw_hybrid(struct parse_events_state *parse_state, |
|
struct list_head *list, struct perf_event_attr *attr, |
|
char *name, struct list_head *config_terms) |
|
{ |
|
struct perf_pmu *pmu; |
|
int ret; |
|
|
|
perf_pmu__for_each_hybrid_pmu(pmu) { |
|
LIST_HEAD(terms); |
|
|
|
if (pmu_cmp(parse_state, pmu)) |
|
continue; |
|
|
|
copy_config_terms(&terms, config_terms); |
|
ret = create_event_hybrid(PERF_TYPE_HARDWARE, |
|
&parse_state->idx, list, attr, name, |
|
&terms, pmu); |
|
free_config_terms(&terms); |
|
if (ret) |
|
return ret; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int create_raw_event_hybrid(int *idx, struct list_head *list, |
|
struct perf_event_attr *attr, char *name, |
|
struct list_head *config_terms, |
|
struct perf_pmu *pmu) |
|
{ |
|
struct evsel *evsel; |
|
|
|
attr->type = pmu->type; |
|
evsel = parse_events__add_event_hybrid(list, idx, attr, name, |
|
pmu, config_terms); |
|
if (evsel) |
|
evsel->pmu_name = strdup(pmu->name); |
|
else |
|
return -ENOMEM; |
|
|
|
return 0; |
|
} |
|
|
|
static int add_raw_hybrid(struct parse_events_state *parse_state, |
|
struct list_head *list, struct perf_event_attr *attr, |
|
char *name, struct list_head *config_terms) |
|
{ |
|
struct perf_pmu *pmu; |
|
int ret; |
|
|
|
perf_pmu__for_each_hybrid_pmu(pmu) { |
|
LIST_HEAD(terms); |
|
|
|
if (pmu_cmp(parse_state, pmu)) |
|
continue; |
|
|
|
copy_config_terms(&terms, config_terms); |
|
ret = create_raw_event_hybrid(&parse_state->idx, list, attr, |
|
name, &terms, pmu); |
|
free_config_terms(&terms); |
|
if (ret) |
|
return ret; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state, |
|
struct list_head *list, |
|
struct perf_event_attr *attr, |
|
char *name, struct list_head *config_terms, |
|
bool *hybrid) |
|
{ |
|
*hybrid = false; |
|
if (attr->type == PERF_TYPE_SOFTWARE) |
|
return 0; |
|
|
|
if (!perf_pmu__has_hybrid()) |
|
return 0; |
|
|
|
*hybrid = true; |
|
if (attr->type != PERF_TYPE_RAW) { |
|
return add_hw_hybrid(parse_state, list, attr, name, |
|
config_terms); |
|
} |
|
|
|
return add_raw_hybrid(parse_state, list, attr, name, |
|
config_terms); |
|
} |
|
|
|
int parse_events__add_cache_hybrid(struct list_head *list, int *idx, |
|
struct perf_event_attr *attr, char *name, |
|
struct list_head *config_terms, |
|
bool *hybrid, |
|
struct parse_events_state *parse_state) |
|
{ |
|
struct perf_pmu *pmu; |
|
int ret; |
|
|
|
*hybrid = false; |
|
if (!perf_pmu__has_hybrid()) |
|
return 0; |
|
|
|
*hybrid = true; |
|
perf_pmu__for_each_hybrid_pmu(pmu) { |
|
LIST_HEAD(terms); |
|
|
|
if (pmu_cmp(parse_state, pmu)) |
|
continue; |
|
|
|
copy_config_terms(&terms, config_terms); |
|
ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list, |
|
attr, name, &terms, pmu); |
|
free_config_terms(&terms); |
|
if (ret) |
|
return ret; |
|
} |
|
|
|
return 0; |
|
}
|
|
|