Interpreting lambda-rich stack frames

Lambda functions don’t have pretty names. That’s merely an annoyance when debugging a crash. But when profiling, it’s a serious handicap. And when profiling futures-driven code, it’s crippling. I’m trying to profile a Tokio-based application, but almost every single frame of every single stack has a generic name like _<futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::h8e23f80c3f62ba61. The flame graph is completely incomprehensible. Using RUSTFLAGS="-C debuginfo=2 -C inline-threshold=0 doesn’t help.

AFAICT, the root cause seems to be that methods like Future::and_then<F, B>(self, f: F) are generic in the f argument. And since the f argument is usually a lambda function, that means that Future::and_then gets monomorphized every place that it’s called. And since f has only one caller, it gets inlined. And since f's caller is technically in the futures crate, its stack frames get those useless names.

Has anybody found a solution to this problem? I feel like it’s the real Achilles’ heel of futures programming.

Does your tool support showing filenames & lines for functions? Those will usually show where in your code the closure is. That of course still doesn’t always show you the right types. I think the only real solution here would be something like https://github.com/rust-lang/rfcs/pull/2603

Have you compared it to code with async/await? Perhaps that code will look better compiled.

@kornel I haven’t tried async/await. Right now its limitations are too strict for my application. I might code up an example, though.

@jethrogb filenames and line numbers don’t help. I can actually see those if I copy/paste into rust-gdb. However, they always show up in the map or and_then method of the futures crate. I think that’s because my closures get inlined into those methods. The mangling V2 RFC you linked to might help, though. It looks like it could give closures more comprehensible names.