Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debugging hooks for futures #6

Open
aturon opened this Issue Apr 18, 2018 · 7 comments

Comments

Projects
None yet
5 participants
@aturon
Copy link
Contributor

aturon commented Apr 18, 2018

Make it possible to debug deadlocks/lost wakeups by examining the graph of tasks and what they believe they're blocked on.

@aturon aturon added the futures label Apr 18, 2018

@aturon

This comment has been minimized.

Copy link
Contributor Author

aturon commented Apr 18, 2018

@cramertj can you sketch out the ideas from the All Hands?

@aturon aturon referenced this issue Apr 18, 2018

Closed

Tracking issue: futures 0.3 #1

1 of 7 tasks complete
@cramertj

This comment has been minimized.

Copy link
Collaborator

cramertj commented Apr 18, 2018

There's been some back and forth about the best way forward, but the original idea was to have a linked list of contextually relevant Debug types included in task::Context:

use std::fmt::Debug;

enum DebugList<'a> {
    Nil,
    Cons(&'a Debug, &'a DebugList<'a>),
}

task::Context would then include a with_debug function that borrowed from a task::Context and produced a new task::Context with one more element in the DebugList. Then, rather than having Clone as a supertrait of Waker, we'd add Waker::clone which took a DebugList so that Waker implementations could record the context of the task that is to be awoken by that Waker. The purpose of providing the debug information directly in the clone method (rather than a separate method) is to ensure that no wakeup is created without the appropriate debug info-- if the information is only provided sometimes, it's dramatically less useful for debugging wakeups that should exist, but don't.

There's also been talk of doing this outside of task::Context using a thread local and having Waker implementations pull from that, though that seems to me like it has more potential for negative performance impact.

@jsgf

This comment has been minimized.

Copy link

jsgf commented Jul 24, 2018

There's a few things I'd like to see:

  • A way to inspect the internal states of Future state machines
  • A way to inspect the dependency graph between them
  • A way to get events as states change within the context of the dependency graph

And just because this is pure wishlist:

  • This composes across crates with different origins
  • Can be as similarly simple to implement as a #[derive()], but allows for more complex impls
  • Cheap enough to always compile in, and can be dynamically enabled/disabled at runtime

We've (mostly @kulshrax) done some prototyping in house, and are mostly at the level of a tracing combinator approach, which is OK but it's limited in scope. I'd like to maintain dependency info, but the lack of a suitable context to hang it off has been hampering that effort (per-thread isn't suitable and per-task doesn't really work). The addition of an explicit context param to poll() makes that easier, which I guess is pretty close to what @cramertj is proposing.

@jsgf

This comment has been minimized.

Copy link

jsgf commented Jul 26, 2018

Oh, another thing that's pretty painful - some standard way to capture panics so they don't get lost. At the moment they just evaporate.

@sfackler

This comment has been minimized.

Copy link

sfackler commented Jul 26, 2018

@jsgf I think https://doc.rust-lang.org/std/panic/fn.set_hook.html may be what you're looking for there?

@jsgf

This comment has been minimized.

Copy link

jsgf commented Jul 27, 2018

@sfackler As a last resort, but its a bit global. I was thinking of something more per-executor.

@aidanhs

This comment has been minimized.

Copy link

aidanhs commented Jul 27, 2018

One thing that I believe was mentioned (I think, trying to dredge my memory) at all hands was that could store your debuglist data by using a combinator, e.g. f1.debuginfo("foo").and_then(|_| f2.debuginfo(Bar { ... })).

This is pretty paged-out though and my recollection of the planned design of futures is hazy, so I may be misrepresenting the idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.