fix(up): stop pinning a CPU core during foreground wait#82
Open
Cyb3rDudu wants to merge 2 commits intoMcrich23:mainfrom
Open
fix(up): stop pinning a CPU core during foreground wait#82Cyb3rDudu wants to merge 2 commits intoMcrich23:mainfrom
Cyb3rDudu wants to merge 2 commits intoMcrich23:mainfrom
Conversation
`waitForever()` used `for await _ in AsyncStream<Void>(unfolding: {})`,
but `AsyncStream<Void>(unfolding: () async -> Void?)` ends only when the
closure returns `nil`. An empty closure returns `()`, which Swift
auto-wraps as `.some(())` — never `nil` — so the stream emits an
infinite sequence of `Void` values with no `await` between them. The
for-loop spins as fast as the runtime can iterate, holding 100% of one
core until the user kills the process.
Replace with `withUnsafeContinuation { _ in }` — the task suspends
indefinitely with zero CPU.
Fixes Mcrich23#27.
Open
Spawns a detached Task running `waitForever()`, sleeps 200 ms wall-clock, and compares user-CPU consumed via `getrusage(RUSAGE_SELF)` before/after. On the bug, the child task pins one core and the test sees ~200,000 µs of user CPU (one core fully used). With the fix, consumption is negligible. Threshold of 50,000 µs gives ~4x headroom for noisy CI baselines. Verified the test fails on the previous behavior: 209,086 µs consumed.
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.
container-compose up(foreground) holds 100% of one core after all containers have started. Reproducible with any compose file run without-d:The hot loop is
ComposeUp.swift::waitForever:AsyncStream<Void>(unfolding: () async -> Void?)ends only when the closure returnsnil. The empty closure returns(), which Swift auto-wraps as.some(())— nevernil— so the stream emits an infinite sequence ofVoidvalues with noawaitbetween them. The for-loop iterates as fast as the runtime can deliver them. The// This will never runcomment is inverted: the body runs constantly; onlyfatalError("unreachable")is unreachable.Fix is
withUnsafeContinuation { _ in }: the task suspends until the process is killed, with zero CPU. After this change the same repro shows0.0 container-compose.Used
withUnsafeContinuationrather thanwithCheckedContinuationbecause the latter logs a "continuation leaked" diagnostic at runtime — leaking is the intent here, since the contract is to wait until the process is killed.Fixes #27.