Re: [PATCH v4 1/1] printk: fix zero-valued printk timestamps in early boot
From: Geert Uytterhoeven
Date: Tue Apr 14 2026 - 03:06:27 EST
Hi Tim,
Thanks for your patch!
On Fri, 10 Apr 2026 at 22:38, Tim Bird <tim.bird@xxxxxxxx> wrote:
> During early boot, printk timestamps are reported as zero before
> kernel timekeeping starts (i.e. before time_init()). This
> hinders boot-time optimization efforts. This period ranges from
> 17 to 1700 milliseconds on different embedded machines running Linux.
>
> Add support for early timestamps based on processor cycle-generators
> that need no kernel initialization. Use a statically-configured
> frequency value for converting cycles to nanoseconds. This means
> that this feature cannot be turned on in generic distro kernels.
> It is intended for temporary use during kernel development and
> boot-time research and optimization only.
>
> This yields non-zero timestamps for printks from the very start
> of kernel execution. The timestamps are relative to the start of
> an architecture-specific counter (e.g. tsc on x86_64 and cntvct_el0
> on arm64). Affected timestamps reflect time from cycle counter
> init (usually machine power-on or virtual machine start) instead of
> time from the kernel's timekeeping initialization. This results in a
> discontinuity in the printk timestamp values, one time, when
> kernel timekeeping starts.
Won't it be hard to see where the discontinuity happens in some cases?
Perhaps this can be made more obvious by not doing the time conversion
in kernelspace, like in your first version?
> Signed-off-by: Tim Bird <tim.bird@xxxxxxxx>
> --- /dev/null
> +++ b/include/linux/early_times.h
> +/* returns a nanosecond value based on early cycles */
> +static inline u64 early_times_ns(void)
> +{
> + if (CONFIG_EARLY_CYCLES_KHZ)
> + /*
> + * Note: the multiply must precede the division to avoid
> + * truncation and loss of resolution
> + * Don't use fancier MULT/SHIFT math here. Since this is
> + * static, the compiler can optimize the math operations.
> + */
> + return (early_unsafe_cycles() * NS_PER_KHZ) / CONFIG_EARLY_CYCLES_KHZ;
Still, this contains a 64-by-32 division, so let's see how this works
out on 32-bit (RISCV_TIMER is set on rv32!). If the compiler would
generate a function call to a libgcc helper, you will have to switch
to the mul_u64_u32_div() helper...
> + return 0;
> +}
> +#else
> +static inline u64 early_times_ns(void)
> +{
> + return 0;
> +}
> +#endif
> +
> +#endif /* _EARLY_TIMES_H */
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds