[PATCH v3 1/2] trace/preemptirq: reduce overhead of irq_enable/disable tracepoints

Wander Lairson Costa posted 2 patches 3 months ago
[PATCH v3 1/2] trace/preemptirq: reduce overhead of irq_enable/disable tracepoints
Posted by Wander Lairson Costa 3 months ago
The irqsoff tracer is rarely enabled in production systems due to the
non-negligible overhead it introduces—even when unused. This is caused
by how trace_hardirqs_on/off() are always invoked in
local_irq_enable/disable(), evaluate the tracepoint static key.

This patch reduces the overhead in the common case where the tracepoint
is disabled by performing the static key check earlier, avoiding the
call to trace_hardirqs_on/off() entirely.

This makes the impact of disabled preemptirq IRQ tracing negligible in
performance-sensitive environments.

We also move the atomic.h include from tracepoint-defs.h to tracepoint.h
due a circular dependency when building 32 bits ARM.

The failure occurs because the new logic in <linux/irqflags.h> calls
tracepoint_enabled(), which requires the tracepoint-defs.h header file.
This header, in turn, includes <linux/atomic.h>. On ARM32, the include
path for kernel/bounds.c creates a circular dependency:
atomic.h -> cmpxchg.h -> irqflags.h -> tracepoint.h -> atomic.h

Signed-off-by: Wander Lairson Costa <wander@redhat.com>
Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Clark Williams <williams@redhat.com>
Cc: Gabriele Monaco <gmonaco@redhat.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
---
 include/linux/irqflags.h        | 30 +++++++++++++++++++++---------
 include/linux/tracepoint-defs.h |  1 -
 include/linux/tracepoint.h      |  1 +
 kernel/trace/trace_preemptirq.c |  3 +++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index 57b074e0cfbb..40e456fa3d10 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h
@@ -17,6 +17,7 @@
 #include <linux/cleanup.h>
 #include <asm/irqflags.h>
 #include <asm/percpu.h>
+#include <linux/tracepoint-defs.h>
 
 struct task_struct;
 
@@ -197,9 +198,17 @@ extern void warn_bogus_irq_restore(void);
  */
 #ifdef CONFIG_TRACE_IRQFLAGS
 
+DECLARE_TRACEPOINT(irq_enable);
+DECLARE_TRACEPOINT(irq_disable);
+
+#define __trace_enabled(tp)				\
+	(IS_ENABLED(CONFIG_PROVE_LOCKING) ||		\
+	 tracepoint_enabled(tp))
+
 #define local_irq_enable()				\
 	do {						\
-		trace_hardirqs_on();			\
+		if (__trace_enabled(irq_enable))	\
+			trace_hardirqs_on();		\
 		raw_local_irq_enable();			\
 	} while (0)
 
@@ -207,31 +216,34 @@ extern void warn_bogus_irq_restore(void);
 	do {						\
 		bool was_disabled = raw_irqs_disabled();\
 		raw_local_irq_disable();		\
-		if (!was_disabled)			\
+		if (__trace_enabled(irq_disable) &&	\
+		    !was_disabled)			\
 			trace_hardirqs_off();		\
 	} while (0)
 
 #define local_irq_save(flags)				\
 	do {						\
 		raw_local_irq_save(flags);		\
-		if (!raw_irqs_disabled_flags(flags))	\
+		if (__trace_enabled(irq_disable) &&	\
+		    !raw_irqs_disabled_flags(flags))	\
 			trace_hardirqs_off();		\
 	} while (0)
 
 #define local_irq_restore(flags)			\
 	do {						\
-		if (!raw_irqs_disabled_flags(flags))	\
+		if (__trace_enabled(irq_enable) &&	\
+		    !raw_irqs_disabled_flags(flags))	\
 			trace_hardirqs_on();		\
 		raw_local_irq_restore(flags);		\
 	} while (0)
 
-#define safe_halt()				\
-	do {					\
-		trace_hardirqs_on();		\
-		raw_safe_halt();		\
+#define safe_halt()					\
+	do {						\
+		if (__trace_enabled(irq_enable))	\
+			trace_hardirqs_on();		\
+		raw_safe_halt();			\
 	} while (0)
 
-
 #else /* !CONFIG_TRACE_IRQFLAGS */
 
 #define local_irq_enable()	do { raw_local_irq_enable(); } while (0)
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index aebf0571c736..cb1f15a4e43f 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -8,7 +8,6 @@
  * trace_print_flags{_u64}. Otherwise linux/tracepoint.h should be used.
  */
 
-#include <linux/atomic.h>
 #include <linux/static_key.h>
 
 struct static_call_key;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 826ce3f8e1f8..2fd91ef49b7f 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -20,6 +20,7 @@
 #include <linux/rcupdate_trace.h>
 #include <linux/tracepoint-defs.h>
 #include <linux/static_call.h>
+#include <linux/atomic.h>
 
 struct module;
 struct tracepoint;
diff --git a/kernel/trace/trace_preemptirq.c b/kernel/trace/trace_preemptirq.c
index 0c42b15c3800..90ee65db4516 100644
--- a/kernel/trace/trace_preemptirq.c
+++ b/kernel/trace/trace_preemptirq.c
@@ -111,6 +111,9 @@ void trace_hardirqs_off(void)
 }
 EXPORT_SYMBOL(trace_hardirqs_off);
 NOKPROBE_SYMBOL(trace_hardirqs_off);
+
+EXPORT_TRACEPOINT_SYMBOL(irq_disable);
+EXPORT_TRACEPOINT_SYMBOL(irq_enable);
 #endif /* CONFIG_TRACE_IRQFLAGS */
 
 #ifdef CONFIG_TRACE_PREEMPT_TOGGLE
-- 
2.50.0

Re: [PATCH v3 1/2] trace/preemptirq: reduce overhead of irq_enable/disable tracepoints
Posted by kernel test robot 3 months ago
Hi Wander,

kernel test robot noticed the following build errors:

[auto build test ERROR on trace/for-next]
[also build test ERROR on tip/sched/core linus/master v6.16-rc4 next-20250704]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Wander-Lairson-Costa/trace-preemptirq-reduce-overhead-of-irq_enable-disable-tracepoints/20250705-011058
base:   https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link:    https://lore.kernel.org/r/20250704170748.97632-2-wander%40redhat.com
patch subject: [PATCH v3 1/2] trace/preemptirq: reduce overhead of irq_enable/disable tracepoints
config: nios2-randconfig-r123-20250706 (https://download.01.org/0day-ci/archive/20250706/202507061226.y7g5eBuq-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 8.5.0
reproduce: (https://download.01.org/0day-ci/archive/20250706/202507061226.y7g5eBuq-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507061226.y7g5eBuq-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from ./arch/nios2/include/generated/asm/cmpxchg.h:1,
                    from include/asm-generic/atomic.h:12,
                    from ./arch/nios2/include/generated/asm/atomic.h:1,
                    from include/linux/atomic.h:7,
                    from include/linux/jump_label.h:257,
                    from include/linux/static_key.h:1,
                    from include/linux/tracepoint-defs.h:11,
                    from include/linux/irqflags.h:20,
                    from include/asm-generic/bitops.h:14,
                    from ./arch/nios2/include/generated/asm/bitops.h:1,
                    from include/linux/bitops.h:68,
                    from include/linux/log2.h:12,
                    from kernel/bounds.c:13:
   include/asm-generic/cmpxchg.h: In function '__generic_xchg':
>> include/asm-generic/cmpxchg.h:33:3: error: implicit declaration of function 'local_irq_save'; did you mean 'arch_local_irq_save'? [-Werror=implicit-function-declaration]
      local_irq_save(flags);
      ^~~~~~~~~~~~~~
      arch_local_irq_save
>> include/asm-generic/cmpxchg.h:36:3: error: implicit declaration of function 'local_irq_restore'; did you mean 'arch_local_irq_restore'? [-Werror=implicit-function-declaration]
      local_irq_restore(flags);
      ^~~~~~~~~~~~~~~~~
      arch_local_irq_restore
   In file included from include/asm-generic/cmpxchg.h:89,
                    from ./arch/nios2/include/generated/asm/cmpxchg.h:1,
                    from include/asm-generic/atomic.h:12,
                    from ./arch/nios2/include/generated/asm/atomic.h:1,
                    from include/linux/atomic.h:7,
                    from include/linux/jump_label.h:257,
                    from include/linux/static_key.h:1,
                    from include/linux/tracepoint-defs.h:11,
                    from include/linux/irqflags.h:20,
                    from include/asm-generic/bitops.h:14,
                    from ./arch/nios2/include/generated/asm/bitops.h:1,
                    from include/linux/bitops.h:68,
                    from include/linux/log2.h:12,
                    from kernel/bounds.c:13:
   include/asm-generic/cmpxchg-local.h: In function '__generic_cmpxchg_local':
>> include/asm-generic/cmpxchg-local.h:26:2: error: implicit declaration of function 'raw_local_irq_save'; did you mean 'arch_local_irq_save'? [-Werror=implicit-function-declaration]
     raw_local_irq_save(flags);
     ^~~~~~~~~~~~~~~~~~
     arch_local_irq_save
>> include/asm-generic/cmpxchg-local.h:47:2: error: implicit declaration of function 'raw_local_irq_restore'; did you mean 'arch_local_irq_restore'? [-Werror=implicit-function-declaration]
     raw_local_irq_restore(flags);
     ^~~~~~~~~~~~~~~~~~~~~
     arch_local_irq_restore
   cc1: some warnings being treated as errors
   make[3]: *** [scripts/Makefile.build:98: kernel/bounds.s] Error 1
   make[3]: Target 'prepare' not remade because of errors.
   make[2]: *** [Makefile:1274: prepare0] Error 2
   make[2]: Target 'prepare' not remade because of errors.
   make[1]: *** [Makefile:248: __sub-make] Error 2
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2
   make: Target 'prepare' not remade because of errors.


vim +33 include/asm-generic/cmpxchg.h

b4816afa3986704 David Howells 2012-03-28  22  
b4816afa3986704 David Howells 2012-03-28  23  static inline
82b993e8249ae3c Mark Rutland  2021-05-25  24  unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
b4816afa3986704 David Howells 2012-03-28  25  {
b4816afa3986704 David Howells 2012-03-28  26  	unsigned long ret, flags;
b4816afa3986704 David Howells 2012-03-28  27  
b4816afa3986704 David Howells 2012-03-28  28  	switch (size) {
b4816afa3986704 David Howells 2012-03-28  29  	case 1:
b4816afa3986704 David Howells 2012-03-28  30  #ifdef __xchg_u8
b4816afa3986704 David Howells 2012-03-28  31  		return __xchg_u8(x, ptr);
b4816afa3986704 David Howells 2012-03-28  32  #else
b4816afa3986704 David Howells 2012-03-28 @33  		local_irq_save(flags);
b4816afa3986704 David Howells 2012-03-28  34  		ret = *(volatile u8 *)ptr;
656e9007ef58627 Arnd Bergmann 2023-03-02  35  		*(volatile u8 *)ptr = (x & 0xffu);
b4816afa3986704 David Howells 2012-03-28 @36  		local_irq_restore(flags);
b4816afa3986704 David Howells 2012-03-28  37  		return ret;
b4816afa3986704 David Howells 2012-03-28  38  #endif /* __xchg_u8 */
b4816afa3986704 David Howells 2012-03-28  39  
b4816afa3986704 David Howells 2012-03-28  40  	case 2:
b4816afa3986704 David Howells 2012-03-28  41  #ifdef __xchg_u16
b4816afa3986704 David Howells 2012-03-28  42  		return __xchg_u16(x, ptr);
b4816afa3986704 David Howells 2012-03-28  43  #else
b4816afa3986704 David Howells 2012-03-28  44  		local_irq_save(flags);
b4816afa3986704 David Howells 2012-03-28  45  		ret = *(volatile u16 *)ptr;
656e9007ef58627 Arnd Bergmann 2023-03-02  46  		*(volatile u16 *)ptr = (x & 0xffffu);
b4816afa3986704 David Howells 2012-03-28  47  		local_irq_restore(flags);
b4816afa3986704 David Howells 2012-03-28  48  		return ret;
b4816afa3986704 David Howells 2012-03-28  49  #endif /* __xchg_u16 */
b4816afa3986704 David Howells 2012-03-28  50  
b4816afa3986704 David Howells 2012-03-28  51  	case 4:
b4816afa3986704 David Howells 2012-03-28  52  #ifdef __xchg_u32
b4816afa3986704 David Howells 2012-03-28  53  		return __xchg_u32(x, ptr);
b4816afa3986704 David Howells 2012-03-28  54  #else
b4816afa3986704 David Howells 2012-03-28  55  		local_irq_save(flags);
b4816afa3986704 David Howells 2012-03-28  56  		ret = *(volatile u32 *)ptr;
656e9007ef58627 Arnd Bergmann 2023-03-02  57  		*(volatile u32 *)ptr = (x & 0xffffffffu);
b4816afa3986704 David Howells 2012-03-28  58  		local_irq_restore(flags);
b4816afa3986704 David Howells 2012-03-28  59  		return ret;
b4816afa3986704 David Howells 2012-03-28  60  #endif /* __xchg_u32 */
b4816afa3986704 David Howells 2012-03-28  61  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki