Missing interpreter frames in profiles of resumed async functions (interpreter and baseline interpreter)
Categories
(Core :: JavaScript Engine, defect, P2)
Tracking
()
People
(Reporter: mstange, Unassigned)
References
(Blocks 1 open bug)
Details
(Whiteboard: [sp3])
Attachments
(1 file, 1 obsolete file)
583 bytes,
text/html
|
Details |
For profiling with native profilers such as samply or perf, Spidermonkey supports entering "stub" functions for the C++ interpreter and the Baseline interpreter. However, it seems that when resuming an async functions, we sometimes don't enter these stubs.
Example profile: https://share.firefox.dev/3UfMbPV
This makes it hard to account the correct sample count to these async functions. It also makes it hard to get an accurate sense of the async/await overhead tracked in bug 1924185.
Comment 1•8 months ago
|
||
Markus, can you name which frames we are supposed to look at in the flame graph?
Updated•8 months ago
|
Reporter | ||
Comment 2•8 months ago
|
||
The callees of the Baseline: AsyncFunctionNext
frame are the frames that are missing JS function names.
I'll try to get a reduced testcase.
Reporter | ||
Updated•8 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Reporter | ||
Comment 3•2 months ago
|
||
samply profile of this testcase: https://share.firefox.dev/428alAq
The profile is missing the frame for myAsyncFunction()
. It's unclear from the profile what is calling foo()
and bar()
.
This profile was collected with samply record -r 4000 PERF_SPEW_DIR=. IONPERF=func MOZ_DISABLE_CONTENT_SANDBOX=1 JIT_OPTION_enableICFramePointers=true JIT_OPTION_onlyInlineSelfHosted=true JIT_OPTION_emitInterpreterEntryTrampoline=true python3 ./mach run
on macOS.
Reporter | ||
Comment 4•2 months ago
|
||
Actually the previous testcase wasn't good because it was calling foo() and bar() with await.
Here's a testcase with regular calls from myAsyncFunction()
to foo()
and to bar()
. There's no interpreter trampoline frame for myAsyncFunction()
in the profile: https://share.firefox.dev/3RGLBsL
Comment 5•2 months ago
|
||
I took a quick look at this. It's a non-trivial fix.
To resume a generator / async function, we call into self-hosted code (GeneratorNext for generators, AsyncFunctionNext for async functions). Those functions contain a call to the resumeGenerator
intrinsic, which the parser turns into JSOp::Resume. The effect of JSOp::Resume is to set up the stack frame for the function being resumed, and then jump to the right place in the code. This plays out in different ways depending on the tier of the result, but the key fact for every tier is that we never actually call the resumed function. We always set up a fake stack frame manually. This means that we can't reuse our existing interpreter entry trampolines, which call the wrapped function.
Instead, we would have to generate a second set of resume trampolines, or at least add an additional path in the trampoline for async functions / generators that would resume the function instead of calling it. Then we could make the resume code call into those trampolines.
Description
•