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

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
Loading
Loading
Loading
Loading
+135 −30
Original line number Diff line number Diff line
@@ -1416,53 +1416,45 @@ static int timerlat_main(void *data)
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * stop_per_cpu_kthread - stop per-cpu threads
 *
 * Stop the osnoise sampling htread. Use this on unload and at system
 * shutdown.
 * stop_kthread - stop a workload thread
 */
static void stop_per_cpu_kthreads(void)
static void stop_kthread(unsigned int cpu)
{
	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;
}
}

/*
 * start_per_cpu_kthread - Kick off per-cpu osnoise sampling kthreads
 * stop_per_cpu_kthread - Stop per-cpu threads
 *
 * This starts the kernel thread that will look for osnoise on many
 * cpus.
 * Stop the osnoise sampling htread. Use this on unload and at system
 * shutdown.
 */
static int start_per_cpu_kthreads(struct trace_array *tr)
static void stop_per_cpu_kthreads(void)
{
	struct cpumask *current_mask = &save_cpumask;
	struct task_struct *kthread;
	char comm[24];
	void *main = osnoise_main;
	int cpu;

	get_online_cpus();
	/*
	 * Run only on CPUs in which trace and osnoise are allowed to run.
	 */
	cpumask_and(current_mask, tr->tracing_cpumask, &osnoise_cpumask);
	/*
	 * And the CPU is online.
	 */
	cpumask_and(current_mask, cpu_online_mask, current_mask);
	put_online_cpus();

	for_each_online_cpu(cpu)
		per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
		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];

	for_each_cpu(cpu, current_mask) {
#ifdef CONFIG_TIMERLAT_TRACER
	if (osnoise_data.timerlat_tracer) {
		snprintf(comm, 24, "timerlat/%d", cpu);
@@ -1483,11 +1475,116 @@ static int start_per_cpu_kthreads(struct trace_array *tr)

	per_cpu(per_cpu_osnoise_var, cpu).kthread = kthread;
	wake_up_process(kthread);

	return 0;
}

/*
 * start_per_cpu_kthread - Kick off per-cpu osnoise sampling kthreads
 *
 * This starts the kernel thread that will look for osnoise on many
 * cpus.
 */
static int start_per_cpu_kthreads(struct trace_array *tr)
{
	struct cpumask *current_mask = &save_cpumask;
	int retval;
	int cpu;

	get_online_cpus();
	/*
	 * Run only on CPUs in which trace and osnoise are allowed to run.
	 */
	cpumask_and(current_mask, tr->tracing_cpumask, &osnoise_cpumask);
	/*
	 * And the CPU is online.
	 */
	cpumask_and(current_mask, cpu_online_mask, current_mask);

	for_each_possible_cpu(cpu)
		per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;

	for_each_cpu(cpu, current_mask) {
		retval = start_kthread(cpu);
		if (retval) {
			stop_per_cpu_kthreads();
			return retval;
		}
	}

	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();