-
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
New implementation of PerformanceObserver and related APIs (fixes #45122) #45206
base: main
Are you sure you want to change the base?
Conversation
2ed73a9
to
5de7d48
Compare
Pushed early changes for approach review. Still working on updating TurboModule and its spec to match new API. |
5de7d48
to
7b45779
Compare
Ready for an early review. Will undo changes related to exposing Performance TurboModule and still needs some testing from my side. |
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 is a larger refactor than I was expecting, but I like the direction we're taking here. I made an initial pass on the PR (please forgive the amount of comments, this is very large). Please let me know what you think, and thanks so much for this!
packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp
Outdated
Show resolved
Hide resolved
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Show resolved
Hide resolved
@@ -28,6 +30,14 @@ namespace facebook::react { | |||
return std::make_shared<NativeIdleCallbacks>(jsInvoker); | |||
} | |||
|
|||
if (name == NativePerformance::kModuleName) { |
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.
We don't want to enable this by default yet, until we've had a chance to test it thoroughly at Meta first. Please revert this for the PR (I understand you still need it to test it).
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.
Please add the comment about this being temporary as well :P
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Show resolved
Hide resolved
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserverRegistry.h
Outdated
Show resolved
Hide resolved
packages/react-native/src/private/webapis/performance/specs/NativePerformanceObserver.js
Show resolved
Hide resolved
844f334
to
8a77bcd
Compare
@rubennorte I've allowed myself to resolve comments that I think are corrected :) The remaining ones I still need some input. FYI: still not fully tested on my side 😅 |
@@ -28,6 +30,14 @@ namespace facebook::react { | |||
return std::make_shared<NativeIdleCallbacks>(jsInvoker); | |||
} | |||
|
|||
if (name == NativePerformance::kModuleName) { |
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.
Please add the comment about this being temporary as well :P
...ages/react-native/ReactCommon/react/nativemodule/defaults/React-defaultsnativemodule.podspec
Outdated
Show resolved
Hide resolved
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/BoundedConsumableBuffer.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserverRegistry.h
Outdated
Show resolved
Hide resolved
caf3b65
to
8772490
Compare
packages/react-native/src/private/webapis/performance/specs/NativePerformanceObserver.js
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/BoundedConsumableBuffer.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryCircularBuffer.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryCircularBuffer.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h
Outdated
Show resolved
Hide resolved
double durationThreshold{DEFAULT_DURATION_THRESHOLD}; | ||
size_t droppedEntriesCount{0}; |
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.
Do these need to be public?
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 needs to be accessed from EntryReporter to validate if the entry should be added. I can make it protected, but then I'd need to make it a friend of EntryReporter
which I'd avoid. As an alternative I could move the login into buffer itself, but that was just moved out of it :D
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 don't think we need durationThreshold here. We can just define it in the buffer for event entry types.
Regarding droppedEntriesCount
, there's no reason to have them per buffer AFAIK, so we could make add
return a boolean and then have a single count in the entry reporter, so you don't even have to iterate over each buffer. It's a bit simpler IMHO.
Actually, we need to keep them separate per buffer because the reported number is only for the entry types that the observer is observing. Please ignore this last comment :)
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryCircularBuffer.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryLinearBuffer.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryKeyedBuffer.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryKeyedBuffer.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryLinearBuffer.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserverRegistry.cpp
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserverRegistry.h
Outdated
Show resolved
Hide resolved
packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h
Outdated
Show resolved
Hide resolved
…o `CircularBuffer`, cleaned up buffer API
e57a510
to
8fe46c2
Compare
packages/react-native/ReactCommon/react/performance/timeline/CircularBuffer.h
Show resolved
Hide resolved
packages/react-native/src/private/webapis/performance/PerformanceObserver.js
Outdated
Show resolved
Hide resolved
@rubennorte has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
@@ -128,6 +137,18 @@ void NativePerformance::measure( | |||
#endif | |||
} | |||
|
|||
void NativePerformance::logEvent( |
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 shouldn't be exposed to JS because these are always emitted from native.
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 exposed them for unittests 😅
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.
Maybe make the name more explicit (e.g.: testOnly_logEvent
).
...ges/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformanceObserver.cpp
Outdated
Show resolved
Hide resolved
double PerformanceObserver::getDroppedEntriesCount() noexcept { | ||
double droppedEntriesCount = 0; | ||
|
||
if (requiresDroppedEntries_) { |
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 should be a set of types that we need to report dropped entries. This should also work if we do this:
observer.observe({type: 'mark', buffered: true}); // report marks until this point and report dropped ones
observer.observer({type: measure', buffered: true}); // same, but for this time and until this moment
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.
We iterate over observer types below, and the flag is reset after each observe
. So it should work as mentioned (considering observe
resets entries, not adds more)
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 we're not handling the timing of that correctly. We're determining the number of dropped entries when the callback is executed, not when we "dump" all the entries in the observer buffer. Also, if we execute the code I shared in previous example, we'd be dropping all the existing entries in the observer buffer because we just reassign it. We just append those and determine dropped entries at the time of observation.
Summary:
Fix #45122.
performance.mark is currently O(1) but performance.clearMark is O(n) (being n the number of entries in the buffer), which makes this operation very slow.
Changes overview
PerformanceEntryBuffer
abstraction with the following subtypes, that differ on how entries are stored:PerformanceEntryCircularBuffer
- stores them in a ring buffer that was already implemented, removed key lookup cache (BoundedConsumableBuffer
)PerformanceEntryKeyedBuffer
- stores them in aunordered_map
, allowing for faster retrieval by typePerformanceEntryLinearBuffer
- a simple infinite buffer based onstd::vector
, currently used in aPerformanceObserver
PerformanceObserver
abstraction on native side.PerformanceObserverRegistry
that collects active observers and forwards entries to observers that should retrieve them.cpp
files to reduce potential compilation time slowdown. As thePerformanceEntryReporter
can be included from anywhere in the code, it will be beneficial to make header files as light as possible.[[nodiscard]]
attributesPerformanceObserver
can be created from native-sideStandards covered:
Changelog:
[GENERAL] [CHANGED] - Refactored
performance-timeline
module, which should improve performance ofperformance.clearMarks
andperformance.clearMeasures
Test Plan:
n/a