-
Notifications
You must be signed in to change notification settings - Fork 370
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
Support inline callstack symbolication for local Firefox builds #3727
Support inline callstack symbolication for local Firefox builds #3727
Conversation
Codecov Report
@@ Coverage Diff @@
## main #3727 +/- ##
==========================================
+ Coverage 88.70% 88.72% +0.01%
==========================================
Files 263 263
Lines 22100 22129 +29
Branches 5660 5666 +6
==========================================
+ Hits 19604 19634 +30
+ Misses 2313 2312 -1
Partials 183 183
Continue to review full report at Codecov.
|
7694e60
to
586e8d9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, let's move forward with that!
That's a pretty big change in our symbolication code, and this all works fine!
|
||
const responseJson = _ensureIsAPIResultV5(await response.json()); | ||
const responseJson = _ensureIsAPIResultV5( | ||
await callback('/symbolicate/v5', JSON.stringify(body)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should pass body
and let the callback call JSON.stringify
if necessary only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be an option. I don't have an opinion on it. Both callees currently need JSON.stringify
.
); | ||
} | ||
|
||
return querySymbolicationApiViaWebChannel(path, requestJson); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering what Firefox does with the path
later on? I think it passes it along all the way to the wasm program, but I wonder why it's useful?
(probably not for this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's useful so that we can add more APIs without having to add more methods to the WebChannel. I want to add two new APIs: A way to get source code, and a way to get assembly code.
I've already landed a /source/v1
API in profiler-get-symbols (but not integrated it into Firefox yet): mstange/profiler-get-symbols#24
// No symbols for this library, it'll need to try the next option. | ||
const { request, error } = response; | ||
failedRequests.push(request); | ||
(errorMap.get(request) ?? []).push(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that working? If the request
isn't in errorMap
yet, how does it get there?
(same remark for the same line below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, maybe I should add a comment. request
is guaranteed to be in the errorMap
- we initialize errorMap
with all requests. The ?? []
is just there because it's the shortest way I could think of to appease Flow. In Rust I would use .unwrap()
here to say "I'm sure that this exists and I'm willing to risk a panic if my reasoning about this code is wrong". In JS I could throw an exception, but that would be three extra lines.
Or maybe I should use ensureExists
from the flow helpers? But that one takes an error message...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added two comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe I should use ensureExists from the flow helpers? But that one takes an error message...
The error message isn't mandatory, the tool adds a default one if it's missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that would have been my preference :-)
// Some libraries are still remaining, try option 3 for them. | ||
// Option 3 is symbolProvider.requestSymbolsFromBrowser. | ||
const option3ResponsePromise = | ||
this._symbolProvider.requestSymbolsFromBrowser(option3Requests); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the functions requestSymbolsFromBrowser
vs requestSymbolTableFromBrowser
are very close, do you have an idea to make them more descriptive? Maybe requestSymbolsFromWebChannel
vs requestSymbolTableFromFrameScript
? But for Android we're not using the framescript, are we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the names are quite close indeed. I'm hoping we can remove the "symbol table" variants once we've converted Android (i.e. fixed bug 1735897).
As for the WebChannel / frame script distinction vs requestSymbols / requestSymbolTable, the relationship is as follows:
SymbolStore --> requestSymbolsFromBrowser --> WebChannel querySymbolicationApi (if available)
|
`-------> requestSymbolTableFromBrowser --> WebChannel getSymbolTable (if available)
|
`-----> otherwise frame script getSymbolTable
requests: LibSymbolicationRequest[], | ||
symbolsUrl: string | ||
callback: (path: string, requestJson: string) => Promise<MixedObject> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the name callback
isn't descriptive enough, what do you think of renaming it symbolFetcherCallback
or something similar?
Also please describe it a bit in the comment above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestions, will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've renamed this to querySymbolicationApiCallback
and also created a type QuerySymbolicationApiCallback
for it.
The errors created here are later accumulated into one big SymbolsNotFoundError, once all options have failed. At that point we also still know the lib. There is no need to embed the lib into the error here, too. We have an instanceof SymbolsNotFoundError check, but that check only ever sees the combined error. It doesn't look at the individual input errors. So this doesn't change any behavior.
It now receives a callback so that it supports both doing a fetch request to a server and sending the request elsewhere, for example to the browser.
This calls through into BrowserConnection.querySymbolicationApi. The request and response JSON are processed by MozillaSymbolicationAPI.
We insert this as the new option 3, before getting symbol tables (which is now option 4). This gives us rich symbol information with file + line + inline data. We keep option 4 for old Firefox versions and for Android system libraries.
586e8d9
to
2fd7f3b
Compare
This PR makes it so that we will get inline callstacks when profiling local Firefox builds. It hooks up symbolication to the new
querySymbolicationApi
entry point from the WebChannel.Example profile: https://share.firefox.dev/31CAqLf
Fixes #1516.