mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Daniel Bristot de Oliveira <bristot@kernel.org>
To: Nicolas Saenz Julienne <nsaenzju@redhat.com>
Cc: mingo@redhat.com, linux-kernel@vger.kernel.org,
	mtosatti@redhat.com, paulmck@kernel.org, rostedt@goodmis.org,
	Juri Lelli <juri.lelli@redhat.com>
Subject: Re: [PATCH] tracing/osnoise: Force quiescent states while tracing
Date: Fri, 4 Mar 2022 15:51:20 +0100	[thread overview]
Message-ID: <abb789c3-0d1a-28e9-3b8d-e4a68e3f57f5@kernel.org> (raw)
In-Reply-To: <b5e1f0d14a48c0815863af623cedbdc8c1bc255f.camel@redhat.com>

>> Hey Nicolas,
>>
>> While testing this patch with rtla osnoise on the 5.17.0-rc6-rt10+, when I hit
>> ^c on osnoise top, the system freezes :-/.
>>
>> Could you try that on your system?
> Yes of course, I'll get a build going.


also, could you try this? 

it is an RFC I was thinking to send, as I mentioned before (and on IRC).

It works fine, I see nohz_full and rcu behaving like if osnoise was a
user-space tool. It is more invasive on osnoise, but the behavior does not
change - like, run cyclictest on top of osnoise and you will see that
the system is still preemptive with low latency even with osnoise with
"preempt_disabled."

do you mind having a look to see if it behaves as expected in your scenario?

[ note, there are things to cleanup in this patch, like adding a static key ]
[ in is_osnoise_cur(), it was a real RFC. 				    ]

-- Daniel

tracing/osnoise: Pretend to be in user-space for RCU

To simulate an user-space workload, osnoise informs RCU that it
is going to user-space by calling rcu_user_enter(). However,
osnoise never actually goes to user-space. It keeps running
in an intermediate stage.

This stage runs with preemption disabled, like the idle thread
does. Likewise idle, osnoise will continuously check for need
resched, allowing its preemption, simulating a fully preemptive
mode.

Anytime a kernel function needs to be called, the rcu_user_enter()
needs to be called.

Any change on rcu_user_enter/exit needs to be tested with
CONFIG_RCU_EQS_DEBUG=y.

Signed-off-by: Daniel Bristot de Oliveira <bristot@redhat.com>
---
 include/linux/trace.h        |   9 +++
 kernel/rcu/tree.c            |   7 +-
 kernel/trace/trace_osnoise.c | 129 +++++++++++++++++++++++++++++++++--
 3 files changed, 136 insertions(+), 9 deletions(-)

diff --git a/include/linux/trace.h b/include/linux/trace.h
index bf169612ffe1..970d66f79cee 100644
--- a/include/linux/trace.h
+++ b/include/linux/trace.h
@@ -48,6 +48,15 @@ void osnoise_arch_unregister(void);
 void osnoise_trace_irq_entry(int id);
 void osnoise_trace_irq_exit(int id, const char *desc);
 
+#ifdef CONFIG_OSNOISE_TRACER
+extern bool is_osnoise_curr(void);
+#else
+static __always_inline bool is_osnoise_curr(void)
+{
+	return false;
+}
+#endif /* CONFIG_OSNOISE_TRACER */
+
 #endif	/* CONFIG_TRACING */
 
 #endif	/* _LINUX_TRACE_H */
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index a4c25a6283b0..ede0c468e75f 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -62,6 +62,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/kasan.h>
+#include <linux/trace.h>
 #include "../time/tick-internal.h"
 
 #include "tree.h"
@@ -442,9 +443,11 @@ static int rcu_is_cpu_rrupt_from_idle(void)
 		return false;
 
 	/*
-	 * If we're not in an interrupt, we must be in the idle task!
+	 * If we're not in an interrupt, we must be in the idle task or osnoise.
+	 * The osnoise thread is an special case. It is a kernel thread that
+	 * pretends to be in user-space. See kernel/trace/trace_osnoise.c.
 	 */
-	WARN_ON_ONCE(!nesting && !is_idle_task(current));
+	WARN_ON_ONCE(!nesting && !(is_idle_task(current) || is_osnoise_curr()));
 
 	/* Does CPU appear to be idle from an RCU standpoint? */
 	return __this_cpu_read(rcu_data.dynticks_nesting) == 0;
diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c
index cfddb30e65ab..d52ef290c884 100644
--- a/kernel/trace/trace_osnoise.c
+++ b/kernel/trace/trace_osnoise.c
@@ -448,6 +448,31 @@ static void print_osnoise_headers(struct seq_file *s)
 }
 #endif /* CONFIG_PREEMPT_RT */
 
+static inline void osnoise_user_enter(void)
+{
+	local_irq_disable();
+	rcu_user_enter();
+	local_irq_enable();
+}
+
+static inline void osnoise_user_exit(void)
+{
+	local_irq_disable();
+	rcu_user_exit();
+	local_irq_enable();
+}
+
+static inline void osnoise_cond_resched(void)
+{
+	if (need_resched()) {
+		osnoise_user_exit();
+		preempt_enable();
+		cond_resched();
+		preempt_disable();
+		osnoise_user_enter();
+	}
+}
+
 /*
  * osnoise_taint - report an osnoise error.
  */
@@ -464,6 +489,14 @@ static void print_osnoise_headers(struct seq_file *s)
 	osnoise_data.tainted = true;						\
 })
 
+#define osnoise_taint_user(msg) ({						\
+	local_irq_disable();							\
+	rcu_user_exit();							\
+	osnoise_taint(msg);							\
+	rcu_user_enter();							\
+	local_irq_enable();							\
+})
+
 /*
  * Record an osnoise_sample into the tracer buffer.
  */
@@ -819,6 +852,43 @@ set_int_safe_time(struct osnoise_variables *osn_var, u64 *time)
 	return int_counter;
 }
 
+/*
+ * set_int_safe_time_thread - Save the current time on *time, aware of interference
+ *
+ * Get the time, taking into consideration a possible interference from
+ * higher priority interrupts and threads.
+ *
+ * See get_int_safe_duration() for an explanation.
+ */
+static u64
+set_int_safe_time_thread(struct osnoise_variables *osn_var, u64 *time)
+{
+	u64 int_counter;
+
+	do {
+		int_counter = local_read(&osn_var->int_counter);
+
+		/* let any thread awakened by an interrupt to run */
+		osnoise_cond_resched();
+
+		/* synchronize with interrupts */
+		barrier();
+
+		*time = time_get();
+
+		/* synchronize with interrupts */
+		barrier();
+
+	} while (int_counter != local_read(&osn_var->int_counter));
+
+	/*
+	 * At this point, the time accounts all the interference from to
+	 * consecutive get time that did not get interfered.
+	 */
+	return int_counter;
+}
+
+
 #ifdef CONFIG_TIMERLAT_TRACER
 /*
  * copy_int_safe_time - Copy *src into *desc aware of interference
@@ -1337,11 +1407,31 @@ static int run_osnoise(void)
 	 */
 	last_int_count = set_int_safe_time(osn_var, &last_sample);
 
+	/*
+	 * to simulate an user-space workload, osnoise informs RCU that it
+	 * is going to user-space by calling rcu_user_enter(). However,
+	 * osnoise never actually goes to user-space. It keeps running
+	 * in an intermediate stage.
+	 *
+	 * This stage runs with preemption disabled, like the idle thread
+	 * does. Likewise idle, osnoise will continuously check for need
+	 * resched, allowing its preemption, simulating a fully preemptive
+	 * mode.
+	 *
+	 * Anytime a kernel function needs to be called, the rcu_user_enter()
+	 * needs to be called.
+	 *
+	 * Any change on rcu_user_enter/exit needs to be tested with
+	 * CONFIG_RCU_EQS_DEBUG=y.
+	 */
+	preempt_disable();
+	osnoise_user_enter();
+
 	do {
 		/*
 		 * Get sample!
 		 */
-		int_count = set_int_safe_time(osn_var, &sample);
+		int_count = set_int_safe_time_thread(osn_var, &sample);
 
 		noise = time_sub(sample, last_sample);
 
@@ -1349,7 +1439,7 @@ static int run_osnoise(void)
 		 * This shouldn't happen.
 		 */
 		if (noise < 0) {
-			osnoise_taint("negative noise!");
+			osnoise_taint_user("negative noise!");
 			goto out;
 		}
 
@@ -1362,7 +1452,7 @@ static int run_osnoise(void)
 		 * Check for possible overflows.
 		 */
 		if (total < last_total) {
-			osnoise_taint("total overflow!");
+			osnoise_taint_user("total overflow!");
 			break;
 		}
 
@@ -1379,24 +1469,41 @@ static int run_osnoise(void)
 
 			sum_noise += noise;
 
+			/*
+			 * osnoise is in fake user-space. Leave this mode to call
+			 * the tracepoint. Interrupts are kept disabled to avoid
+			 * having the overhead of enabling/disabling around
+			 * rcu_user_exit/enter again. This does not change the
+			 * behavior of osnoise.
+			 */
+			local_irq_disable();
+			rcu_user_exit();
 			trace_sample_threshold(last_sample, noise, interference);
+			rcu_user_enter();
+			local_irq_enable();
 
 			if (osnoise_data.stop_tracing)
-				if (noise > stop_in)
+				if (noise > stop_in) {
+					osnoise_user_exit();
 					osnoise_stop_tracing();
+					osnoise_user_enter();
+				}
 		}
 
+
 		/*
-		 * For the non-preemptive kernel config: let threads runs, if
-		 * they so wish.
+		 * Let threads to interfere with osnoise.
 		 */
-		cond_resched();
+		osnoise_cond_resched();
 
 		last_sample = sample;
 		last_int_count = int_count;
 
 	} while (total < runtime && !kthread_should_stop());
 
+	osnoise_user_exit();
+	preempt_enable();
+
 	/*
 	 * Finish the above in the view for interrupts.
 	 */
@@ -2387,3 +2494,11 @@ __init static int init_osnoise_tracer(void)
 	return 0;
 }
 late_initcall(init_osnoise_tracer);
+
+bool is_osnoise_curr(void)
+{
+	struct osnoise_variables *osn_var = this_cpu_osn_var();
+	if (osn_var->kthread == current)
+		return 1;
+	return 0;
+}
-- 
2.34.1

  parent reply	other threads:[~2022-03-04 14:51 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-28 14:14 Nicolas Saenz Julienne
2022-02-28 15:45 ` Steven Rostedt
2022-03-01 10:59   ` Nicolas Saenz Julienne
2022-03-01 17:30     ` Daniel Bristot de Oliveira
2022-02-28 20:00 ` Daniel Bristot de Oliveira
2022-03-01 10:52   ` Nicolas Saenz Julienne
2022-03-01 17:55     ` Daniel Bristot de Oliveira
2022-03-01 18:05       ` Paul E. McKenney
2022-03-01 18:44         ` Daniel Bristot de Oliveira
2022-03-01 18:58           ` Paul E. McKenney
2022-03-01 19:29             ` Daniel Bristot de Oliveira
2022-03-01 19:46               ` Paul E. McKenney
2022-03-01 19:53                 ` Daniel Bristot de Oliveira
2022-02-28 22:11 ` Paul E. McKenney
2022-03-01 10:00   ` Nicolas Saenz Julienne
2022-03-01 17:44     ` Daniel Bristot de Oliveira
2022-03-01 17:56     ` Paul E. McKenney
2022-03-02 10:46       ` Nicolas Saenz Julienne
2022-03-04 14:28 ` Daniel Bristot de Oliveira
2022-03-04 14:36   ` Nicolas Saenz Julienne
2022-03-04 14:39     ` Daniel Bristot de Oliveira
2022-03-04 14:51     ` Daniel Bristot de Oliveira [this message]
2022-03-04 15:28       ` Nicolas Saenz Julienne
2022-03-04 15:37         ` Daniel Bristot de Oliveira
2022-03-04 15:55           ` Nicolas Saenz Julienne
2022-03-04 16:26             ` Paul E. McKenney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=abb789c3-0d1a-28e9-3b8d-e4a68e3f57f5@kernel.org \
    --to=bristot@kernel.org \
    --cc=juri.lelli@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=nsaenzju@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome