Loading arch/arm64/kernel/perf_event.c +48 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #include <linux/perf/arm_pmu.h> #include <linux/platform_device.h> static DEFINE_PER_CPU(bool, is_hotplugging); /* * ARMv8 PMUv3 Performance Events handling code. * Common event types (some are defined in asm/perf_event.h). Loading Loading @@ -982,6 +984,9 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) if (!cpu_pmu) return; if (__this_cpu_read(is_hotplugging)) return; hw_events = this_cpu_ptr(cpu_pmu->hw_events); if (!hw_events) Loading Loading @@ -1031,14 +1036,13 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) pmu_idle_nb->cpu_pmu = cpu_pmu; pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier; idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); ret = smp_call_function_any(&cpu_pmu->supported_cpus, __armv8pmu_probe_pmu, cpu_pmu, 1); if (ret) idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb); if (!ret) idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); return ret; } Loading Loading @@ -1140,6 +1144,37 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = { {}, }; #ifdef CONFIG_HOTPLUG_CPU static int perf_event_hotplug_coming_up(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = false; return 0; } static int perf_event_hotplug_going_down(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = true; return 0; } static int perf_event_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_NOTIFY_ONLINE, "PERF_EVENT/CPUHP_AP_NOTIFY_ONLINE", perf_event_hotplug_coming_up, perf_event_hotplug_going_down); if (ret) pr_err("CPU hotplug notifier for perf_event.c could not be registered: %d\n", ret); return ret; } #else static int perf_event_cpu_hp_init(void) { return 0; } #endif /* * Non DT systems have their micro/arch events probed at run-time. * A fairly complete list of generic events are provided and ones that Loading @@ -1152,6 +1187,16 @@ static const struct pmu_probe_info armv8_pmu_probe_table[] = { static int armv8_pmu_device_probe(struct platform_device *pdev) { int ret, cpu; for_each_possible_cpu(cpu) per_cpu(is_hotplugging, cpu) = false; ret = perf_event_cpu_hp_init(); if (ret) return ret; if (acpi_disabled) return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL); Loading kernel/events/core.c +41 −45 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); static DEFINE_PER_CPU(bool, is_idle); static DEFINE_PER_CPU(bool, is_hotplugging); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; Loading Loading @@ -3495,6 +3496,9 @@ static void __perf_event_read(void *info) struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); struct pmu *pmu = event->pmu; if (__this_cpu_read(is_hotplugging)) return; /* * If this is a task context, we need to check whether it is * the current task context of this cpu. If not it has been Loading Loading @@ -3619,7 +3623,8 @@ static int perf_event_read(struct perf_event *event, bool group) return 0; if (cpu_isolated(event_cpu) || (event->attr.exclude_idle && per_cpu(is_idle, event_cpu))) per_cpu(is_idle, event_cpu)) || per_cpu(is_hotplugging, event_cpu)) active_event_skip_read = true; } Loading Loading @@ -3649,7 +3654,8 @@ static int perf_event_read(struct perf_event *event, bool group) preempt_enable(); ret = data.ret; } else if (event->state == PERF_EVENT_STATE_INACTIVE || active_event_skip_read) { (active_event_skip_read && !per_cpu(is_hotplugging, event_cpu))) { struct perf_event_context *ctx = event->ctx; unsigned long flags; Loading Loading @@ -10711,6 +10717,8 @@ static void __init perf_event_init_all_cpus(void) raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu)); INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu)); per_cpu(is_hotplugging, cpu) = false; per_cpu(is_idle, cpu) = false; } } Loading @@ -10734,19 +10742,10 @@ int perf_event_init_cpu(unsigned int cpu) static void check_hotplug_start_event(struct perf_event *event) { if (event->attr.type == PERF_TYPE_SOFTWARE) { switch (event->attr.config) { case PERF_COUNT_SW_CPU_CLOCK: cpu_clock_event_start(event, 0); break; case PERF_COUNT_SW_TASK_CLOCK: break; default: if (event->pmu->start) if (event->pmu->events_across_hotplug && event->attr.type == PERF_TYPE_SOFTWARE && event->pmu->start) event->pmu->start(event, 0); break; } } } static int perf_event_start_swevents(unsigned int cpu) Loading @@ -10767,6 +10766,7 @@ static int perf_event_start_swevents(unsigned int cpu) mutex_unlock(&ctx->mutex); } srcu_read_unlock(&pmus_srcu, idx); per_cpu(is_hotplugging, cpu) = false; return 0; } Loading @@ -10783,22 +10783,13 @@ check_hotplug_remove_from_context(struct perf_event *event, struct perf_cpu_context *cpuctx, struct perf_event_context *ctx) { if (!event->pmu->events_across_hotplug) { if (event->pmu->events_across_hotplug && event->attr.type == PERF_TYPE_SOFTWARE && event->pmu->stop) event->pmu->stop(event, PERF_EF_UPDATE); else if (!event->pmu->events_across_hotplug) __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP); } else if (event->attr.type == PERF_TYPE_SOFTWARE) { switch (event->attr.config) { case PERF_COUNT_SW_CPU_CLOCK: cpu_clock_event_stop(event, 0); break; case PERF_COUNT_SW_TASK_CLOCK: break; default: if (event->pmu->stop) event->pmu->stop(event, 0); break; } } } static void __perf_event_exit_context(void *__info) Loading Loading @@ -10837,6 +10828,7 @@ static void perf_event_exit_cpu_context(int cpu) { } int perf_event_exit_cpu(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = true; perf_event_exit_cpu_context(cpu); return 0; } Loading Loading @@ -10880,6 +10872,24 @@ static struct notifier_block perf_event_idle_nb = { .notifier_call = event_idle_notif, }; #ifdef CONFIG_HOTPLUG_CPU static int perf_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, "PERF/CORE/CPUHP_AP_PERF_ONLINE", perf_event_start_swevents, perf_event_exit_cpu); if (ret) pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", ret); return ret; } #else static int perf_cpu_hp_init(void) { return 0; } #endif void __init perf_event_init(void) { Loading @@ -10896,6 +10906,8 @@ void __init perf_event_init(void) perf_event_init_cpu(smp_processor_id()); idle_notifier_register(&perf_event_idle_nb); register_reboot_notifier(&perf_reboot_notifier); ret = perf_cpu_hp_init(); WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret); ret = init_hw_breakpoint(); WARN(ret, "hw_breakpoint initialization failed with: %d", ret); Loading Loading @@ -10949,22 +10961,6 @@ static int __init perf_event_sysfs_init(void) } device_initcall(perf_event_sysfs_init); #ifdef CONFIG_HOTPLUG_CPU static int perf_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, "PERF/CORE/AP_PERF_ONLINE", perf_event_start_swevents, perf_event_exit_cpu); if (ret) pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", ret); return ret; } subsys_initcall(perf_cpu_hp_init); #endif #ifdef CONFIG_CGROUP_PERF static struct cgroup_subsys_state * Loading Loading
arch/arm64/kernel/perf_event.c +48 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #include <linux/perf/arm_pmu.h> #include <linux/platform_device.h> static DEFINE_PER_CPU(bool, is_hotplugging); /* * ARMv8 PMUv3 Performance Events handling code. * Common event types (some are defined in asm/perf_event.h). Loading Loading @@ -982,6 +984,9 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) if (!cpu_pmu) return; if (__this_cpu_read(is_hotplugging)) return; hw_events = this_cpu_ptr(cpu_pmu->hw_events); if (!hw_events) Loading Loading @@ -1031,14 +1036,13 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) pmu_idle_nb->cpu_pmu = cpu_pmu; pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier; idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); ret = smp_call_function_any(&cpu_pmu->supported_cpus, __armv8pmu_probe_pmu, cpu_pmu, 1); if (ret) idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb); if (!ret) idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); return ret; } Loading Loading @@ -1140,6 +1144,37 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = { {}, }; #ifdef CONFIG_HOTPLUG_CPU static int perf_event_hotplug_coming_up(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = false; return 0; } static int perf_event_hotplug_going_down(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = true; return 0; } static int perf_event_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_NOTIFY_ONLINE, "PERF_EVENT/CPUHP_AP_NOTIFY_ONLINE", perf_event_hotplug_coming_up, perf_event_hotplug_going_down); if (ret) pr_err("CPU hotplug notifier for perf_event.c could not be registered: %d\n", ret); return ret; } #else static int perf_event_cpu_hp_init(void) { return 0; } #endif /* * Non DT systems have their micro/arch events probed at run-time. * A fairly complete list of generic events are provided and ones that Loading @@ -1152,6 +1187,16 @@ static const struct pmu_probe_info armv8_pmu_probe_table[] = { static int armv8_pmu_device_probe(struct platform_device *pdev) { int ret, cpu; for_each_possible_cpu(cpu) per_cpu(is_hotplugging, cpu) = false; ret = perf_event_cpu_hp_init(); if (ret) return ret; if (acpi_disabled) return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL); Loading
kernel/events/core.c +41 −45 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); static DEFINE_PER_CPU(bool, is_idle); static DEFINE_PER_CPU(bool, is_hotplugging); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; Loading Loading @@ -3495,6 +3496,9 @@ static void __perf_event_read(void *info) struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); struct pmu *pmu = event->pmu; if (__this_cpu_read(is_hotplugging)) return; /* * If this is a task context, we need to check whether it is * the current task context of this cpu. If not it has been Loading Loading @@ -3619,7 +3623,8 @@ static int perf_event_read(struct perf_event *event, bool group) return 0; if (cpu_isolated(event_cpu) || (event->attr.exclude_idle && per_cpu(is_idle, event_cpu))) per_cpu(is_idle, event_cpu)) || per_cpu(is_hotplugging, event_cpu)) active_event_skip_read = true; } Loading Loading @@ -3649,7 +3654,8 @@ static int perf_event_read(struct perf_event *event, bool group) preempt_enable(); ret = data.ret; } else if (event->state == PERF_EVENT_STATE_INACTIVE || active_event_skip_read) { (active_event_skip_read && !per_cpu(is_hotplugging, event_cpu))) { struct perf_event_context *ctx = event->ctx; unsigned long flags; Loading Loading @@ -10711,6 +10717,8 @@ static void __init perf_event_init_all_cpus(void) raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu)); INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu)); per_cpu(is_hotplugging, cpu) = false; per_cpu(is_idle, cpu) = false; } } Loading @@ -10734,19 +10742,10 @@ int perf_event_init_cpu(unsigned int cpu) static void check_hotplug_start_event(struct perf_event *event) { if (event->attr.type == PERF_TYPE_SOFTWARE) { switch (event->attr.config) { case PERF_COUNT_SW_CPU_CLOCK: cpu_clock_event_start(event, 0); break; case PERF_COUNT_SW_TASK_CLOCK: break; default: if (event->pmu->start) if (event->pmu->events_across_hotplug && event->attr.type == PERF_TYPE_SOFTWARE && event->pmu->start) event->pmu->start(event, 0); break; } } } static int perf_event_start_swevents(unsigned int cpu) Loading @@ -10767,6 +10766,7 @@ static int perf_event_start_swevents(unsigned int cpu) mutex_unlock(&ctx->mutex); } srcu_read_unlock(&pmus_srcu, idx); per_cpu(is_hotplugging, cpu) = false; return 0; } Loading @@ -10783,22 +10783,13 @@ check_hotplug_remove_from_context(struct perf_event *event, struct perf_cpu_context *cpuctx, struct perf_event_context *ctx) { if (!event->pmu->events_across_hotplug) { if (event->pmu->events_across_hotplug && event->attr.type == PERF_TYPE_SOFTWARE && event->pmu->stop) event->pmu->stop(event, PERF_EF_UPDATE); else if (!event->pmu->events_across_hotplug) __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP); } else if (event->attr.type == PERF_TYPE_SOFTWARE) { switch (event->attr.config) { case PERF_COUNT_SW_CPU_CLOCK: cpu_clock_event_stop(event, 0); break; case PERF_COUNT_SW_TASK_CLOCK: break; default: if (event->pmu->stop) event->pmu->stop(event, 0); break; } } } static void __perf_event_exit_context(void *__info) Loading Loading @@ -10837,6 +10828,7 @@ static void perf_event_exit_cpu_context(int cpu) { } int perf_event_exit_cpu(unsigned int cpu) { per_cpu(is_hotplugging, cpu) = true; perf_event_exit_cpu_context(cpu); return 0; } Loading Loading @@ -10880,6 +10872,24 @@ static struct notifier_block perf_event_idle_nb = { .notifier_call = event_idle_notif, }; #ifdef CONFIG_HOTPLUG_CPU static int perf_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, "PERF/CORE/CPUHP_AP_PERF_ONLINE", perf_event_start_swevents, perf_event_exit_cpu); if (ret) pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", ret); return ret; } #else static int perf_cpu_hp_init(void) { return 0; } #endif void __init perf_event_init(void) { Loading @@ -10896,6 +10906,8 @@ void __init perf_event_init(void) perf_event_init_cpu(smp_processor_id()); idle_notifier_register(&perf_event_idle_nb); register_reboot_notifier(&perf_reboot_notifier); ret = perf_cpu_hp_init(); WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret); ret = init_hw_breakpoint(); WARN(ret, "hw_breakpoint initialization failed with: %d", ret); Loading Loading @@ -10949,22 +10961,6 @@ static int __init perf_event_sysfs_init(void) } device_initcall(perf_event_sysfs_init); #ifdef CONFIG_HOTPLUG_CPU static int perf_cpu_hp_init(void) { int ret; ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, "PERF/CORE/AP_PERF_ONLINE", perf_event_start_swevents, perf_event_exit_cpu); if (ret) pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", ret); return ret; } subsys_initcall(perf_cpu_hp_init); #endif #ifdef CONFIG_CGROUP_PERF static struct cgroup_subsys_state * Loading