trace/osnoise: Support hotplug operations

Enable and disable osnoise/timerlat thread during on CPU hotplug online
and offline operations respectivelly.

Link: https://lore.kernel.org/linux-doc/20210621134636.5b332226@oasis.local.home/
Link: https://lkml.kernel.org/r/39f98590b3caeb3c32f09526214058efe0e9272a.1624372313.git.bristot@redhat.com

Cc: Phil Auld <pauld@redhat.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Kate Carcia <kcarcia@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Alexandre Chartre <alexandre.chartre@oracle.com>
Cc: Clark Willaims <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Suggested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Daniel Bristot de Oliveira <bristot@redhat.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Daniel Bristot de Oliveira 2021-06-22 16:42:32 +02:00 committed by Steven Rostedt (VMware)
parent ba998f7d95
commit c8895e271f

View file

@ -1416,22 +1416,67 @@ static int timerlat_main(void *data)
#endif /* CONFIG_TIMERLAT_TRACER */
/*
* stop_per_cpu_kthread - stop per-cpu threads
* stop_kthread - stop a workload thread
*/
static void stop_kthread(unsigned int cpu)
{
struct task_struct *kthread;
kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread;
if (kthread)
kthread_stop(kthread);
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
}
/*
* stop_per_cpu_kthread - Stop per-cpu threads
*
* Stop the osnoise sampling htread. Use this on unload and at system
* shutdown.
*/
static void stop_per_cpu_kthreads(void)
{
struct task_struct *kthread;
int cpu;
for_each_online_cpu(cpu) {
kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread;
if (kthread)
kthread_stop(kthread);
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
get_online_cpus();
for_each_online_cpu(cpu)
stop_kthread(cpu);
put_online_cpus();
}
/*
* start_kthread - Start a workload tread
*/
static int start_kthread(unsigned int cpu)
{
struct task_struct *kthread;
void *main = osnoise_main;
char comm[24];
#ifdef CONFIG_TIMERLAT_TRACER
if (osnoise_data.timerlat_tracer) {
snprintf(comm, 24, "timerlat/%d", cpu);
main = timerlat_main;
} else {
snprintf(comm, 24, "osnoise/%d", cpu);
}
#else
snprintf(comm, 24, "osnoise/%d", cpu);
#endif
kthread = kthread_create_on_cpu(main, NULL, cpu, comm);
if (IS_ERR(kthread)) {
pr_err(BANNER "could not start sampling thread\n");
stop_per_cpu_kthreads();
return -ENOMEM;
}
per_cpu(per_cpu_osnoise_var, cpu).kthread = kthread;
wake_up_process(kthread);
return 0;
}
/*
@ -1443,9 +1488,7 @@ static void stop_per_cpu_kthreads(void)
static int start_per_cpu_kthreads(struct trace_array *tr)
{
struct cpumask *current_mask = &save_cpumask;
struct task_struct *kthread;
char comm[24];
void *main = osnoise_main;
int retval;
int cpu;
get_online_cpus();
@ -1457,37 +1500,91 @@ static int start_per_cpu_kthreads(struct trace_array *tr)
* And the CPU is online.
*/
cpumask_and(current_mask, cpu_online_mask, current_mask);
put_online_cpus();
for_each_online_cpu(cpu)
for_each_possible_cpu(cpu)
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
for_each_cpu(cpu, current_mask) {
#ifdef CONFIG_TIMERLAT_TRACER
if (osnoise_data.timerlat_tracer) {
snprintf(comm, 24, "timerlat/%d", cpu);
main = timerlat_main;
} else {
snprintf(comm, 24, "osnoise/%d", cpu);
}
#else
snprintf(comm, 24, "osnoise/%d", cpu);
#endif
kthread = kthread_create_on_cpu(main, NULL, cpu, comm);
if (IS_ERR(kthread)) {
pr_err(BANNER "could not start sampling thread\n");
retval = start_kthread(cpu);
if (retval) {
stop_per_cpu_kthreads();
return -ENOMEM;
return retval;
}
per_cpu(per_cpu_osnoise_var, cpu).kthread = kthread;
wake_up_process(kthread);
}
put_online_cpus();
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
static void osnoise_hotplug_workfn(struct work_struct *dummy)
{
struct trace_array *tr = osnoise_trace;
unsigned int cpu = smp_processor_id();
mutex_lock(&trace_types_lock);
if (!osnoise_busy)
goto out_unlock_trace;
mutex_lock(&interface_lock);
get_online_cpus();
if (!cpumask_test_cpu(cpu, &osnoise_cpumask))
goto out_unlock;
if (!cpumask_test_cpu(cpu, tr->tracing_cpumask))
goto out_unlock;
start_kthread(cpu);
out_unlock:
put_online_cpus();
mutex_unlock(&interface_lock);
out_unlock_trace:
mutex_unlock(&trace_types_lock);
}
static DECLARE_WORK(osnoise_hotplug_work, osnoise_hotplug_workfn);
/*
* osnoise_cpu_init - CPU hotplug online callback function
*/
static int osnoise_cpu_init(unsigned int cpu)
{
schedule_work_on(cpu, &osnoise_hotplug_work);
return 0;
}
/*
* osnoise_cpu_die - CPU hotplug offline callback function
*/
static int osnoise_cpu_die(unsigned int cpu)
{
stop_kthread(cpu);
return 0;
}
static void osnoise_init_hotplug_support(void)
{
int ret;
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "trace/osnoise:online",
osnoise_cpu_init, osnoise_cpu_die);
if (ret < 0)
pr_warn(BANNER "Error to init cpu hotplug support\n");
return;
}
#else /* CONFIG_HOTPLUG_CPU */
static void osnoise_init_hotplug_support(void)
{
return 0;
}
#endif /* CONFIG_HOTPLUG_CPU */
/*
* osnoise_cpus_read - Read function for reading the "cpus" file
* @filp: The active open file structure
@ -1583,7 +1680,14 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count,
osnoise_tracer_stop(tr);
mutex_lock(&interface_lock);
/*
* osnoise_cpumask is read by CPU hotplug operations.
*/
get_online_cpus();
cpumask_copy(&osnoise_cpumask, osnoise_cpumask_new);
put_online_cpus();
mutex_unlock(&interface_lock);
if (running)
@ -1940,6 +2044,7 @@ __init static int init_osnoise_tracer(void)
return ret;
}
#endif
osnoise_init_hotplug_support();
init_tracefs();