More useful structured concurrency stack traces
Alan Bateman
Alan.Bateman at oracle.com
Tue Jul 9 19:10:36 UTC 2024
Probably best to bring this to loom-dev as there have been some
exploration into but where we decided not to expose any APIs at this time.
-Alan
On 09/07/2024 19:50, Louis Wasserman wrote:
> My understanding of the structured concurrency APIs now in preview is
> that when a subtask is forked, exceptions thrown in that stack trace
> will have stack traces going up to the beginning of that subtask, not
> e.g. up the structured concurrency task tree. (My tests suggest this
> is the case for simple virtual threads without structured
> concurrency.) Most concurrency frameworks on the JVM that I’ve
> encountered share the property that stack traces for exceptions don’t
> trace through the entire causal chain – and, not unrelatedly, that
> developers struggle to debug concurrent applications, especially with
> stack traces from production and not full debuggers attached.
>
> In some cases, like chained CompletableFutures, this seems necessary
> to ensure that executing what amounts to a loop does not result in
> stack traces that grow linearly with the number of chained futures.
> But when structured concurrency is involved, it seems more plausible
> to me that the most useful possible stack traces would go up the tree
> of tasks – that is, whenever a task was forked, the stack trace would
> look roughly as if it were a normal/sequential/direct invocation of
> the task. This could conceivably cause stack overflows where they
> didn’t happen before, but only for code that violates the expectations
> we have around normal sequential code: you can’t recurse unboundedly;
> use iteration instead.
>
> I’m curious if there are ways we could make the upcoming structured
> concurrency APIs give those stack traces all the way up the tree, or
> provide hooks to enable you to do that yourself. Last year’s JVMLS
> talk on Continuations Under the Covers demonstrated how stacks were
> redesigned in ways that frequently and efficiently snapshot the stack
> itself – not just the trace, but the thing that includes all the
> variables in use. There’s a linked list of StackChunks, and all but
> maybe the top of the stack has those elements frozen, etc, and the top
> of the stack gets frozen when the thread is yielded. Without
> certainty about how stack traces are managed in the JVM today, I would
> imagine you could possibly do something similar – you’d add a way to
> cheaply snapshot a reference to the current stack trace that can be
> traversed later. If you’re willing to hold on to all the references
> currently on the stack – which might be acceptable for the structured
> concurrency case in particular, where you might be able to assume
> you’ll return to the parent task and its stack at some point – you
> might be able to do this by simply wrapping the existing StackChunks.
> Then, each `fork` or `StructuredTaskScope` creation might snapshot the
> current call stack, and you’d stitch together the stack traces
> later…somewhere. That part is a little more open ended: would you add
> a new variant of `fillInStackTrace`? Would it only apply to
> exceptions that bubbled up to the task scope? Or would we be adding
> new semantics to what happens when you throw an exception or walk the
> stack in general? The most plausible vision I have at this point is
> an API that spawns a virtual thread which receives a stack trace of
> some sort – or perhaps snapshots the current stack trace – and
> prepends that trace to all stack traces within the virtual thread’s
> execution.
>
> I suppose this is doable today if you’re willing to pay the
> performance cost of explicitly getting the current stack trace every
> time you fork a task or start a scope. That is kind of antithetical
> to the point of virtual threads – making forking tasks very efficient
> – but it’s something you might be willing to turn on during testing.
>
> Right now, my inspiration for this question is attempting to improve
> the stack trace situation with Kotlin coroutines, where Google
> production apps have complained about the difficulty of debugging with
> the current stack traces. But this is something I'd expect to apply
> equally well to all JVM languages: the ability to snapshot and string
> together stack trace causal chains like this in production could
> significantly improve the experience of debugging concurrent code.
>
> --
> Louis Wasserman
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240709/7420ba6e/attachment-0001.htm>
More information about the core-libs-dev
mailing list