-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
k_sleep duration is off by 1 tick #32499
Comments
k_ticks_t ticks = timeout.ticks + 1; This may be because of the following: If you have, say, a 1kHz clock. And you wait for 1 tick to pass by immediately before a tick. This will wait ~0ms, plus RTOS overhead. Or rather: Without With Generally (not always), it's better to wait too long than too short. (And with RTOS overhead there's no guarantee that you won't oversleep anyways.) |
This looks correct. The documented behavior of a relative timeout is that it sleeps for at least that long. So in your relative example you wait for tick alignment, sleep for four ticks, and then receive your interrupt at the next tick that arrives after that, which is five ticks after the tick that arrived immediately before the sleep call. We can't wake you up in exactly four ticks without either:
The absolute case gets this right, though. If you call k_uptime_ticks() immediately after that sleep returns, you should find that it produces exactly the uptime you asked for. In fact the ability to reason about questions like this more precisely (without worrying about things like aligned tick interrupts or round-up padding) is precisely why absolute timeouts were introduced to the API. |
I understand the relative timeout case. But in my test with the absolute timeout the system wakes up 1 tick BEFORE the specified time ( I think the problem is that at the point where the +1 happens the absolute timeout is still in its negative representation, thus shortening the timeout. I think what you want is actually this: k_ticks_t ticks = timeout.ticks;
if (IS_ENABLED(CONFIG_TIMEOUT_64BIT) && Z_TICK_ABS(ticks) >= 0) {
ticks = Z_TICK_ABS(ticks) - (curr_tick + elapsed());
} else {
ticks++;
} With this the absolute case wakes up at the precise tick, and the relative case still adds an extra tick. |
Ah, OK. Indeed, I buy that, the early addition is clearly wrong. Do you want to submit or should I? Ideally we want to add a test case that exhibits the early wakeup too. |
Feel free to submit this. There is actually a second related issue: The computation of the expected timeout in |
The computation was using the already-adjusted input value that assumed relative timeouts and not the actual argument the user passed. Absolute timeouts were consistently waking up one tick early. Fixes zephyrproject-rtos#32499 Signed-off-by: Andy Ross <[email protected]>
Fix up at #32505 Please open a second bug against sleep, this one is going to get closed automatically when that merges. |
See #32506. |
I had the pleasure of writing my own timer driver and in the process I got another look at this issue. If I am not wrong, there is still a window of opportunity where absolute timeouts can be off by one tick even after this fix. It is pretty unlikely and it would be hard to actually observe this.
Item 1 can be fixed (probably) with this modification: k_ticks_t ticks = timeout.ticks;
if (IS_ENABLED(CONFIG_TIMEOUT_64BIT) && Z_TICK_ABS(ticks) >= 0) {
ticks = MAX(1, Z_TICK_ABS(ticks) - curr_tick);
} else {
ticks += elapsed() + 1; /* MAX not required because ticks >= 0 before this */
}
__ASSERT(!sys_dnode_is_linked(&to->node), "");
to->fn = fn;
LOCKED(&timeout_lock) {
struct _timeout *t;
to->dticks = ticks; Item 2: I don't see an easy fix for this. Maybe the timer driver in |
I did some tests for a project that required precise timing and I noticed that k_sleep sleeps one tick too long when using a relative timeout, and one tick too short when using an absolute timeout.
Test code:
Observed behavior:
Looking at the debug pin with a scope confirms this and I see a 520us pulse in case 1, and a 320us pulse in case 2.
The problem seems to come from the following line in
z_add_timeout()
:My setup is a efm32gg_stk3701a board (Cortex-M4) with 10kHz ticks, 50MHz clock, no time slicing, 64-bit timeouts enabled.
The text was updated successfully, but these errors were encountered: