Use the --foreground option for timeout in combination with INT signal to dd.
timeout --foreground -s INT 0.1 dd if=/dev/zero of=/dev/null
Documentation for timeout say:
--foreground
when not running timeout directly from a shell prompt,
allow COMMAND to read from the TTY and get TTY signals;
in this mode, children of COMMAND will not be timed out
From what I can see trough traces etc. it looks like this works better for dd. Without --foreground the process get the INT signal but then a CONT to both dd and timeout which rapidly result in the process exiting. In very rare cases dd does get the time to process the INT signal, but that is not the norm.
With --foreground the CONT is never sent and dd get time to print the stats before exiting.
The cleanup function linked above is called on first iteration call to sigsuspend.
dds process_signals() is extremely rarely called after interrupt_signal has been set when CONT is in process for timeout (i.e. --foreground not set).