Add TimerImpl::enableHRTimer - take two#9229
Conversation
93c4522 to
649815b
Compare
This reverts commit a693496. Signed-off-by: Otto van der Schaaf <[email protected]>
- Updates TimerUtils::durationToTimeval to use templating to avoid implicit conversions of durations when passing argument, thereby generating an opportunity to bound the input before doing conversions on it. Throws when passed a negative duration. - Adds some more tests around this - Slightly refactored version modified of: envoyproxy#9155, Signed-off-by: Otto van der Schaaf <[email protected]>
649815b to
6bb6555
Compare
Signed-off-by: Otto van der Schaaf <[email protected]>
Signed-off-by: Otto van der Schaaf <[email protected]>
|
@htuch attempt two at this, hopefully the fuzzer doesn't object this time. This mitigates potential overflow issues, but unfortunately I have not been able to reproduce the issue locally -- even given the provided corpus that teased it out on CI. Is it possible to respin the fuzzer tests in CI a couple of times for this change? |
| * @param tv output parameter that will be updated | ||
| */ | ||
| template <typename Duration> static void durationToTimeval(const Duration& d, timeval& tv) { | ||
| if (d.count() < 0) { |
There was a problem hiding this comment.
Additional thought: one thing that might be worth attempting here, is to typedef the duration args to enableXXXTimer(). E.g.
using TimerDuration = std::chrono::duration<uint64_t, std::milli>;Doing that would void the need for this sanity check here, but would also bloat this PR a lot as call sites would have to be audited / updated.
There was a problem hiding this comment.
Not sure if it is a big win. Perhaps this should be an ASSERT? Or treat negative duration as 0? ASSERT may however slow down fuzzers considerably if they go to negative duration. So probably would an exception here.
Also the comment says negative duration causes ASSERT, not exception. One of the two needs to change.
source/common/event/timer_impl.h
Outdated
| /** | ||
| * Intended for consumption by enable(HR)Timer, this method is templated method to avoid implicit | ||
| * duration conversions for its input arguments. This lets us have an opportunity to check bounds | ||
| * before doing any conversions. When the passed in duration exceeds UINT32_T max days, the output |
There was a problem hiding this comment.
Should this read "INT32_T max seconds"? As per the code?
| throw EnvoyException( | ||
| fmt::format("Negative duration passed to durationToTimeval(): {}", d.count())); | ||
| }; | ||
| constexpr int64_t clip_to = INT32_MAX; // 136.102208 years |
There was a problem hiding this comment.
I certainly think this is more than enough. Out of curiosity though, why 32 bits? I think timeval uses time_t for seconds, which is 64 bit?
|
@yanavlasov thanks for your feedback! I will push an update to make comments consistent shortly. Sharing some thoughts that further motivate some of the changes in here, as well addresses as some of your questions/feedback.
It might be a little paranoid, but I'm hoping that capping the inbound number of seconds to https://en.wikipedia.org/w/index.php?title=Time_t&oldid=450752800 [3] |
Signed-off-by: Otto van der Schaaf <[email protected]>
source/common/event/timer_impl.h
Outdated
| /** | ||
| * Intended for consumption by enable(HR)Timer, this method is templated method to avoid implicit | ||
| * duration conversions for its input arguments. This lets us have an opportunity to check bounds | ||
| * before doing any conversions. When the passed in duration exceeds INT32_T max days, the output |
There was a problem hiding this comment.
Nit: I think this should just say "INT32_MAX seconds", otherwise it is hard to interpret. Same below, the "INT32_MAX days worth of seconds" may be hard to understand.
There was a problem hiding this comment.
Sorry - that was a confusing comment indeed; amended: 0c57cfc
Signed-off-by: Otto van der Schaaf <[email protected]>
Signed-off-by: Otto van der Schaaf <[email protected]>
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
- Updates TimerUtils::durationToTimeval to use templating to avoid implicit conversions of durations when passing argument, thereby generating an opportunity to bound the input before doing conversions on it. Throws when passed a negative duration. - Adds some more tests around this Slightly refactored version of envoyproxy#9155 Risk Level: medium Testing: unit tests Signed-off-by: Otto van der Schaaf <[email protected]> Signed-off-by: Prakhar <[email protected]>
|
Q: in what cases do you require microsecond resolution? Something to keep in mind is that syscalls like epoll_wait which I think we are used by libevent on linux take arguments at millisecond resolution. |
|
@antoniovicente this NH commit introduces using microsecond resolution for scheduling wakeups on the dispatcher in NH. Context: In Nighthawk, when the client has in-flight requests, we can't spin the event loop to poll the clock for determining the time of the next request release, as timers take priority over i/o events. We wouldn't want to block processing of i/o events. So we use sleeps to schedule wakeups instead. Without this change, the smallest unit of time we could use to poll the clock would then be approximately 1ms when there are requests in-flight. There are scenarios where that seems suboptimal; the simplest example I can come up with is that when 2000 qps is requested, we'd probably end up batching two requests every 1 ms, whereas we actually ought to release one every 500 us. With the |
|
There's several other cases where the TimerImpl 0msec timeout behavior has come up. I'm looking into it but it's going slowly. Thanks for the explanation for your use case and problems you have seen. I do think that you may see some desirable behavior when adding a usec timer based on the iteration's time reference and the real clock has advanced past the absolute time that the timer was set to since you do poll for fd events but with an epoll_wait of 0msecs. libevent rounds timeouts up to nearest 1ms when scheduling epoll_wait |
implicit conversions of durations when passing argument, thereby
generating an opportunity to bound the input before doing conversions
on it. Throws when passed a negative duration.
Risk Level: medium
Testing: unit tests