aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/util/pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/pmu.c')
-rw-r--r--tools/perf/util/pmu.c555
1 files changed, 87 insertions, 468 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ad209c88a124..64fa568a5426 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -4,20 +4,15 @@
#include <linux/string.h>
#include <linux/zalloc.h>
#include <linux/ctype.h>
-#include <subcmd/pager.h>
#include <sys/types.h>
-#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
-#include <stdarg.h>
#include <dirent.h>
#include <api/fs/fs.h>
#include <locale.h>
-#include <regex.h>
-#include <perf/cpumap.h>
#include <fnmatch.h>
#include <math.h>
#include "debug.h"
@@ -32,7 +27,6 @@
#include "string2.h"
#include "strbuf.h"
#include "fncache.h"
-#include "pmu-hybrid.h"
#include "util/evsel_config.h"
struct perf_pmu perf_pmu__fake;
@@ -60,10 +54,6 @@ struct perf_pmu_format {
struct list_head list;
};
-static bool hybrid_scanned;
-
-static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name);
-
/*
* Parse & process all the sysfs attributes located under
* the directory specified in 'dir' parameter.
@@ -557,36 +547,11 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
return 0;
}
-/* Add all pmus in sysfs to pmu list: */
-static void pmu_read_sysfs(void)
-{
- int fd;
- DIR *dir;
- struct dirent *dent;
-
- fd = perf_pmu__event_source_devices_fd();
- if (fd < 0)
- return;
-
- dir = fdopendir(fd);
- if (!dir)
- return;
-
- while ((dent = readdir(dir))) {
- if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
- continue;
- /* add to static LIST_HEAD(pmus): */
- perf_pmu__find2(fd, dent->d_name);
- }
-
- closedir(dir);
-}
-
/*
* Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
* may have a "cpus" file.
*/
-static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name)
+static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name, bool is_core)
{
struct perf_cpu_map *cpus;
const char *templates[] = {
@@ -610,16 +575,14 @@ static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name)
return cpus;
}
- return NULL;
+ /* Nothing found, for core PMUs assume this means all CPUs. */
+ return is_core ? perf_cpu_map__get(cpu_map__online()) : NULL;
}
static bool pmu_is_uncore(int dirfd, const char *name)
{
int fd;
- if (perf_pmu__hybrid_mounted(name))
- return false;
-
fd = perf_pmu__pathname_fd(dirfd, name, "cpumask", O_PATH);
if (fd < 0)
return false;
@@ -643,12 +606,14 @@ static char *pmu_id(const char *name)
return str;
}
-/*
- * PMU CORE devices have different name other than cpu in sysfs on some
- * platforms.
- * Looking for possible sysfs files to identify the arm core device.
+/**
+ * is_sysfs_pmu_core() - PMU CORE devices have different name other than cpu in
+ * sysfs on some platforms like ARM or Intel hybrid. Looking for
+ * possible the cpus file in sysfs files to identify whether this is a
+ * core device.
+ * @name: The PMU name such as "cpu_atom".
*/
-static int is_arm_pmu_core(const char *name)
+static int is_sysfs_pmu_core(const char *name)
{
char path[PATH_MAX];
@@ -777,9 +742,11 @@ out:
}
struct pmu_add_cpu_aliases_map_data {
+ /* List being added to. */
struct list_head *head;
- const char *name;
- const char *cpu_name;
+ /* If a pmu_event lacks a given PMU the default used. */
+ char *default_pmu_name;
+ /* The PMU that we're searching for events for. */
struct perf_pmu *pmu;
};
@@ -788,37 +755,32 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
void *vdata)
{
struct pmu_add_cpu_aliases_map_data *data = vdata;
- const char *pname = pe->pmu ? pe->pmu : data->cpu_name;
-
- if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name))
- goto new_alias;
-
- if (strcmp(pname, data->name))
- return 0;
+ const char *pname = pe->pmu ?: data->default_pmu_name;
-new_alias:
- /* need type casts to override 'const' */
- __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc,
- (char *)pe->event, pe);
+ if (!strcmp(pname, data->pmu->name) ||
+ (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->pmu->name))) {
+ /* need type casts to override 'const' */
+ __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc,
+ (char *)pe->event, pe);
+ }
return 0;
}
/*
- * From the pmu_events_map, find the table of PMU events that corresponds
- * to the current running CPU. Then, add all PMU events from that table
- * as aliases.
+ * From the pmu_events_table, find the events that correspond to the given
+ * PMU and add them to the list 'head'.
*/
void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu,
- const struct pmu_events_table *table)
+ const struct pmu_events_table *table)
{
struct pmu_add_cpu_aliases_map_data data = {
.head = head,
- .name = pmu->name,
- .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu",
+ .default_pmu_name = perf_pmus__default_pmu_name(),
.pmu = pmu,
};
pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data);
+ free(data.default_pmu_name);
}
static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
@@ -898,23 +860,16 @@ static int pmu_max_precise(int dirfd, struct perf_pmu *pmu)
return max_precise;
}
-static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name)
+struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name)
{
struct perf_pmu *pmu;
LIST_HEAD(format);
LIST_HEAD(aliases);
__u32 type;
char *name = pmu_find_real_name(lookup_name);
- bool is_hybrid = perf_pmu__hybrid_mounted(name);
char *alias_name;
/*
- * Check pmu name for hybrid and the pmu may be invalid in sysfs
- */
- if (!strncmp(name, "cpu_", 4) && !is_hybrid)
- return NULL;
-
- /*
* The pmu data we store & need consists of the pmu
* type value and format definitions. Load both right
* now.
@@ -932,9 +887,9 @@ static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name)
if (!pmu)
return NULL;
- pmu->cpus = pmu_cpumask(dirfd, name);
+ pmu->is_core = is_pmu_core(name);
+ pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
pmu->name = strdup(name);
-
if (!pmu->name)
goto err;
@@ -962,12 +917,7 @@ static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name)
INIT_LIST_HEAD(&pmu->caps);
list_splice(&format, &pmu->format);
list_splice(&aliases, &pmu->aliases);
- list_add_tail(&pmu->list, &pmus);
-
- if (is_hybrid)
- list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus);
- else
- INIT_LIST_HEAD(&pmu->hybrid_list);
+ list_add_tail(&pmu->list, pmus);
pmu->default_config = perf_pmu__get_default_config(pmu);
@@ -982,6 +932,11 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
{
struct perf_pmu_format *format;
+ if (pmu->formats_checked)
+ return;
+
+ pmu->formats_checked = true;
+
/* fake pmu doesn't have format list */
if (pmu == &perf_pmu__fake)
return;
@@ -995,61 +950,6 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
}
}
-static struct perf_pmu *pmu_find(const char *name)
-{
- struct perf_pmu *pmu;
-
- list_for_each_entry(pmu, &pmus, list) {
- if (!strcmp(pmu->name, name) ||
- (pmu->alias_name && !strcmp(pmu->alias_name, name)))
- return pmu;
- }
-
- return NULL;
-}
-
-struct perf_pmu *perf_pmu__find_by_type(unsigned int type)
-{
- struct perf_pmu *pmu;
-
- list_for_each_entry(pmu, &pmus, list)
- if (pmu->type == type)
- return pmu;
-
- return NULL;
-}
-
-struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
-{
- /*
- * pmu iterator: If pmu is NULL, we start at the begin,
- * otherwise return the next pmu. Returns NULL on end.
- */
- if (!pmu) {
- pmu_read_sysfs();
- pmu = list_prepare_entry(pmu, &pmus, list);
- }
- list_for_each_entry_continue(pmu, &pmus, list)
- return pmu;
- return NULL;
-}
-
-struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
-{
- struct perf_pmu *pmu = NULL;
-
- if (evsel->pmu)
- return evsel->pmu;
-
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (pmu->type == evsel->core.attr.type)
- break;
- }
-
- ((struct evsel *)evsel)->pmu = pmu;
- return pmu;
-}
-
bool evsel__is_aux_event(const struct evsel *evsel)
{
struct perf_pmu *pmu = evsel__find_pmu(evsel);
@@ -1086,43 +986,6 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
evsel->core.attr.config |= field_prep(bits, val);
}
-struct perf_pmu *perf_pmu__find(const char *name)
-{
- struct perf_pmu *pmu;
- int dirfd;
-
- /*
- * Once PMU is loaded it stays in the list,
- * so we keep us from multiple reading/parsing
- * the pmu format definitions.
- */
- pmu = pmu_find(name);
- if (pmu)
- return pmu;
-
- dirfd = perf_pmu__event_source_devices_fd();
- pmu = pmu_lookup(dirfd, name);
- close(dirfd);
-
- return pmu;
-}
-
-static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
-{
- struct perf_pmu *pmu;
-
- /*
- * Once PMU is loaded it stays in the list,
- * so we keep us from multiple reading/parsing
- * the pmu format definitions.
- */
- pmu = pmu_find(name);
- if (pmu)
- return pmu;
-
- return pmu_lookup(dirfd, name);
-}
-
static struct perf_pmu_format *
pmu_find_format(struct list_head *formats, const char *name)
{
@@ -1398,7 +1261,6 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
{
bool zero = !!pmu->default_config;
- attr->type = pmu->type;
return perf_pmu__config_terms(pmu->name, &pmu->format, attr,
head_terms, zero, err);
}
@@ -1553,250 +1415,46 @@ void perf_pmu__del_formats(struct list_head *formats)
}
}
-static int sub_non_neg(int a, int b)
-{
- if (b > a)
- return 0;
- return a - b;
-}
-
-static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
- const struct perf_pmu_alias *alias)
-{
- struct parse_events_term *term;
- int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
-
- list_for_each_entry(term, &alias->terms, list) {
- if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
- used += snprintf(buf + used, sub_non_neg(len, used),
- ",%s=%s", term->config,
- term->val.str);
- }
-
- if (sub_non_neg(len, used) > 0) {
- buf[used] = '/';
- used++;
- }
- if (sub_non_neg(len, used) > 0) {
- buf[used] = '\0';
- used++;
- } else
- buf[len - 1] = '\0';
-
- return buf;
-}
-
-/** Struct for ordering events as output in perf list. */
-struct sevent {
- /** PMU for event. */
- const struct perf_pmu *pmu;
- /**
- * Optional event for name, desc, etc. If not present then this is a
- * selectable PMU and the event name is shown as "//".
- */
- const struct perf_pmu_alias *event;
- /** Is the PMU for the CPU? */
- bool is_cpu;
-};
-
-static int cmp_sevent(const void *a, const void *b)
+bool is_pmu_core(const char *name)
{
- const struct sevent *as = a;
- const struct sevent *bs = b;
- const char *a_pmu_name = NULL, *b_pmu_name = NULL;
- const char *a_name = "//", *a_desc = NULL, *a_topic = "";
- const char *b_name = "//", *b_desc = NULL, *b_topic = "";
- int ret;
-
- if (as->event) {
- a_name = as->event->name;
- a_desc = as->event->desc;
- a_topic = as->event->topic ?: "";
- a_pmu_name = as->event->pmu_name;
- }
- if (bs->event) {
- b_name = bs->event->name;
- b_desc = bs->event->desc;
- b_topic = bs->event->topic ?: "";
- b_pmu_name = bs->event->pmu_name;
- }
- /* Put extra events last. */
- if (!!a_desc != !!b_desc)
- return !!a_desc - !!b_desc;
-
- /* Order by topics. */
- ret = strcmp(a_topic, b_topic);
- if (ret)
- return ret;
-
- /* Order CPU core events to be first */
- if (as->is_cpu != bs->is_cpu)
- return as->is_cpu ? -1 : 1;
-
- /* Order by PMU name. */
- if (as->pmu != bs->pmu) {
- a_pmu_name = a_pmu_name ?: (as->pmu->name ?: "");
- b_pmu_name = b_pmu_name ?: (bs->pmu->name ?: "");
- ret = strcmp(a_pmu_name, b_pmu_name);
- if (ret)
- return ret;
- }
-
- /* Order by event name. */
- return strcmp(a_name, b_name);
+ return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name);
}
-bool is_pmu_core(const char *name)
+bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu)
{
- return !strcmp(name, "cpu") || is_arm_pmu_core(name);
+ return pmu->is_core;
}
-static bool pmu_alias_is_duplicate(struct sevent *alias_a,
- struct sevent *alias_b)
+bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu)
{
- const char *a_pmu_name = NULL, *b_pmu_name = NULL;
- const char *a_name = "//", *b_name = "//";
-
-
- if (alias_a->event) {
- a_name = alias_a->event->name;
- a_pmu_name = alias_a->event->pmu_name;
- }
- if (alias_b->event) {
- b_name = alias_b->event->name;
- b_pmu_name = alias_b->event->pmu_name;
- }
-
- /* Different names -> never duplicates */
- if (strcmp(a_name, b_name))
- return false;
-
- /* Don't remove duplicates for different PMUs */
- a_pmu_name = a_pmu_name ?: (alias_a->pmu->name ?: "");
- b_pmu_name = b_pmu_name ?: (alias_b->pmu->name ?: "");
- return strcmp(a_pmu_name, b_pmu_name) == 0;
+ return pmu->is_core && perf_pmus__num_core_pmus() == 1;
}
-void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
+bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name)
{
- struct perf_pmu *pmu;
- struct perf_pmu_alias *event;
- char buf[1024];
- int printed = 0;
- int len, j;
- struct sevent *aliases;
-
- pmu = NULL;
- len = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- list_for_each_entry(event, &pmu->aliases, list)
- len++;
- if (pmu->selectable)
- len++;
- }
- aliases = zalloc(sizeof(struct sevent) * len);
- if (!aliases) {
- pr_err("FATAL: not enough memory to print PMU events\n");
- return;
- }
- pmu = NULL;
- j = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name);
-
- list_for_each_entry(event, &pmu->aliases, list) {
- aliases[j].event = event;
- aliases[j].pmu = pmu;
- aliases[j].is_cpu = is_cpu;
- j++;
- }
- if (pmu->selectable) {
- aliases[j].event = NULL;
- aliases[j].pmu = pmu;
- aliases[j].is_cpu = is_cpu;
- j++;
- }
- }
- len = j;
- qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
- for (j = 0; j < len; j++) {
- const char *name, *alias = NULL, *scale_unit = NULL,
- *desc = NULL, *long_desc = NULL,
- *encoding_desc = NULL, *topic = NULL,
- *pmu_name = NULL;
- bool deprecated = false;
- size_t buf_used;
-
- /* Skip duplicates */
- if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
- continue;
+ struct perf_pmu_alias *alias;
- if (!aliases[j].event) {
- /* A selectable event. */
- pmu_name = aliases[j].pmu->name;
- buf_used = snprintf(buf, sizeof(buf), "%s//", pmu_name) + 1;
- name = buf;
- } else {
- if (aliases[j].event->desc) {
- name = aliases[j].event->name;
- buf_used = 0;
- } else {
- name = format_alias(buf, sizeof(buf), aliases[j].pmu,
- aliases[j].event);
- if (aliases[j].is_cpu) {
- alias = name;
- name = aliases[j].event->name;
- }
- buf_used = strlen(buf) + 1;
- }
- pmu_name = aliases[j].event->pmu_name ?: (aliases[j].pmu->name ?: "");
- if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) {
- scale_unit = buf + buf_used;
- buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
- "%G%s", aliases[j].event->scale,
- aliases[j].event->unit) + 1;
- }
- desc = aliases[j].event->desc;
- long_desc = aliases[j].event->long_desc;
- topic = aliases[j].event->topic;
- encoding_desc = buf + buf_used;
- buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
- "%s/%s/", pmu_name, aliases[j].event->str) + 1;
- deprecated = aliases[j].event->deprecated;
- }
- print_cb->print_event(print_state,
- pmu_name,
- topic,
- name,
- alias,
- scale_unit,
- deprecated,
- "Kernel PMU event",
- desc,
- long_desc,
- encoding_desc);
+ list_for_each_entry(alias, &pmu->aliases, list) {
+ if (!strcmp(alias->name, name))
+ return true;
}
- if (printed && pager_in_use())
- printf("\n");
-
- zfree(&aliases);
- return;
+ return false;
}
-bool pmu_have_event(const char *pname, const char *name)
+bool perf_pmu__is_software(const struct perf_pmu *pmu)
{
- struct perf_pmu *pmu;
- struct perf_pmu_alias *alias;
-
- pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (strcmp(pname, pmu->name))
- continue;
- list_for_each_entry(alias, &pmu->aliases, list)
- if (!strcmp(alias->name, name))
- return true;
+ if (pmu->is_core || pmu->is_uncore || pmu->auxtrace)
+ return false;
+ switch (pmu->type) {
+ case PERF_TYPE_HARDWARE: return false;
+ case PERF_TYPE_SOFTWARE: return true;
+ case PERF_TYPE_TRACEPOINT: return true;
+ case PERF_TYPE_HW_CACHE: return false;
+ case PERF_TYPE_RAW: return false;
+ case PERF_TYPE_BREAKPOINT: return true;
+ default: break;
}
- return false;
+ return !strcmp(pmu->name, "kprobe") || !strcmp(pmu->name, "uprobe");
}
FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
@@ -1967,47 +1625,53 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu)
return pmu->nr_caps;
}
-void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
- const char *name)
+static void perf_pmu__compute_config_masks(struct perf_pmu *pmu)
{
struct perf_pmu_format *format;
- __u64 masks = 0, bits;
- char buf[100];
- unsigned int i;
+
+ if (pmu->config_masks_computed)
+ return;
list_for_each_entry(format, &pmu->format, list) {
- if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG)
+ unsigned int i;
+ __u64 *mask;
+
+ if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END)
continue;
+ pmu->config_masks_present = true;
+ mask = &pmu->config_masks[format->value];
+
for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS)
- masks |= 1ULL << i;
+ *mask |= 1ULL << i;
}
+ pmu->config_masks_computed = true;
+}
+
+void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
+ const char *name, int config_num,
+ const char *config_name)
+{
+ __u64 bits;
+ char buf[100];
+
+ perf_pmu__compute_config_masks(pmu);
/*
* Kernel doesn't export any valid format bits.
*/
- if (masks == 0)
+ if (!pmu->config_masks_present)
return;
- bits = config & ~masks;
+ bits = config & ~pmu->config_masks[config_num];
if (bits == 0)
return;
bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf));
- pr_warning("WARNING: event '%s' not valid (bits %s of config "
+ pr_warning("WARNING: event '%s' not valid (bits %s of %s "
"'%llx' not supported by kernel)!\n",
- name ?: "N/A", buf, config);
-}
-
-bool perf_pmu__has_hybrid(void)
-{
- if (!hybrid_scanned) {
- hybrid_scanned = true;
- perf_pmu__scan(NULL);
- }
-
- return !list_empty(&perf_pmu__hybrid_pmus);
+ name ?: "N/A", buf, config_name, config);
}
int perf_pmu__match(char *pattern, char *name, char *tok)
@@ -2024,39 +1688,6 @@ int perf_pmu__match(char *pattern, char *name, char *tok)
return 0;
}
-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)
-{
- struct perf_cpu_map *pmu_cpus = pmu->cpus;
- struct perf_cpu_map *matched_cpus, *unmatched_cpus;
- struct perf_cpu cpu;
- int i, matched_nr = 0, unmatched_nr = 0;
-
- matched_cpus = perf_cpu_map__default_new();
- if (!matched_cpus)
- return -1;
-
- unmatched_cpus = perf_cpu_map__default_new();
- if (!unmatched_cpus) {
- perf_cpu_map__put(matched_cpus);
- return -1;
- }
-
- perf_cpu_map__for_each_cpu(cpu, i, cpus) {
- if (!perf_cpu_map__has(pmu_cpus, cpu))
- RC_CHK_ACCESS(unmatched_cpus)->map[unmatched_nr++] = cpu;
- else
- RC_CHK_ACCESS(matched_cpus)->map[matched_nr++] = cpu;
- }
-
- perf_cpu_map__set_nr(unmatched_cpus, unmatched_nr);
- perf_cpu_map__set_nr(matched_cpus, matched_nr);
- *mcpus_ptr = matched_cpus;
- *ucpus_ptr = unmatched_cpus;
- return 0;
-}
-
double __weak perf_pmu__cpu_slots_per_cycle(void)
{
return NAN;
@@ -2110,7 +1741,7 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename,
return openat(dirfd, path, flags);
}
-static void perf_pmu__delete(struct perf_pmu *pmu)
+void perf_pmu__delete(struct perf_pmu *pmu)
{
perf_pmu__del_formats(&pmu->format);
perf_pmu__del_aliases(pmu);
@@ -2123,15 +1754,3 @@ static void perf_pmu__delete(struct perf_pmu *pmu)
zfree(&pmu->alias_name);
free(pmu);
}
-
-void perf_pmu__destroy(void)
-{
- struct perf_pmu *pmu, *tmp;
-
- list_for_each_entry_safe(pmu, tmp, &pmus, list) {
- list_del(&pmu->list);
- list_del(&pmu->hybrid_list);
-
- perf_pmu__delete(pmu);
- }
-}