Commit c8895e27 authored by Daniel Bristot de Oliveira's avatar Daniel Bristot de Oliveira Committed by Steven Rostedt (VMware)

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: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: default avatarDaniel Bristot de Oliveira <bristot@redhat.com>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent ba998f7d
...@@ -1416,22 +1416,67 @@ static int timerlat_main(void *data) ...@@ -1416,22 +1416,67 @@ static int timerlat_main(void *data)
#endif /* CONFIG_TIMERLAT_TRACER */ #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 * Stop the osnoise sampling htread. Use this on unload and at system
* shutdown. * shutdown.
*/ */
static void stop_per_cpu_kthreads(void) static void stop_per_cpu_kthreads(void)
{ {
struct task_struct *kthread;
int cpu; int cpu;
for_each_online_cpu(cpu) { get_online_cpus();
kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread;
if (kthread) for_each_online_cpu(cpu)
kthread_stop(kthread); stop_kthread(cpu);
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
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) ...@@ -1443,9 +1488,7 @@ static void stop_per_cpu_kthreads(void)
static int start_per_cpu_kthreads(struct trace_array *tr) static int start_per_cpu_kthreads(struct trace_array *tr)
{ {
struct cpumask *current_mask = &save_cpumask; struct cpumask *current_mask = &save_cpumask;
struct task_struct *kthread; int retval;
char comm[24];
void *main = osnoise_main;
int cpu; int cpu;
get_online_cpus(); get_online_cpus();
...@@ -1457,37 +1500,91 @@ static int start_per_cpu_kthreads(struct trace_array *tr) ...@@ -1457,37 +1500,91 @@ static int start_per_cpu_kthreads(struct trace_array *tr)
* And the CPU is online. * And the CPU is online.
*/ */
cpumask_and(current_mask, cpu_online_mask, current_mask); 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; per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
for_each_cpu(cpu, current_mask) { for_each_cpu(cpu, current_mask) {
#ifdef CONFIG_TIMERLAT_TRACER retval = start_kthread(cpu);
if (osnoise_data.timerlat_tracer) { if (retval) {
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(); 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; 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 * osnoise_cpus_read - Read function for reading the "cpus" file
* @filp: The active open file structure * @filp: The active open file structure
...@@ -1583,7 +1680,14 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count, ...@@ -1583,7 +1680,14 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count,
osnoise_tracer_stop(tr); osnoise_tracer_stop(tr);
mutex_lock(&interface_lock); mutex_lock(&interface_lock);
/*
* osnoise_cpumask is read by CPU hotplug operations.
*/
get_online_cpus();
cpumask_copy(&osnoise_cpumask, osnoise_cpumask_new); cpumask_copy(&osnoise_cpumask, osnoise_cpumask_new);
put_online_cpus();
mutex_unlock(&interface_lock); mutex_unlock(&interface_lock);
if (running) if (running)
...@@ -1940,6 +2044,7 @@ __init static int init_osnoise_tracer(void) ...@@ -1940,6 +2044,7 @@ __init static int init_osnoise_tracer(void)
return ret; return ret;
} }
#endif #endif
osnoise_init_hotplug_support();
init_tracefs(); init_tracefs();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment