linux-stable/tools/perf/util/pmu.h
Ian Rogers e5c6109f48 perf list: Reorganize to use callbacks to allow honouring command line options
Rather than controlling the list output with passed flags, add
callbacks that are called when an event or metric are
encountered. State is passed to the callback so that command line
options can be respected, alternatively the callbacks can be changed.

Fix a few bugs:
 - wordwrap to columns metric descriptions and expressions;
 - remove unnecessary whitespace after PMU event names;
 - the metric filter is a glob but matched using strstr which will
   always fail, switch to using a proper globmatch,
 - the detail flag gives details for extra kernel PMU events like
   branch-instructions.

In metricgroup.c switch from struct mep being a rbtree of metricgroups
containing a list of metrics, to the tree directly containing all the
metrics. In general the alias for a name is passed to the print
routine rather than being contained in the name with OR.

Committer notes:

Check the asprint() return to address this on fedora 36:

  util/print-events.c: In function ‘print_sdt_events’:
  util/print-events.c:183:33: error: ignoring return value of ‘asprintf’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
    183 |                                 asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid);
        |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  cc1: all warnings being treated as errors

  $ gcc --version | head -1
  gcc (GCC) 12.2.1 20220819 (Red Hat 12.2.1-2)
  $

Fix ps.pmu_glob setting when dealing with *:* events, it was being left
with a freed pointer that then at the end of cmd_list() would be double
freed.

Check if pmu_name is NULL in default_print_event() before calling
strglobmatch(pmu_name, ...) to avoid a segfault.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xin Gao <gaoxin@cdjrlc.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: http://lore.kernel.org/lkml/20221114210723.2749751-10-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-11-23 10:29:59 -03:00

262 lines
7.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PMU_H
#define __PMU_H
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <linux/perf_event.h>
#include <linux/list.h>
#include <stdbool.h>
#include "parse-events.h"
#include "pmu-events/pmu-events.h"
struct evsel_config_term;
struct perf_cpu_map;
struct print_callbacks;
enum {
PERF_PMU_FORMAT_VALUE_CONFIG,
PERF_PMU_FORMAT_VALUE_CONFIG1,
PERF_PMU_FORMAT_VALUE_CONFIG2,
PERF_PMU_FORMAT_VALUE_CONFIG_END,
};
#define PERF_PMU_FORMAT_BITS 64
#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"
#define MAX_PMU_NAME_LEN 128
struct perf_event_attr;
struct perf_pmu_caps {
char *name;
char *value;
struct list_head list;
};
/**
* struct perf_pmu - hi
*/
struct perf_pmu {
/** @name: The name of the PMU such as "cpu". */
char *name;
/**
* @alias_name: Optional alternate name for the PMU determined in
* architecture specific code.
*/
char *alias_name;
/**
* @id: Optional PMU identifier read from
* <sysfs>/bus/event_source/devices/<name>/identifier.
*/
char *id;
/**
* @type: Perf event attributed type value, read from
* <sysfs>/bus/event_source/devices/<name>/type.
*/
__u32 type;
/**
* @selectable: Can the PMU name be selected as if it were an event?
*/
bool selectable;
/**
* @is_uncore: Is the PMU not within the CPU core? Determined by the
* presence of <sysfs>/bus/event_source/devices/<name>/cpumask.
*/
bool is_uncore;
/**
* @auxtrace: Are events auxiliary events? Determined in architecture
* specific code.
*/
bool auxtrace;
/**
* @max_precise: Number of levels of :ppp precision supported by the
* PMU, read from
* <sysfs>/bus/event_source/devices/<name>/caps/max_precise.
*/
int max_precise;
/**
* @default_config: Optional default perf_event_attr determined in
* architecture specific code.
*/
struct perf_event_attr *default_config;
/**
* @cpus: Empty or the contents of either of:
* <sysfs>/bus/event_source/devices/<name>/cpumask.
* <sysfs>/bus/event_source/devices/<cpu>/cpus.
*/
struct perf_cpu_map *cpus;
/**
* @format: Holds the contents of files read from
* <sysfs>/bus/event_source/devices/<name>/format/. The contents specify
* which event parameter changes what config, config1 or config2 bits.
*/
struct list_head format;
/**
* @aliases: List of struct perf_pmu_alias. Each alias corresponds to an
* event read from <sysfs>/bus/event_source/devices/<name>/events/ or
* from json events in pmu-events.c.
*/
struct list_head aliases;
/** @caps_initialized: Has the list caps been initialized? */
bool caps_initialized;
/** @nr_caps: The length of the list caps. */
u32 nr_caps;
/**
* @caps: Holds the contents of files read from
* <sysfs>/bus/event_source/devices/<name>/caps/.
*
* The contents are pairs of the filename with the value of its
* contents, for example, max_precise (see above) may have a value of 3.
*/
struct list_head caps;
/** @list: Element on pmus list in pmu.c. */
struct list_head list;
/** @hybrid_list: Element on perf_pmu__hybrid_pmus. */
struct list_head hybrid_list;
/**
* @missing_features: Features to inhibit when events on this PMU are
* opened.
*/
struct {
/**
* @exclude_guest: Disables perf_event_attr exclude_guest and
* exclude_host.
*/
bool exclude_guest;
} missing_features;
};
/** @perf_pmu__fake: A special global PMU used for testing. */
extern struct perf_pmu perf_pmu__fake;
struct perf_pmu_info {
const char *unit;
const char *metric_expr;
const char *metric_name;
double scale;
bool per_pkg;
bool snapshot;
};
#define UNIT_MAX_LEN 31 /* max length for event unit name */
/**
* struct perf_pmu_alias - An event either read from sysfs or builtin in
* pmu-events.c, created by parsing the pmu-events json files.
*/
struct perf_pmu_alias {
/** @name: Name of the event like "mem-loads". */
char *name;
/** @desc: Optional short description of the event. */
char *desc;
/** @long_desc: Optional long description. */
char *long_desc;
/**
* @topic: Optional topic such as cache or pipeline, particularly for
* json events.
*/
char *topic;
/**
* @str: Comma separated parameter list like
* "event=0xcd,umask=0x1,ldlat=0x3".
*/
char *str;
/** @terms: Owned list of the original parsed parameters. */
struct list_head terms;
/** @list: List element of struct perf_pmu aliases. */
struct list_head list;
/** @unit: Units for the event, such as bytes or cache lines. */
char unit[UNIT_MAX_LEN+1];
/** @scale: Value to scale read counter values by. */
double scale;
/**
* @per_pkg: Does the file
* <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.per-pkg or
* equivalent json value exist and have the value 1.
*/
bool per_pkg;
/**
* @snapshot: Does the file
* <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.snapshot
* exist and have the value 1.
*/
bool snapshot;
/**
* @deprecated: Is the event hidden and so not shown in perf list by
* default.
*/
bool deprecated;
/**
* @metric_expr: A metric expression associated with an event. Doing
* this makes little sense due to scale and unit applying to both.
*/
char *metric_expr;
/** @metric_name: A name for the metric. unit applying to both. */
char *metric_name;
/** @pmu_name: The name copied from struct perf_pmu. */
char *pmu_name;
};
struct perf_pmu *perf_pmu__find(const char *name);
struct perf_pmu *perf_pmu__find_by_type(unsigned int type);
void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu);
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms,
struct parse_events_error *error);
int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats,
struct perf_event_attr *attr,
struct list_head *head_terms,
bool zero, struct parse_events_error *error);
__u64 perf_pmu__format_bits(struct list_head *formats, const char *name);
int perf_pmu__format_type(struct list_head *formats, const char *name);
int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
struct perf_pmu_info *info);
struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
struct list_head *head_terms);
void perf_pmu_error(struct list_head *list, char *name, char const *msg);
int perf_pmu__new_format(struct list_head *list, char *name,
int config, unsigned long *bits);
void perf_pmu__set_format(unsigned long *bits, long from, long to);
int perf_pmu__format_parse(char *dir, struct list_head *head);
void perf_pmu__del_formats(struct list_head *formats);
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
bool is_pmu_core(const char *name);
void print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
bool pmu_have_event(const char *pname, const char *name);
int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);
int perf_pmu__test(void);
struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu,
const struct pmu_events_table *table);
char *perf_pmu__getcpuid(struct perf_pmu *pmu);
const struct pmu_events_table *pmu_events_table__find(void);
bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
void perf_pmu_free_alias(struct perf_pmu_alias *alias);
int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
int perf_pmu__caps_parse(struct perf_pmu *pmu);
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
const char *name);
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);
bool perf_pmu__has_hybrid(void);
int perf_pmu__match(char *pattern, char *name, char *tok);
int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus,
struct perf_cpu_map **mcpus_ptr,
struct perf_cpu_map **ucpus_ptr);
char *pmu_find_real_name(const char *name);
char *pmu_find_alias_name(const char *name);
#endif /* __PMU_H */