-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
Fix hermes profiler #34129
Fix hermes profiler #34129
Conversation
Base commit: 22a067b |
Base commit: 303aaf8 |
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 for sending this over @janicduplessis 👌 I'd like to get a pass from @neildhar @jpporto
resp->id = req.id; | ||
|
||
inspector_ | ||
->executeIfEnabled( |
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.
executeIfEnabled() ensures that the JS VM is not running when making calls to it -- it therefore serializes accesses to the VM. I am not sure it is safe to make this change. @neildhar, any thoughts?
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 think in this case we want it to run if the js vm is running since this command gets called periodically by devtools to get the current memory usage.
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 had a quick look and it seems fine to call from any thread since this info comes from the GC and uses a lock.
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.
getHeapUsage() is only synchronized with the GC, not with the VM execution. Therefore it is not safe to be invoked with the VM running. You could use onPause/onResume to determine whether to invoke getHeapUsage(), or whether return a cached value.
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 think it would be nice to be able to run getHeapUsage while the VM is running, it is used to display realtime memory usage in chrome devtools, so requiring that the VM is paused kind of defeats the purpose of this.
Is there any info coming from the VM that needs synchronization? Also can anything bad happen if we execute this on a running VM, except from potential wrong values, which I think is fine in this case.
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 could also just disable this for now if we're not comfortable landing this change. This feature is not very important compared to be able to profile.
@@ -221,6 +221,12 @@ std::unique_ptr<JSExecutor> HermesExecutorFactory::createJSExecutor( | |||
decoratedRuntime, delegate, jsQueue, timeoutInvoker_, runtimeInstaller_); | |||
} | |||
|
|||
::hermes::vm::RuntimeConfig HermesExecutorFactory::defaultRuntimeConfig() { | |||
return ::hermes::vm::RuntimeConfig::Builder() | |||
.withEnableSampleProfiling(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.
This enables the sampling profiler for all RN users by default. I don't know RN enough, but how is the HermesExecutorFactory create? You need to pipe the options to that call, and not set it here by default...
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, this would enable it by default, which I think is reasonable. Do you know if there’s any overhead in enabling it? Should we do it only for debug builds?
It would still be possible to change by passing a hermes config when creating the HermesExecutorFactory. This is done in the user’s AppDelegate.mm for iOS (https://github.com/facebook/react-native/blob/main/packages/rn-tester/RNTester/AppDelegate.mm#L195) and Android also supports passing in a JavaScriptExecutor factory (
react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
Line 87 in b6f7689
public ReactInstanceManagerBuilder setJavaScriptExecutorFactory( |
react-native/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp
Line 50 in 1bf84a6
.withEnableSampleProfiling(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.
The problem is that the profiler machinery is thread-affined. To be honest we tried to change this several times but we couldn't find a solution :(
I understand your frustration -- we REALLY want to enable usage of the sampling profiler more broadly, but enabling it by default for all users could lead to usability issues -- incorrect stacks, runtime crashes etc.
I think at this point I'll defer to the RN folks on what they want to do. @cortinico?
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.
Would it be possible to enable the profiler only when devtools are connected? I know chrome devtools send Profiler.enable event when connected. Can registerForProfiling
/ unregisterForProfiling
be called on a running VM?
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.
registerForProfiling/unregisterForProfiling must be invoked in the thread running JS (i.e., the "VM" thread), so the VM will be stopped by necessity.
Is there a way to enable this for iOS in a similar manner than it is currently done for Android?
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.
With that being said, someone from RN should have the final say here as to how they want this done. @cortinico
I think I'm sadly not the right person to make this call.
I understand your frustration -- we REALLY want to enable usage of the sampling profiler more broadly, but enabling it by default for all users could lead to usability issues -- incorrect stacks, runtime crashes etc.
My 2 cents here, I won't enable sampling profiler for all the users, but I'll wrap it around a boolean guard that users can control. I understand the value of this, but I think the set of people that will actually use a sampling profiler are a niche.
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.
From what I can tell, the sampling profiler has been enabled for all users before, and still is for android. It is no longer enabled by default since a recent change in hermes.
I haven't tried to see if it works, but would a better solution be to enable profiler when devtools connect?
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 current sampling profiler API requires (un)registerForProfiling() to be called from the thread running the VM, so running it from the inspector thread is wrong.
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 imagine it would be possible to run that code on the JS VM thread, not sure if some other methods already do that.
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.
What's the consensus here. I would like to drive this forward and try to merge it. @jpporto I believe this is fine on RN's end. Are we fine merging it?
@philIip has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
I had a discussion with @jpporto. This is safe to land. We're a bit afraid this might lead to crashes internally due to how we call |
Sounds good, I’m fine with exploring other solutions, or trying to enable it only for open source if it causes an issue internally. |
@philIip has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
This pull request was successfully merged by @janicduplessis in 81564c1. When will my fix make it into a release? | Upcoming Releases |
Summary: The hermes profiler doesn't work currently, I tracked down the problem to a couple of things. - Need to call `registerForProfiling` to enable profiling for a specific runtime. I added the call at the same place where we enable the debugger. - `runInExecutor` didn't work and call its callback. Not sure exactly why, but using `executor_->add` like we do in a lot of other places to run code on the executor works. - `GetHeapUsageRequest` seems to cause some deadlocks. JS contexts were not detected reliably, I suspect this is related to deadlocks when trying to run on inspector executor. `GetHeapUsageRequest` doesn't actually need any data from the inspector so there is no need to run it on that queue. To fix it I moved the call to use `runInExecutor` instead. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [General] [Fixed] - Fix hermes profiler Pull Request resolved: #34129 Reviewed By: cortinico Differential Revision: D37669469 Pulled By: philIip fbshipit-source-id: 6cf3b2857ac60b0a1518837b9c56b9c093ed222f
Summary: The hermes profiler doesn't work currently, I tracked down the problem to a couple of things. - Need to call `registerForProfiling` to enable profiling for a specific runtime. I added the call at the same place where we enable the debugger. - `runInExecutor` didn't work and call its callback. Not sure exactly why, but using `executor_->add` like we do in a lot of other places to run code on the executor works. - `GetHeapUsageRequest` seems to cause some deadlocks. JS contexts were not detected reliably, I suspect this is related to deadlocks when trying to run on inspector executor. `GetHeapUsageRequest` doesn't actually need any data from the inspector so there is no need to run it on that queue. To fix it I moved the call to use `runInExecutor` instead. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [General] [Fixed] - Fix hermes profiler Pull Request resolved: #34129 Reviewed By: cortinico Differential Revision: D37669469 Pulled By: philIip fbshipit-source-id: 6cf3b2857ac60b0a1518837b9c56b9c093ed222f
Summary
The hermes profiler doesn't work currently, I tracked down the problem to a couple of things.
registerForProfiling
to enable profiling for a specific runtime. I added the call at the same place where we enable the debugger.runInExecutor
didn't work and call its callback. Not sure exactly why, but usingexecutor_->add
like we do in a lot of other places to run code on the executor works.GetHeapUsageRequest
seems to cause some deadlocks. JS contexts were not detected reliably, I suspect this is related to deadlocks when trying to run on inspector executor.GetHeapUsageRequest
doesn't actually need any data from the inspector so there is no need to run it on that queue. To fix it I moved the call to userunInExecutor
instead.Changelog
[General] [Fixed] - Fix hermes profiler
Test Plan