Re: [PATCH v7 2/4] preemptirq_delay_test: Add the burst feature and a sysfs trigger

2019-10-01 Thread Joel Fernandes
On Fri, Sep 20, 2019 at 05:22:17PM +0200, Viktor Rosendahl (BMW) wrote:
> This burst feature enables the user to generate a burst of
> preempt/irqsoff latencies. This makes it possible to test whether we
> are able to detect latencies that systematically occur very close to
> each other.
> 
> The maximum burst size is 10. We also create 10 identical test
> functions, so that we get 10 different backtraces; this is useful
> when we want to test whether we can detect all the latencies in a
> burst. Otherwise, there would be no easy way of differentiating
> between which latency in a burst was captured by the tracer.
> 
> In addition, there is a sysfs trigger, so that it's not necessary to
> reload the module to repeat the test. The trigger will appear as
> /sys/kernel/preemptirq_delay_test/trigger in sysfs.
> 
> Signed-off-by: Viktor Rosendahl (BMW) 

Reviewed-by: Joel Fernandes (Google) 

thanks,

 - Joel


> ---
>  kernel/trace/Kconfig |   6 +-
>  kernel/trace/preemptirq_delay_test.c | 144 +++
>  2 files changed, 128 insertions(+), 22 deletions(-)
> 
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index e08527f50d2a..2a58380ea310 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -752,9 +752,9 @@ config PREEMPTIRQ_DELAY_TEST
> configurable delay. The module busy waits for the duration of the
> critical section.
>  
> -   For example, the following invocation forces a one-time irq-disabled
> -   critical section for 500us:
> -   modprobe preemptirq_delay_test test_mode=irq delay=50
> +   For example, the following invocation generates a burst of three
> +   irq-disabled critical sections for 500us:
> +   modprobe preemptirq_delay_test test_mode=irq delay=500 burst_size=3
>  
> If unsure, say N
>  
> diff --git a/kernel/trace/preemptirq_delay_test.c 
> b/kernel/trace/preemptirq_delay_test.c
> index d8765c952fab..31c0fad4cb9e 100644
> --- a/kernel/trace/preemptirq_delay_test.c
> +++ b/kernel/trace/preemptirq_delay_test.c
> @@ -10,18 +10,25 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  static ulong delay = 100;
> -static char test_mode[10] = "irq";
> +static char test_mode[12] = "irq";
> +static uint burst_size = 1;
>  
> -module_param_named(delay, delay, ulong, S_IRUGO);
> -module_param_string(test_mode, test_mode, 10, S_IRUGO);
> -MODULE_PARM_DESC(delay, "Period in microseconds (100 uS default)");
> -MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt or irq 
> (default irq)");
> +module_param_named(delay, delay, ulong, 0444);
> +module_param_string(test_mode, test_mode, 12, 0444);
> +module_param_named(burst_size, burst_size, uint, 0444);
> +MODULE_PARM_DESC(delay, "Period in microseconds (100 us default)");
> +MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt, irq, or 
> alternate (default irq)");
> +MODULE_PARM_DESC(burst_size, "The size of a burst (default 1)");
> +
> +#define MIN(x, y) ((x) < (y) ? (x) : (y))
>  
>  static void busy_wait(ulong time)
>  {
> @@ -34,37 +41,136 @@ static void busy_wait(ulong time)
>   } while ((end - start) < (time * 1000));
>  }
>  
> -static int preemptirq_delay_run(void *data)
> +static __always_inline void irqoff_test(void)
>  {
>   unsigned long flags;
> + local_irq_save(flags);
> + busy_wait(delay);
> + local_irq_restore(flags);
> +}
>  
> - if (!strcmp(test_mode, "irq")) {
> - local_irq_save(flags);
> - busy_wait(delay);
> - local_irq_restore(flags);
> - } else if (!strcmp(test_mode, "preempt")) {
> - preempt_disable();
> - busy_wait(delay);
> - preempt_enable();
> +static __always_inline void preemptoff_test(void)
> +{
> + preempt_disable();
> + busy_wait(delay);
> + preempt_enable();
> +}
> +
> +static void execute_preemptirqtest(int idx)
> +{
> + if (!strcmp(test_mode, "irq"))
> + irqoff_test();
> + else if (!strcmp(test_mode, "preempt"))
> + preemptoff_test();
> + else if (!strcmp(test_mode, "alternate")) {
> + if (idx % 2 == 0)
> + irqoff_test();
> + else
> + preemptoff_test();
>   }
> +}
> +
> +#define DECLARE_TESTFN(POSTFIX)  \
> + static void preemptirqtest_##POSTFIX(int idx)   \
> + {   \
> + execute_preemptirqtest(idx);\
> + }   \
>  
> +/*
> + * We create 10 different functions, so that we can get 10 different
> + * backtraces.
> + */
> +DECLARE_TESTFN(0)
> +DECLARE_TESTFN(1)
> +DECLARE_TESTFN(2)
> +DECLARE_TESTFN(3)
> +DECLARE_TESTFN(4)
> +DECLARE_TESTFN(5)
> +DECLARE_TESTFN(6)
> +DECLARE_TESTFN(7)
> +DECLARE_TESTFN(8)
> +DECLARE_TESTFN(9)
> +
> +static void 

[PATCH v7 2/4] preemptirq_delay_test: Add the burst feature and a sysfs trigger

2019-09-20 Thread Viktor Rosendahl (BMW)
This burst feature enables the user to generate a burst of
preempt/irqsoff latencies. This makes it possible to test whether we
are able to detect latencies that systematically occur very close to
each other.

The maximum burst size is 10. We also create 10 identical test
functions, so that we get 10 different backtraces; this is useful
when we want to test whether we can detect all the latencies in a
burst. Otherwise, there would be no easy way of differentiating
between which latency in a burst was captured by the tracer.

In addition, there is a sysfs trigger, so that it's not necessary to
reload the module to repeat the test. The trigger will appear as
/sys/kernel/preemptirq_delay_test/trigger in sysfs.

Signed-off-by: Viktor Rosendahl (BMW) 
---
 kernel/trace/Kconfig |   6 +-
 kernel/trace/preemptirq_delay_test.c | 144 +++
 2 files changed, 128 insertions(+), 22 deletions(-)

diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index e08527f50d2a..2a58380ea310 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -752,9 +752,9 @@ config PREEMPTIRQ_DELAY_TEST
  configurable delay. The module busy waits for the duration of the
  critical section.
 
- For example, the following invocation forces a one-time irq-disabled
- critical section for 500us:
- modprobe preemptirq_delay_test test_mode=irq delay=50
+ For example, the following invocation generates a burst of three
+ irq-disabled critical sections for 500us:
+ modprobe preemptirq_delay_test test_mode=irq delay=500 burst_size=3
 
  If unsure, say N
 
diff --git a/kernel/trace/preemptirq_delay_test.c 
b/kernel/trace/preemptirq_delay_test.c
index d8765c952fab..31c0fad4cb9e 100644
--- a/kernel/trace/preemptirq_delay_test.c
+++ b/kernel/trace/preemptirq_delay_test.c
@@ -10,18 +10,25 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 
 static ulong delay = 100;
-static char test_mode[10] = "irq";
+static char test_mode[12] = "irq";
+static uint burst_size = 1;
 
-module_param_named(delay, delay, ulong, S_IRUGO);
-module_param_string(test_mode, test_mode, 10, S_IRUGO);
-MODULE_PARM_DESC(delay, "Period in microseconds (100 uS default)");
-MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt or irq (default 
irq)");
+module_param_named(delay, delay, ulong, 0444);
+module_param_string(test_mode, test_mode, 12, 0444);
+module_param_named(burst_size, burst_size, uint, 0444);
+MODULE_PARM_DESC(delay, "Period in microseconds (100 us default)");
+MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt, irq, or 
alternate (default irq)");
+MODULE_PARM_DESC(burst_size, "The size of a burst (default 1)");
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
 
 static void busy_wait(ulong time)
 {
@@ -34,37 +41,136 @@ static void busy_wait(ulong time)
} while ((end - start) < (time * 1000));
 }
 
-static int preemptirq_delay_run(void *data)
+static __always_inline void irqoff_test(void)
 {
unsigned long flags;
+   local_irq_save(flags);
+   busy_wait(delay);
+   local_irq_restore(flags);
+}
 
-   if (!strcmp(test_mode, "irq")) {
-   local_irq_save(flags);
-   busy_wait(delay);
-   local_irq_restore(flags);
-   } else if (!strcmp(test_mode, "preempt")) {
-   preempt_disable();
-   busy_wait(delay);
-   preempt_enable();
+static __always_inline void preemptoff_test(void)
+{
+   preempt_disable();
+   busy_wait(delay);
+   preempt_enable();
+}
+
+static void execute_preemptirqtest(int idx)
+{
+   if (!strcmp(test_mode, "irq"))
+   irqoff_test();
+   else if (!strcmp(test_mode, "preempt"))
+   preemptoff_test();
+   else if (!strcmp(test_mode, "alternate")) {
+   if (idx % 2 == 0)
+   irqoff_test();
+   else
+   preemptoff_test();
}
+}
+
+#define DECLARE_TESTFN(POSTFIX)\
+   static void preemptirqtest_##POSTFIX(int idx)   \
+   {   \
+   execute_preemptirqtest(idx);\
+   }   \
 
+/*
+ * We create 10 different functions, so that we can get 10 different
+ * backtraces.
+ */
+DECLARE_TESTFN(0)
+DECLARE_TESTFN(1)
+DECLARE_TESTFN(2)
+DECLARE_TESTFN(3)
+DECLARE_TESTFN(4)
+DECLARE_TESTFN(5)
+DECLARE_TESTFN(6)
+DECLARE_TESTFN(7)
+DECLARE_TESTFN(8)
+DECLARE_TESTFN(9)
+
+static void (*testfuncs[])(int)  = {
+   preemptirqtest_0,
+   preemptirqtest_1,
+   preemptirqtest_2,
+   preemptirqtest_3,
+   preemptirqtest_4,
+   preemptirqtest_5,
+   preemptirqtest_6,
+   preemptirqtest_7,
+   preemptirqtest_8,
+   preemptirqtest_9,
+};
+
+#define NR_TEST_FUNCS ARRAY_SIZE(testfuncs)
+