drivers: timer: native_sim_timer: keep the model ticking at the tick period - #116977
drivers: timer: native_sim_timer: keep the model ticking at the tick period#116977kartben wants to merge 1 commit into
Conversation
…period hwtimer_enable() sets the period the timer model free-runs at, so arming the next announce with it stretched that period out to the whole span and let the model reach the deadline in a single step. The model paces simulated time against real time once per tick expiry, so one step of the whole span leaves nothing to pace it. Under CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME an idle with no timeout arms 0x7fffffff ticks, simulated time leaves the wall clock ~248 days behind in one go, and the model then tries to sleep off the difference. Simulated time is no longer related to real time and anything sharing the simulation with a real-world peer stalls: CI hit this on the native offloaded sockets tests that talk to a host TLS server (net.sockets.tls12.ec_kex, net.sockets.tls12.psk_kex and sample.net.sockets.http_get.nsos.https all hung in connect()). Arm through hwtimer_set_silent_ticks() instead, as the driver did before the conversion: the period stays at one tick, the model keeps stepping -- and pacing -- a tick at a time, and the ticks up to the deadline are passed over without raising an interrupt. hwtimer_enable() goes back to the single call at init that sets that period. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org> Assisted-by: Claude:opus-5
50aa11e to
ff5811d
Compare
npitre
left a comment
There was a problem hiding this comment.
My regression, thanks for chasing it down.
Two things to fold in.
cycles / NP_TICK_PERIOD_US wants to be DIV_ROUND_UP(cycles, NP_TICK_PERIOD_US). When an arm lands off the model's tick grid the floor drops
a whole tick, so the interrupt comes a tick early and the kernel re-arms: two
interrupts per timeout instead of one. Measured on native_sim/native/64, 40
iterations of k_busy_wait(3333) plus k_msleep(50), counting entries to
np_timer_isr():
| ISRs per sleep | elapsed | |
|---|---|---|
| before 0342c93 | 1.00 | 2400 ms |
| this PR | 2.00 | 2400 ms |
this PR + DIV_ROUND_UP |
1.00 | 2400 ms |
Same elapsed either way, so rounding up does not fire late. A plain k_msleep()
loop shows 1.00 in all three, since with the CPU consuming no simulated time
every arm lands on the grid; it takes another event to knock them off, which the
offloaded-socket tests have no shortage of.
Separately, the BUILD_ASSERT does not compile with
CONFIG_SYSTEM_CLOCK_HW_CYCLES_PER_SEC_RUNTIME_UPDATE=y:
drivers/timer/native_sim_timer.c:62:32: error: expression in static assertion is not constant
Same class as #116777. Nothing in tree sets it on native_sim, but skipping the
assert would not be enough: if it were set, NP_TICK_PERIOD_US would diverge
from the runtime rate and the silent-tick arithmetic would be quietly wrong. A
simulated microsecond cannot be re-rated, so I would #error on the option.
|
Thanks for attempting a fix. |
Fixes the twister regression on
mainseen in https://github.com/zephyrproject-rtos/zephyr/actions/runs/32385137294.Root cause
0342c93 ("drivers: timer: native_sim_timer: use the generic timer core") arms the next announce with
hwtimer_enable(cycles).hwtimer_enable()sets the period the timer model free-runs at, so arming stretches the tick period out to the whole span and the model reaches the deadline in a single step.The model paces simulated time against real time once per tick expiry, so a single step of the whole span leaves nothing to pace it. Under
CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME(the default whenever!CONFIG_TEST, which covers both failing test directories) an idle with no timeout arms0x7fffffffticks, simulated time leaves the wall clock ~248 days behind in one go, and the model then tries to sleep off the difference.Simulated time on
samples/hello_world,native_sim/native/64, after N seconds of wall clock:Only tests sharing the simulation with a real-world peer notice, which is why the native offloaded sockets talking to a host
openssl s_server/google.comare the ones that broke. A small NSOS round-trip app against a local echo server reportsTest PASSEDat simulated00:00:00.180before the conversion and with this PR, versus00:17:31.026on currentmain.The fix
Arm through
hwtimer_set_silent_ticks(), as the driver did before the conversion: the period stays at one tick, the model keeps stepping -- and pacing -- a tick at a time, and the ticks up to the deadline are passed over without raising an interrupt.hwtimer_enable()goes back to the single call at init that sets that period. The conversion to the generic timer core itself is kept.Skipping ticks lands on the model's own tick grid rather than exactly
cyclesfrom now, so the interrupt can come up to a tick early; the core announces what actually elapsed and the kernel re-arms, so that costs one extra announce and nothing else.A straight revert of 0342c93 might be a lower-risk alternative.