mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 11:40:53 +07:00
perf: Dynamic pmu types
Extend the perf_pmu_register() interface to allow for named and dynamic pmu types. Because we need to support the existing static types we cannot use dynamic types for everything, hence provide a type argument. If we want to enumerate the PMUs they need a name, provide one. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <20101117222056.259707703@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
9f58a205c6
commit
2e80a82a49
@ -882,7 +882,7 @@ int __init init_hw_perf_events(void)
|
|||||||
/* And set up PMU specification */
|
/* And set up PMU specification */
|
||||||
alpha_pmu = &ev67_pmu;
|
alpha_pmu = &ev67_pmu;
|
||||||
|
|
||||||
perf_pmu_register(&pmu);
|
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3034,7 +3034,7 @@ init_hw_perf_events(void)
|
|||||||
pr_info("no hardware support available\n");
|
pr_info("no hardware support available\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
perf_pmu_register(&pmu);
|
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1379,7 +1379,7 @@ int register_power_pmu(struct power_pmu *pmu)
|
|||||||
freeze_events_kernel = MMCR0_FCHV;
|
freeze_events_kernel = MMCR0_FCHV;
|
||||||
#endif /* CONFIG_PPC64 */
|
#endif /* CONFIG_PPC64 */
|
||||||
|
|
||||||
perf_pmu_register(&power_pmu);
|
perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
|
||||||
perf_cpu_notifier(power_pmu_notifier);
|
perf_cpu_notifier(power_pmu_notifier);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -681,7 +681,7 @@ int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
|
|||||||
pr_info("%s performance monitor hardware support registered\n",
|
pr_info("%s performance monitor hardware support registered\n",
|
||||||
pmu->name);
|
pmu->name);
|
||||||
|
|
||||||
perf_pmu_register(&fsl_emb_pmu);
|
perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ int __cpuinit register_sh_pmu(struct sh_pmu *_pmu)
|
|||||||
|
|
||||||
WARN_ON(_pmu->num_events > MAX_HWEVENTS);
|
WARN_ON(_pmu->num_events > MAX_HWEVENTS);
|
||||||
|
|
||||||
perf_pmu_register(&pmu);
|
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
|
||||||
perf_cpu_notifier(sh_pmu_notifier);
|
perf_cpu_notifier(sh_pmu_notifier);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1318,7 @@ int __init init_hw_perf_events(void)
|
|||||||
|
|
||||||
pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
|
pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
|
||||||
|
|
||||||
perf_pmu_register(&pmu);
|
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
|
||||||
register_die_notifier(&perf_event_nmi_notifier);
|
register_die_notifier(&perf_event_nmi_notifier);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1465,7 +1465,7 @@ int __init init_hw_perf_events(void)
|
|||||||
pr_info("... fixed-purpose events: %d\n", x86_pmu.num_counters_fixed);
|
pr_info("... fixed-purpose events: %d\n", x86_pmu.num_counters_fixed);
|
||||||
pr_info("... event mask: %016Lx\n", x86_pmu.intel_ctrl);
|
pr_info("... event mask: %016Lx\n", x86_pmu.intel_ctrl);
|
||||||
|
|
||||||
perf_pmu_register(&pmu);
|
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
|
||||||
perf_cpu_notifier(x86_pmu_notifier);
|
perf_cpu_notifier(x86_pmu_notifier);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -588,6 +588,9 @@ struct perf_event;
|
|||||||
struct pmu {
|
struct pmu {
|
||||||
struct list_head entry;
|
struct list_head entry;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
int type;
|
||||||
|
|
||||||
int * __percpu pmu_disable_count;
|
int * __percpu pmu_disable_count;
|
||||||
struct perf_cpu_context * __percpu pmu_cpu_context;
|
struct perf_cpu_context * __percpu pmu_cpu_context;
|
||||||
int task_ctx_nr;
|
int task_ctx_nr;
|
||||||
@ -916,7 +919,7 @@ struct perf_output_handle {
|
|||||||
|
|
||||||
#ifdef CONFIG_PERF_EVENTS
|
#ifdef CONFIG_PERF_EVENTS
|
||||||
|
|
||||||
extern int perf_pmu_register(struct pmu *pmu);
|
extern int perf_pmu_register(struct pmu *pmu, char *name, int type);
|
||||||
extern void perf_pmu_unregister(struct pmu *pmu);
|
extern void perf_pmu_unregister(struct pmu *pmu);
|
||||||
|
|
||||||
extern int perf_num_counters(void);
|
extern int perf_num_counters(void);
|
||||||
|
@ -641,7 +641,7 @@ int __init init_hw_breakpoint(void)
|
|||||||
|
|
||||||
constraints_initialized = 1;
|
constraints_initialized = 1;
|
||||||
|
|
||||||
perf_pmu_register(&perf_breakpoint);
|
perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT);
|
||||||
|
|
||||||
return register_die_notifier(&hw_breakpoint_exceptions_nb);
|
return register_die_notifier(&hw_breakpoint_exceptions_nb);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@ -4961,7 +4962,7 @@ static struct pmu perf_tracepoint = {
|
|||||||
|
|
||||||
static inline void perf_tp_register(void)
|
static inline void perf_tp_register(void)
|
||||||
{
|
{
|
||||||
perf_pmu_register(&perf_tracepoint);
|
perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event_set_filter(struct perf_event *event, void __user *arg)
|
static int perf_event_set_filter(struct perf_event *event, void __user *arg)
|
||||||
@ -5305,8 +5306,9 @@ static void free_pmu_context(struct pmu *pmu)
|
|||||||
out:
|
out:
|
||||||
mutex_unlock(&pmus_lock);
|
mutex_unlock(&pmus_lock);
|
||||||
}
|
}
|
||||||
|
static struct idr pmu_idr;
|
||||||
|
|
||||||
int perf_pmu_register(struct pmu *pmu)
|
int perf_pmu_register(struct pmu *pmu, char *name, int type)
|
||||||
{
|
{
|
||||||
int cpu, ret;
|
int cpu, ret;
|
||||||
|
|
||||||
@ -5316,13 +5318,32 @@ int perf_pmu_register(struct pmu *pmu)
|
|||||||
if (!pmu->pmu_disable_count)
|
if (!pmu->pmu_disable_count)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
pmu->type = -1;
|
||||||
|
if (!name)
|
||||||
|
goto skip_type;
|
||||||
|
pmu->name = name;
|
||||||
|
|
||||||
|
if (type < 0) {
|
||||||
|
int err = idr_pre_get(&pmu_idr, GFP_KERNEL);
|
||||||
|
if (!err)
|
||||||
|
goto free_pdc;
|
||||||
|
|
||||||
|
err = idr_get_new_above(&pmu_idr, pmu, PERF_TYPE_MAX, &type);
|
||||||
|
if (err) {
|
||||||
|
ret = err;
|
||||||
|
goto free_pdc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pmu->type = type;
|
||||||
|
|
||||||
|
skip_type:
|
||||||
pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);
|
pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);
|
||||||
if (pmu->pmu_cpu_context)
|
if (pmu->pmu_cpu_context)
|
||||||
goto got_cpu_context;
|
goto got_cpu_context;
|
||||||
|
|
||||||
pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
|
pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
|
||||||
if (!pmu->pmu_cpu_context)
|
if (!pmu->pmu_cpu_context)
|
||||||
goto free_pdc;
|
goto free_ird;
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
struct perf_cpu_context *cpuctx;
|
struct perf_cpu_context *cpuctx;
|
||||||
@ -5366,6 +5387,10 @@ int perf_pmu_register(struct pmu *pmu)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
free_idr:
|
||||||
|
if (pmu->type >= PERF_TYPE_MAX)
|
||||||
|
idr_remove(&pmu_idr, pmu->type);
|
||||||
|
|
||||||
free_pdc:
|
free_pdc:
|
||||||
free_percpu(pmu->pmu_disable_count);
|
free_percpu(pmu->pmu_disable_count);
|
||||||
goto unlock;
|
goto unlock;
|
||||||
@ -5385,6 +5410,8 @@ void perf_pmu_unregister(struct pmu *pmu)
|
|||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
free_percpu(pmu->pmu_disable_count);
|
free_percpu(pmu->pmu_disable_count);
|
||||||
|
if (pmu->type >= PERF_TYPE_MAX)
|
||||||
|
idr_remove(&pmu_idr, pmu->type);
|
||||||
free_pmu_context(pmu);
|
free_pmu_context(pmu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5394,6 +5421,13 @@ struct pmu *perf_init_event(struct perf_event *event)
|
|||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = srcu_read_lock(&pmus_srcu);
|
idx = srcu_read_lock(&pmus_srcu);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
pmu = idr_find(&pmu_idr, event->attr.type);
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (pmu)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
list_for_each_entry_rcu(pmu, &pmus, entry) {
|
list_for_each_entry_rcu(pmu, &pmus, entry) {
|
||||||
int ret = pmu->event_init(event);
|
int ret = pmu->event_init(event);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -6555,11 +6589,13 @@ void __init perf_event_init(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
idr_init(&pmu_idr);
|
||||||
|
|
||||||
perf_event_init_all_cpus();
|
perf_event_init_all_cpus();
|
||||||
init_srcu_struct(&pmus_srcu);
|
init_srcu_struct(&pmus_srcu);
|
||||||
perf_pmu_register(&perf_swevent);
|
perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE);
|
||||||
perf_pmu_register(&perf_cpu_clock);
|
perf_pmu_register(&perf_cpu_clock, NULL, -1);
|
||||||
perf_pmu_register(&perf_task_clock);
|
perf_pmu_register(&perf_task_clock, NULL, -1);
|
||||||
perf_tp_register();
|
perf_tp_register();
|
||||||
perf_cpu_notifier(perf_cpu_notify);
|
perf_cpu_notifier(perf_cpu_notify);
|
||||||
register_reboot_notifier(&perf_reboot_notifier);
|
register_reboot_notifier(&perf_reboot_notifier);
|
||||||
|
Loading…
Reference in New Issue
Block a user