summaryrefslogtreecommitdiff
path: root/tools/perf/util/env.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/env.c')
-rw-r--r--tools/perf/util/env.c187
1 files changed, 182 insertions, 5 deletions
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index cae4f6d63318..1e54e2c86360 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,8 +3,10 @@
#include "debug.h"
#include "env.h"
#include "util/header.h"
-#include "linux/compiler.h"
+#include "util/rwsem.h"
+#include <linux/compiler.h>
#include <linux/ctype.h>
+#include <linux/rbtree.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include "cgroup.h"
@@ -17,8 +19,6 @@
#include "strbuf.h"
#include "trace/beauty/beauty.h"
-struct perf_env perf_env;
-
#ifdef HAVE_LIBBPF_SUPPORT
#include "bpf-event.h"
#include "bpf-utils.h"
@@ -89,6 +89,20 @@ out:
return node;
}
+void perf_env__iterate_bpf_prog_info(struct perf_env *env,
+ void (*cb)(struct bpf_prog_info_node *node,
+ void *data),
+ void *data)
+{
+ struct rb_node *first;
+
+ down_read(&env->bpf_progs.lock);
+ first = rb_first(&env->bpf_progs.infos);
+ for (struct rb_node *node = first; node != NULL; node = rb_next(node))
+ (*cb)(rb_entry(node, struct bpf_prog_info_node, rb_node), data);
+ up_read(&env->bpf_progs.lock);
+}
+
bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
{
bool ret;
@@ -174,6 +188,7 @@ static void perf_env__purge_bpf(struct perf_env *env)
next = rb_next(&node->rb_node);
rb_erase(&node->rb_node, root);
zfree(&node->info_linear);
+ bpf_metadata_free(node->metadata);
free(node);
}
@@ -201,6 +216,34 @@ static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
}
#endif // HAVE_LIBBPF_SUPPORT
+void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
+{
+ if (!cd_map)
+ return;
+
+ for (u32 i = 0; i < nr; i++) {
+ if (!cd_map[i])
+ continue;
+
+ for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
+ struct domain_info *d_info = cd_map[i]->domains[j];
+
+ if (!d_info)
+ continue;
+
+ if (schedstat_version >= 17)
+ zfree(&d_info->dname);
+
+ zfree(&d_info->cpumask);
+ zfree(&d_info->cpulist);
+ zfree(&d_info);
+ }
+ zfree(&cd_map[i]->domains);
+ zfree(&cd_map[i]);
+ }
+ zfree(&cd_map);
+}
+
void perf_env__exit(struct perf_env *env)
{
int i, j;
@@ -250,10 +293,12 @@ void perf_env__exit(struct perf_env *env)
zfree(&env->pmu_caps[i].pmu_name);
}
zfree(&env->pmu_caps);
+ free_cpu_domain_info(env->cpu_domain, env->schedstat_version, env->nr_cpus_avail);
}
void perf_env__init(struct perf_env *env)
{
+ memset(env, 0, sizeof(*env));
#ifdef HAVE_LIBBPF_SUPPORT
env->bpf_progs.infos = RB_ROOT;
env->bpf_progs.btfs = RB_ROOT;
@@ -416,6 +461,116 @@ static int perf_env__read_nr_cpus_avail(struct perf_env *env)
return env->nr_cpus_avail ? 0 : -ENOENT;
}
+static int __perf_env__read_core_pmu_caps(const struct perf_pmu *pmu,
+ int *nr_caps, char ***caps,
+ unsigned int *max_branches,
+ unsigned int *br_cntr_nr,
+ unsigned int *br_cntr_width)
+{
+ struct perf_pmu_caps *pcaps = NULL;
+ char *ptr, **tmp;
+ int ret = 0;
+
+ *nr_caps = 0;
+ *caps = NULL;
+
+ if (!pmu->nr_caps)
+ return 0;
+
+ *caps = calloc(pmu->nr_caps, sizeof(char *));
+ if (!*caps)
+ return -ENOMEM;
+
+ tmp = *caps;
+ list_for_each_entry(pcaps, &pmu->caps, list) {
+ if (asprintf(&ptr, "%s=%s", pcaps->name, pcaps->value) < 0) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ *tmp++ = ptr;
+
+ if (!strcmp(pcaps->name, "branches"))
+ *max_branches = atoi(pcaps->value);
+ else if (!strcmp(pcaps->name, "branch_counter_nr"))
+ *br_cntr_nr = atoi(pcaps->value);
+ else if (!strcmp(pcaps->name, "branch_counter_width"))
+ *br_cntr_width = atoi(pcaps->value);
+ }
+ *nr_caps = pmu->nr_caps;
+ return 0;
+error:
+ while (tmp-- != *caps)
+ zfree(tmp);
+ zfree(caps);
+ *nr_caps = 0;
+ return ret;
+}
+
+int perf_env__read_core_pmu_caps(struct perf_env *env)
+{
+ struct pmu_caps *pmu_caps;
+ struct perf_pmu *pmu = NULL;
+ int nr_pmu, i = 0, j;
+ int ret;
+
+ nr_pmu = perf_pmus__num_core_pmus();
+
+ if (!nr_pmu)
+ return -ENODEV;
+
+ if (nr_pmu == 1) {
+ pmu = perf_pmus__find_core_pmu();
+ if (!pmu)
+ return -ENODEV;
+ ret = perf_pmu__caps_parse(pmu);
+ if (ret < 0)
+ return ret;
+ return __perf_env__read_core_pmu_caps(pmu, &env->nr_cpu_pmu_caps,
+ &env->cpu_pmu_caps,
+ &env->max_branches,
+ &env->br_cntr_nr,
+ &env->br_cntr_width);
+ }
+
+ pmu_caps = calloc(nr_pmu, sizeof(*pmu_caps));
+ if (!pmu_caps)
+ return -ENOMEM;
+
+ while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+ if (perf_pmu__caps_parse(pmu) <= 0)
+ continue;
+ ret = __perf_env__read_core_pmu_caps(pmu, &pmu_caps[i].nr_caps,
+ &pmu_caps[i].caps,
+ &pmu_caps[i].max_branches,
+ &pmu_caps[i].br_cntr_nr,
+ &pmu_caps[i].br_cntr_width);
+ if (ret)
+ goto error;
+
+ pmu_caps[i].pmu_name = strdup(pmu->name);
+ if (!pmu_caps[i].pmu_name) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ i++;
+ }
+
+ env->nr_pmus_with_caps = nr_pmu;
+ env->pmu_caps = pmu_caps;
+
+ return 0;
+error:
+ for (i = 0; i < nr_pmu; i++) {
+ for (j = 0; j < pmu_caps[i].nr_caps; j++)
+ zfree(&pmu_caps[i].caps[j]);
+ zfree(&pmu_caps[i].caps);
+ zfree(&pmu_caps[i].pmu_name);
+ }
+ zfree(&pmu_caps);
+ return ret;
+}
+
const char *perf_env__raw_arch(struct perf_env *env)
{
return env && !perf_env__read_arch(env) ? env->arch : "unknown";
@@ -543,7 +698,7 @@ int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
for (i = 0; i < env->nr_numa_nodes; i++) {
nn = &env->numa_nodes[i];
- nr = max(nr, perf_cpu_map__max(nn->map).cpu);
+ nr = max(nr, (int)perf_cpu_map__max(nn->map).cpu);
}
nr++;
@@ -563,7 +718,7 @@ int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
for (i = 0; i < env->nr_numa_nodes; i++) {
struct perf_cpu tmp;
- int j;
+ unsigned int j;
nn = &env->numa_nodes[i];
perf_cpu_map__for_each_cpu(tmp, j, nn->map)
@@ -676,3 +831,25 @@ bool x86__is_amd_cpu(void)
return is_amd;
}
+
+bool perf_env__is_x86_intel_cpu(struct perf_env *env)
+{
+ static int is_intel; /* 0: Uninitialized, 1: Yes, -1: No */
+
+ if (is_intel == 0)
+ is_intel = env->cpuid && strstarts(env->cpuid, "GenuineIntel") ? 1 : -1;
+
+ return is_intel >= 1 ? true : false;
+}
+
+bool x86__is_intel_cpu(void)
+{
+ struct perf_env env = { .total_mem = 0, };
+ bool is_intel;
+
+ perf_env__cpuid(&env);
+ is_intel = perf_env__is_x86_intel_cpu(&env);
+ perf_env__exit(&env);
+
+ return is_intel;
+}