As part of the per-console loglevel implementation, printk_delay()
introduces a call to suppress_message_printing_everywhere() within
printk_delay(). This check acquires the console SRCU lock and iterates
through all registered consoles to determine if the message implies a
delay based on per-console loglevels.
Since printk_delay() is called in the hotpath of vprintk_emit(), this
introduces measurable overhead (locking and pointer chasing) for every
printk message, even on systems where no delay is configured.
Optimise this by short-circuiting the function. If neither a boot delay
nor a runtime printk_delay_msec is configured, return immediately. This
avoids the expensive console list iteration in the common case where
delays are disabled.
Signed-off-by: Chris Down <chris@chrisdown.name>
---
kernel/printk/printk.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 0d7f3dac8177..13e17d892ec9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2233,20 +2233,31 @@ int printk_delay_msec __read_mostly;
static inline void printk_delay(int level)
{
+ bool boot_delay_active = false;
+ int m;
+
+#ifdef CONFIG_BOOT_PRINTK_DELAY
+ boot_delay_active = boot_delay && system_state < SYSTEM_RUNNING;
+#endif
+
+ if (!boot_delay_active && !READ_ONCE(printk_delay_msec))
+ return;
+
/* If the message is forced (e.g. panic), we must delay */
if (!is_printk_force_console() &&
suppress_message_printing_everywhere(level))
return;
- boot_delay_msec();
+ if (boot_delay_active)
+ boot_delay_msec();
- if (unlikely(printk_delay_msec)) {
- int m = printk_delay_msec;
+ m = READ_ONCE(printk_delay_msec);
+ if (!m)
+ return;
- while (m--) {
- mdelay(1);
- touch_nmi_watchdog();
- }
+ while (m--) {
+ mdelay(1);
+ touch_nmi_watchdog();
}
}
--
2.51.2