You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rmw_wait rounds its timeout to whole milliseconds: 1 kHz timers skip periods and short waits time out early #82
Yes — it works with another RMW, so the bug looks specific to rmw_unix_socket_cpp
QoS profile (if applicable):
No response
'ros2 doctor --report' output
No response
Steps to reproduce issue
Run a node with a 1 kHz timer (create_wall_timer(1ms)) that counts its callbacks for 30 s, with RMW_IMPLEMENTATION=rmw_unix_socket_cpp.
Or call rmw_wait directly on a guard condition that is never triggered, with a 0.3 ms and then a 1.7 ms timeout, and time each call.
Expected behavior
About 30 000 timer callbacks in 30 s, as with Fast DDS, Cyclone DDS and Zenoh (29 998 to 30 001).
rmw_wait returns RMW_RET_TIMEOUT no earlier than the timeout, and shortly after it.
Actual behavior
28 174 of 30 000 callbacks: about 6 % of the periods are skipped (29 622 with SCHED_FIFO).
A 0.3 ms wait takes about 1.06 ms.
A 1.7 ms wait returns RMW_RET_TIMEOUT after about 1.06 ms, before its deadline (20 of 20 tries).
Knock-on effects: a 1 kHz request/reply loop between two processes loses 2–7 % of its replies, and the iRobot cli_srv 10 B benchmark completes only 35 310 of 40 000 calls in 20 s.
Additional information
Cause:src/rmw_wait.cpp converts the timeout to whole milliseconds for epoll_wait, in three places:
the caller's timeout is truncated (nsec / 1000000), and anything under 1 ms becomes 1 ms ("At least 1ms");
the deadline is computed from that rounded value, which is why a 1.7 ms wait ends after 1 ms;
each time the wait re-blocks, the remaining time is rounded up to the next millisecond.
rclcpp passes the time until the next timer with nanosecond resolution, so a 1 kHz timer almost always asks for less than 1 ms and wakes up late.
PR #8 changed this code for infinite timeouts and kept the <1ms → 1ms rounding on purpose. This issue is about that rounding.
Proposed fix: keep the timeout in nanoseconds and block with epoll_pwait2() (Linux 5.11, glibc 2.35). Where it isn't available (older glibc, ENOSYS, or EPERM from a seccomp profile), fall back to epoll_wait() with the remaining time rounded up.
Activity