Conversation
b30b4ac to
40cc2a5
Compare
|
Sorry for doing an oopsie on your PR history. Regarding loop {
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| self.coroutine.force_unwind()));
if res.is_ok() {
break;
}
}Seems to work. A few notes:
|
|
Okay nevermind on the loop, as per Amanieu/corosensei#57 only the first call matters |
a0e2074 to
40cc2a5
Compare
40cc2a5 to
e55ee58
Compare
| Ready, // has a suspended function in its cell; waiting for input about what to do next | ||
| Running, // currently inside a user-provided function | ||
| FinishedIteration, // has finished the previous function, can be initialized with a new one | ||
| Exited, // the internal coroutine has exited its loop and cannot receive new functions to execute |
There was a problem hiding this comment.
Why do we need FinishedIteration and Exited?
There was a problem hiding this comment.
FinishedIteration is similar to NotReady, except that it has an old function in its cell, instead of no function at all.
Exited indicates that the coroutine has exited the inner loop and cannot be reused or resumed.
I think the new states make the state-machine easier to understand, even if they aren't strictly necessary (obviously they aren't because we got away with only three states before).
| pub fn new() -> Self { | ||
| Self { | ||
| stack_size: 0x8000, | ||
| stack_size: 0xf000, |
There was a problem hiding this comment.
In my testing the corosensei coroutines were running out of stack space occasionally. I guess there is some slight constant memory usage overhead as compared to generators
There was a problem hiding this comment.
per the comment on the longer benchmarking time with backtraces, this is probably because corosensei produces deeper callstacks than generators
| } | ||
|
|
||
| impl Drop for ContinuationPool { | ||
| fn drop(&mut self) { |
There was a problem hiding this comment.
Why is is fine to remove this?
There was a problem hiding this comment.
This "cheat" was necessary because of an internal implementation detail of the Generators library. As far as I can see corosensei does not internally use ThreadLocals in the same way. I think the "cheat" is a bit difficult to reason about (overloading a state, messing with drop behavior) and so if it is not necessary I believe it should be removed.
|
Benchmarks take a gigantuan amount of time. Not uncommon for them to take long, but they shouldn't time out? |
I reran the CI job last night with #213 and it finished successfully in 30m: Corosensei is faster across the board. Must be that capturing a backtrace from corosensei is more expensive (deeper stack) |
|
Could you rebase so that benchmarks get run (I merged the backtrace fix) |
This PR switches Shuttle continuations to use corosensei rather than the generators library. In the context-switch heavy micro-benchmarks (for example,
shuttle/benches/counter.rswith theRandomScheduler), this results in 5-20% faster scheduling throughput because of reduced context-switching overhead.Major points for discussion:
There is an API change with
corosenseiwhere we now need to pass an explicityielderin order to suspend a coroutine. Because the continuations are kept in a pool and reused, this requires us to exfiltrate the yielder from the closure passed in toCoroutine::with_stackand persist it for the lifetime of the Continuation. Currently, the yielder is carried around as a raw pointer on the Task struct, but I suspect there might be a nicer way to do this. Unfortunately, naively embedding it in the Continuation struct is not possible because the Continuation is already borrowed by itsresumemethod whenswitchis called.There is an issue where
corosenseiexpects to catch a ForcedUnwind when dropping coroutines. Something in the way Shuttle handles panics is intercepting the ForcedUnwind and not propagating it up to where corosensei expects it, causing it to panic. This only arises on an initial panic, or during cleanup if some Tasks are detached. The current solution is to callforce_resetinstead offorce_unwindin these cases, which does not attempt to unwind the coroutine, but therefore may leak resources allocated on the coroutine. In these two scenarios, we probably don't care about leaking resources, because the whole test is about to exit. UPDATE this is fixed inforce_unwindandpanic!"the ForcedUnwind panic was caught and not rethrown"Amanieu/corosensei#57.TODOS before this is ready for merging:
refactor ContinuationState enum to contain the coroutine function itself-- I'd like to move this refactor to a future PR so that we can land this PR sooner rather than laterBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.