Current hardware events has special perf types PERF_TYPE_HARDWARE.
But it doesn't pass the PMU type in the user interface. For a hybrid
system, the perf kernel doesn't know which PMU the events belong to.
So now this type is extended to be PMU aware type. The PMU type ID
is stored at attr.config[63:32].
PMU type ID is retrieved from sysfs.
root@lkp-adl-d01:/sys/devices/cpu_atom# cat type
8
root@lkp-adl-d01:/sys/devices/cpu_core# cat type
4
When enabling a hybrid hardware event without specified pmu, such as,
'perf stat -e cycles -a', two events are created automatically. One
is for atom, the other is for core.
# perf stat -e cycles -a -vv -- sleep 1
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
size 120
config 0x400000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
size 120
config 0x400000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 15 group_fd -1 flags 0x8 = 19
------------------------------------------------------------
perf_event_attr:
size 120
config 0x800000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 16 group_fd -1 flags 0x8 = 20
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
size 120
config 0x800000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 23 group_fd -1 flags 0x8 = 27
cycles: 0: 836272 1001525722 1001525722
cycles: 1: 628564 1001580453 1001580453
cycles: 2: 872693 1001605997 1001605997
cycles: 3: 70417 1001641369 1001641369
cycles: 4: 88593 1001726722 1001726722
cycles: 5: 470495 1001752993 1001752993
cycles: 6: 484733 1001840440 1001840440
cycles: 7: 1272477 1001593105 1001593105
cycles: 8: 209185 1001608616 1001608616
cycles: 9: 204391 1001633962 1001633962
cycles: 10: 264121 1001661745 1001661745
cycles: 11: 826104 1001689904 1001689904
cycles: 12: 89935 1001728861 1001728861
cycles: 13: 70639 1001756757 1001756757
cycles: 14: 185266 1001784810 1001784810
cycles: 15: 171094 1001825466 1001825466
cycles: 0: 129624 1001854843 1001854843
cycles: 1: 122533 1001840421 1001840421
cycles: 2: 90055 1001882506 1001882506
cycles: 3: 139607 1001896463 1001896463
cycles: 4: 141791 1001907838 1001907838
cycles: 5: 530927 1001883880 1001883880
cycles: 6: 143246 1001852529 1001852529
cycles: 7: 667769 1001872626 1001872626
cycles: 6744979 16026956922 16026956922
cycles: 1965552 8014991106 8014991106
Performance counter stats for 'system wide':
6,744,979 cpu_core/cycles/
1,965,552 cpu_atom/cycles/
1.001882711 seconds time elapsed
0x4 in 0x400000000 indicates the cpu_core pmu.
0x8 in 0x800000000 indicates the cpu_atom pmu.
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210427070139.25256-9-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
272 lines
8.5 KiB
C
272 lines
8.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __PERF_PARSE_EVENTS_H
|
|
#define __PERF_PARSE_EVENTS_H
|
|
/*
|
|
* Parse symbolic events/counts passed in as options:
|
|
*/
|
|
|
|
#include <linux/list.h>
|
|
#include <stdbool.h>
|
|
#include <linux/types.h>
|
|
#include <linux/perf_event.h>
|
|
#include <string.h>
|
|
|
|
struct list_head;
|
|
struct evsel;
|
|
struct evlist;
|
|
struct parse_events_error;
|
|
|
|
struct option;
|
|
struct perf_pmu;
|
|
|
|
struct tracepoint_path {
|
|
char *system;
|
|
char *name;
|
|
struct tracepoint_path *next;
|
|
};
|
|
|
|
struct tracepoint_path *tracepoint_id_to_path(u64 config);
|
|
struct tracepoint_path *tracepoint_name_to_path(const char *name);
|
|
bool have_tracepoints(struct list_head *evlist);
|
|
|
|
const char *event_type(int type);
|
|
|
|
int parse_events_option(const struct option *opt, const char *str, int unset);
|
|
int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset);
|
|
int __parse_events(struct evlist *evlist, const char *str, struct parse_events_error *error,
|
|
struct perf_pmu *fake_pmu);
|
|
|
|
static inline int parse_events(struct evlist *evlist, const char *str,
|
|
struct parse_events_error *err)
|
|
{
|
|
return __parse_events(evlist, str, err, NULL);
|
|
}
|
|
|
|
int parse_events_terms(struct list_head *terms, const char *str);
|
|
int parse_filter(const struct option *opt, const char *str, int unset);
|
|
int exclude_perf(const struct option *opt, const char *arg, int unset);
|
|
|
|
#define EVENTS_HELP_MAX (128*1024)
|
|
|
|
enum perf_pmu_event_symbol_type {
|
|
PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */
|
|
PMU_EVENT_SYMBOL, /* normal style PMU event */
|
|
PMU_EVENT_SYMBOL_PREFIX, /* prefix of pre-suf style event */
|
|
PMU_EVENT_SYMBOL_SUFFIX, /* suffix of pre-suf style event */
|
|
};
|
|
|
|
struct perf_pmu_event_symbol {
|
|
char *symbol;
|
|
enum perf_pmu_event_symbol_type type;
|
|
};
|
|
|
|
enum {
|
|
PARSE_EVENTS__TERM_TYPE_NUM,
|
|
PARSE_EVENTS__TERM_TYPE_STR,
|
|
};
|
|
|
|
enum {
|
|
PARSE_EVENTS__TERM_TYPE_USER,
|
|
PARSE_EVENTS__TERM_TYPE_CONFIG,
|
|
PARSE_EVENTS__TERM_TYPE_CONFIG1,
|
|
PARSE_EVENTS__TERM_TYPE_CONFIG2,
|
|
PARSE_EVENTS__TERM_TYPE_NAME,
|
|
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
|
|
PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ,
|
|
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
|
|
PARSE_EVENTS__TERM_TYPE_TIME,
|
|
PARSE_EVENTS__TERM_TYPE_CALLGRAPH,
|
|
PARSE_EVENTS__TERM_TYPE_STACKSIZE,
|
|
PARSE_EVENTS__TERM_TYPE_NOINHERIT,
|
|
PARSE_EVENTS__TERM_TYPE_INHERIT,
|
|
PARSE_EVENTS__TERM_TYPE_MAX_STACK,
|
|
PARSE_EVENTS__TERM_TYPE_MAX_EVENTS,
|
|
PARSE_EVENTS__TERM_TYPE_NOOVERWRITE,
|
|
PARSE_EVENTS__TERM_TYPE_OVERWRITE,
|
|
PARSE_EVENTS__TERM_TYPE_DRV_CFG,
|
|
PARSE_EVENTS__TERM_TYPE_PERCORE,
|
|
PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT,
|
|
PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE,
|
|
__PARSE_EVENTS__TERM_TYPE_NR,
|
|
};
|
|
|
|
struct parse_events_array {
|
|
size_t nr_ranges;
|
|
struct {
|
|
unsigned int start;
|
|
size_t length;
|
|
} *ranges;
|
|
};
|
|
|
|
struct parse_events_term {
|
|
char *config;
|
|
struct parse_events_array array;
|
|
union {
|
|
char *str;
|
|
u64 num;
|
|
} val;
|
|
int type_val;
|
|
int type_term;
|
|
struct list_head list;
|
|
bool used;
|
|
bool no_value;
|
|
|
|
/* error string indexes for within parsed string */
|
|
int err_term;
|
|
int err_val;
|
|
|
|
/* Coming from implicit alias */
|
|
bool weak;
|
|
};
|
|
|
|
struct parse_events_error {
|
|
int num_errors; /* number of errors encountered */
|
|
int idx; /* index in the parsed string */
|
|
char *str; /* string to display at the index */
|
|
char *help; /* optional help string */
|
|
int first_idx;/* as above, but for the first encountered error */
|
|
char *first_str;
|
|
char *first_help;
|
|
};
|
|
|
|
struct parse_events_state {
|
|
struct list_head list;
|
|
int idx;
|
|
int nr_groups;
|
|
struct parse_events_error *error;
|
|
struct evlist *evlist;
|
|
struct list_head *terms;
|
|
int stoken;
|
|
struct perf_pmu *fake_pmu;
|
|
};
|
|
|
|
void parse_events__handle_error(struct parse_events_error *err, int idx,
|
|
char *str, char *help);
|
|
void parse_events__shrink_config_terms(void);
|
|
int parse_events__is_hardcoded_term(struct parse_events_term *term);
|
|
int parse_events_term__num(struct parse_events_term **term,
|
|
int type_term, char *config, u64 num,
|
|
bool novalue,
|
|
void *loc_term, void *loc_val);
|
|
int parse_events_term__str(struct parse_events_term **term,
|
|
int type_term, char *config, char *str,
|
|
void *loc_term, void *loc_val);
|
|
int parse_events_term__sym_hw(struct parse_events_term **term,
|
|
char *config, unsigned idx);
|
|
int parse_events_term__clone(struct parse_events_term **new,
|
|
struct parse_events_term *term);
|
|
void parse_events_term__delete(struct parse_events_term *term);
|
|
void parse_events_terms__delete(struct list_head *terms);
|
|
void parse_events_terms__purge(struct list_head *terms);
|
|
void parse_events__clear_array(struct parse_events_array *a);
|
|
int parse_events__modifier_event(struct list_head *list, char *str, bool add);
|
|
int parse_events__modifier_group(struct list_head *list, char *event_mod);
|
|
int parse_events_name(struct list_head *list, char *name);
|
|
int parse_events_add_tracepoint(struct list_head *list, int *idx,
|
|
const char *sys, const char *event,
|
|
struct parse_events_error *error,
|
|
struct list_head *head_config);
|
|
int parse_events_load_bpf(struct parse_events_state *parse_state,
|
|
struct list_head *list,
|
|
char *bpf_file_name,
|
|
bool source,
|
|
struct list_head *head_config);
|
|
/* Provide this function for perf test */
|
|
struct bpf_object;
|
|
int parse_events_load_bpf_obj(struct parse_events_state *parse_state,
|
|
struct list_head *list,
|
|
struct bpf_object *obj,
|
|
struct list_head *head_config);
|
|
int parse_events_add_numeric(struct parse_events_state *parse_state,
|
|
struct list_head *list,
|
|
u32 type, u64 config,
|
|
struct list_head *head_config);
|
|
enum perf_tool_event;
|
|
int parse_events_add_tool(struct parse_events_state *parse_state,
|
|
struct list_head *list,
|
|
enum perf_tool_event tool_event);
|
|
int parse_events_add_cache(struct list_head *list, int *idx,
|
|
char *type, char *op_result1, char *op_result2,
|
|
struct parse_events_error *error,
|
|
struct list_head *head_config);
|
|
int parse_events_add_breakpoint(struct list_head *list, int *idx,
|
|
u64 addr, char *type, u64 len);
|
|
int parse_events_add_pmu(struct parse_events_state *parse_state,
|
|
struct list_head *list, char *name,
|
|
struct list_head *head_config,
|
|
bool auto_merge_stats,
|
|
bool use_alias);
|
|
|
|
struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr,
|
|
char *name, struct perf_pmu *pmu);
|
|
|
|
int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
|
|
char *str,
|
|
struct list_head **listp);
|
|
|
|
int parse_events_copy_term_list(struct list_head *old,
|
|
struct list_head **new);
|
|
|
|
enum perf_pmu_event_symbol_type
|
|
perf_pmu__parse_check(const char *name);
|
|
void parse_events__set_leader(char *name, struct list_head *list,
|
|
struct parse_events_state *parse_state);
|
|
void parse_events_update_lists(struct list_head *list_event,
|
|
struct list_head *list_all);
|
|
void parse_events_evlist_error(struct parse_events_state *parse_state,
|
|
int idx, const char *str);
|
|
|
|
void print_events(const char *event_glob, bool name_only, bool quiet,
|
|
bool long_desc, bool details_flag, bool deprecated);
|
|
|
|
struct event_symbol {
|
|
const char *symbol;
|
|
const char *alias;
|
|
};
|
|
extern struct event_symbol event_symbols_hw[];
|
|
extern struct event_symbol event_symbols_sw[];
|
|
void print_symbol_events(const char *event_glob, unsigned type,
|
|
struct event_symbol *syms, unsigned max,
|
|
bool name_only);
|
|
void print_tool_events(const char *event_glob, bool name_only);
|
|
void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
|
|
bool name_only);
|
|
int print_hwcache_events(const char *event_glob, bool name_only);
|
|
void print_sdt_events(const char *subsys_glob, const char *event_glob,
|
|
bool name_only);
|
|
int is_valid_tracepoint(const char *event_string);
|
|
|
|
int valid_event_mount(const char *eventfs);
|
|
char *parse_events_formats_error_string(char *additional_terms);
|
|
|
|
void parse_events_print_error(struct parse_events_error *err,
|
|
const char *event);
|
|
|
|
#ifdef HAVE_LIBELF_SUPPORT
|
|
/*
|
|
* If the probe point starts with '%',
|
|
* or starts with "sdt_" and has a ':' but no '=',
|
|
* then it should be a SDT/cached probe point.
|
|
*/
|
|
static inline bool is_sdt_event(char *str)
|
|
{
|
|
return (str[0] == '%' ||
|
|
(!strncmp(str, "sdt_", 4) &&
|
|
!!strchr(str, ':') && !strchr(str, '=')));
|
|
}
|
|
#else
|
|
static inline bool is_sdt_event(char *str __maybe_unused)
|
|
{
|
|
return false;
|
|
}
|
|
#endif /* HAVE_LIBELF_SUPPORT */
|
|
|
|
int perf_pmu__test_parse_init(void);
|
|
|
|
struct evsel *parse_events__add_event_hybrid(struct list_head *list, int *idx,
|
|
struct perf_event_attr *attr,
|
|
char *name, struct perf_pmu *pmu,
|
|
struct list_head *config_terms);
|
|
|
|
#endif /* __PERF_PARSE_EVENTS_H */
|