Reduced CPU usage - #11
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Performance and correctness fixes across the timer wheel, accept path, and coroutine dispatch.
Changes
perf(timer): replace
std::listbuckets withstd::vector, fix O(n) scan inupdateNextExpiryTimeTimer wheel buckets used
std::list<Timer*>, causing pointer chasing on every tick iteration.Replaced with
std::vector<Timer*>and swap-and-pop removal — O(1), order within a bucket is irrelevant.updateNextExpiryTimewas called after everyadvance()— up to N times per tick, each doing a fullscan of all 1024 buckets. Fixed by maintaining
nextExpiryTime_incrementally inaddTimerToWheeland invalidating it to
0inremoveTimerFromWheel. Full rescan now runs only when the minimum isunknown (after removal or expiry of the minimum timer). Added early return for
elapsed == 0.feat(net): add
async_accept(F, Args...)overload, deprecateasync_accept()The zero-argument
async_accept()accepted one connection per ET wakeup and returned. Inedge-triggered mode (epoll ET / kqueue EV_CLEAR) this silently drops all connections buffered
since the last edge.
New overload drains the accept queue in a tight loop until EAGAIN before suspending — one suspend
per batch of connections instead of one per socket.
Fmay be a plainvoidcallback or acoroutine function; coroutines are automatically spawned via
co_spawn. Extra arguments areforwarded to
Fon each call via variadicArgs....Implemented independently per backend:
AwaiterAcceptonEAGAINaccept4first, fall back toAcceptAwaiterSQEfcntl(O_NONBLOCK|FD_CLOEXEC)AcceptExloop inlined, no recursiveasync_accept()callOld overload preserved with
[[deprecated]]for backwards compatibility.fix(system): correct promise cast in
co_spawn_staticoverloadsTemplate overload cast
promisetoAwaitableFrameBaseby value, slicing the object —set_thread_idwas never called on the original. Fixed withstatic_cast<AwaitableFrameBase*>.Handle overload had a malformed cast on
coroutine_handle<>— erased handles cannot be castdirectly. Fixed by restoring the typed handle via
from_addressbefore accessing the promise.Testing
Profiled under wrk load (
-t8 -c500 -d30s) withperf record -F 999. Flamegraph attached.No regressions in existing sync primitives, channels, or timer tests.