-
Notifications
You must be signed in to change notification settings - Fork 232
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 hermes-specific support for the trace event format #458
Add hermes-specific support for the trace event format #458
Conversation
@@ -48,12 +48,30 @@ interface TraceEvent { | |||
cat?: string | |||
|
|||
// Any arguments provided for the event. Some of the event types have required argument fields, otherwise, you can put any information you wish in here. The arguments are displayed in Trace Viewer when you view an event in the analysis section. | |||
args: any | |||
args?: any |
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.
Based on the spec this is not a required field for some event types, so marked it as optional. Happy to change back if this was intentional
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.
Seems fine
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.
Cool! High level looks good. A few minor requests inline, and then more generally please change all of the isHermesProfile
arguments to be enum args instead of an ExporterSource
with current values of UNKNOWN
or HERMES
. That way this will extend well if we want to specialize for other trace events types in the future, and also makes call-sites more self-documenting
src/import/trace-event.ts
Outdated
@@ -669,6 +739,8 @@ export function importTraceEvents(rawProfile: Trace): ProfileGroup { | |||
return sampleListToProfileGroup(rawProfile) | |||
} else if (isTraceEventObject(rawProfile)) { | |||
return eventListToProfileGroup(rawProfile.traceEvents) | |||
} else if (isHermesTraceEventList(rawProfile)) { | |||
return eventListToProfileGroup(rawProfile, true) |
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.
As much as possible, I like to use enums rather than bare boolean arguments because it makes it clearer what's going on at the call-site. The true
here isn't self documenting, but if this was e.g. return eventListToProfileGroup(rawProfile, ExportSource.HERMES)
it would be really clear
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.
makes sense - generally I just make any function that takes in more than one obvious parameter take in an object so the meaning of every param is clear at the callsite, but I saw that it isn't a pattern in the codebase. Using an enum is super readable, will do that
src/import/trace-event.ts
Outdated
function isHermesTraceEventList(maybeEventList: any): maybeEventList is HermesTraceEvent[] { | ||
if (!isTraceEventList(maybeEventList)) return false | ||
|
||
return maybeEventList.every(el => isHermesTraceEvent(el.args)) |
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.
For the sake of hermes profile import speed, it's IMO fine to just check the first event. Otherwise this seems like it might be needlessly slow.
src/import/trace-event.ts
Outdated
const requiredProperties: Array<keyof HermesTraceEventArgs> = [ | ||
'line', | ||
'column', | ||
'name', | ||
'category', | ||
'url', | ||
'params', | ||
'allocatedCategory', | ||
'allocatedName', | ||
] |
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.
Browsers probably optimize this anyway, but just for sanity, let's move this array outside of the call-stack. This seems like it would fit well as a constant directly below HermesTraceEventArgs
as heremesTraceEventRequiredProperties
@jlfwong thanks for the feedback, pushed up some fixes! |
// We just check the first element to avoid iterating over all trace events, | ||
// and asumme that if the first one is formatted like a hermes profile then | ||
// all events will be | ||
return isHermesTraceEvent(maybeEventList[0].args) |
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.
[0]?.args
please!
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.
Nevermind, this is guarded in isTraceEventList
Amazing! If you write a markdown description (just in a comment here is fine) for React Native profiling, then I'll copy that into the wiki and update the README to link to it to indicate there's specific support for React Native via Hermes. Here's an example of such a page: https://github.com/jlfwong/speedscope/wiki/Importing-from-pprof-(go) |
Importing from HermesHermes is a javascript engine developed by facebook for use in react-native applications. For the most up-to-date instructions on how to take a profile, see Profiling with Hermes. Profiling in Development ModeTo record a sampling profiler from the Dev Menu:
A toast will show the location where the sampling profiler has been saved, usually in You can then extract the profile from your emulator / device using the following command:
To view, drag and drop the profile from destinationDir into Speedscope. Profiling in Release ModeTo profile hermes in a release build of your app, you can use the react-native-release-profiler npm package:
import { startProfiling } from 'react-native-release-profiler'
startProfiling()
import { stopProfiling } from 'react-native-release-profiler'
// `true` to save the trace to the phone's downloads folder, `false` otherwise
const path = await stopProfiling(true)
First find your app id. It should look something like
Then run:
To view, drag and drop the profile saved in your current working directory into Spedscope. It should be transformed with sourcemaps! |
@jlfwong took a pass at some docs ^. Profiling in release mode is something that Margelo recently worked one while contracting for my company, so honestly these are probably the most up-to-date / complete docs that exist anywhere right now. |
@zacharyfmarion Great! Added to the wiki, and updated the README. Whenever you'd like to do an awareness push on Twitter or LinkedIn or wherever, let me know and I'll help signal boost. |
Profiles that are transformed into the hermes trace event format are guaranteed to have specific arguments that supply metadata that is useful for debugging - namely the filename, line + col number that the function call originated from, with sourcemaps applied. This PR adds specific support for this information to the trace event importer. This means that we can have the Frame name be just the name of the function, since we know all the information we want to be displayed in the UI is captured in the frame info, which makes the traces cleaner to look at.