-
-
Notifications
You must be signed in to change notification settings - Fork 332
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: Implement fallback system to screens that aren't reporting on the native layer the time to display. #4042
base: main
Are you sure you want to change the base?
Conversation
Instructions and example for changelogPlease add an entry to Example: ## Unreleased
- Implement fallback system to screens that aren't reporting on the native layer the time to display ([#4042](https://github.com/getsentry/sentry-react-native/pull/4042)) If none of the above apply, you can opt out of this check by adding |
Android (legacy) Performance metrics 🚀
|
Revision | Plain | With Sentry | Diff |
---|---|---|---|
31fcca2 | 391.22 ms | 414.78 ms | 23.56 ms |
76d1baf+dirty | 335.72 ms | 355.52 ms | 19.80 ms |
d361d38 | 354.10 ms | 381.69 ms | 27.59 ms |
62a750b | 395.96 ms | 423.36 ms | 27.41 ms |
5a22220 | 412.38 ms | 447.35 ms | 34.97 ms |
700cbf4 | 425.56 ms | 436.26 ms | 10.70 ms |
86d6d2c+dirty | 332.90 ms | 352.45 ms | 19.55 ms |
dadc233+dirty | 333.78 ms | 343.94 ms | 10.16 ms |
0677344 | 327.74 ms | 337.14 ms | 9.40 ms |
1c65324 | 426.37 ms | 460.36 ms | 33.99 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
31fcca2 | 17.73 MiB | 19.90 MiB | 2.17 MiB |
76d1baf+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
d361d38 | 17.73 MiB | 19.81 MiB | 2.08 MiB |
62a750b | 17.73 MiB | 19.93 MiB | 2.20 MiB |
5a22220 | 17.73 MiB | 19.93 MiB | 2.20 MiB |
700cbf4 | 17.73 MiB | 20.07 MiB | 2.33 MiB |
86d6d2c+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
dadc233+dirty | 17.73 MiB | 19.75 MiB | 2.02 MiB |
0677344 | 17.73 MiB | 19.81 MiB | 2.07 MiB |
1c65324 | 17.73 MiB | 19.95 MiB | 2.21 MiB |
Android (new) Performance metrics 🚀
|
Revision | Plain | With Sentry | Diff |
---|---|---|---|
f06c879+dirty | 361.27 ms | 407.88 ms | 46.61 ms |
2534337+dirty | 597.14 ms | 665.04 ms | 67.90 ms |
76d1baf+dirty | 339.02 ms | 408.65 ms | 69.63 ms |
1d86dd6+dirty | 335.76 ms | 371.22 ms | 35.46 ms |
1c65324+dirty | 381.10 ms | 427.26 ms | 46.16 ms |
5bb8d5f+dirty | 356.71 ms | 389.65 ms | 32.94 ms |
5a22220+dirty | 384.61 ms | 419.06 ms | 34.45 ms |
0db0c72+dirty | 335.20 ms | 351.06 ms | 15.86 ms |
5446992+dirty | 371.61 ms | 390.00 ms | 18.39 ms |
4a6664f+dirty | 357.02 ms | 394.91 ms | 37.89 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
f06c879+dirty | 7.15 MiB | 8.12 MiB | 997.78 KiB |
2534337+dirty | 7.15 MiB | 8.11 MiB | 988.68 KiB |
76d1baf+dirty | 7.15 MiB | 8.09 MiB | 964.41 KiB |
1d86dd6+dirty | 7.15 MiB | 8.13 MiB | 1002.18 KiB |
1c65324+dirty | 7.15 MiB | 8.22 MiB | 1.07 MiB |
5bb8d5f+dirty | 7.15 MiB | 8.21 MiB | 1.06 MiB |
5a22220+dirty | 7.15 MiB | 8.21 MiB | 1.06 MiB |
0db0c72+dirty | 7.15 MiB | 8.04 MiB | 911.02 KiB |
5446992+dirty | 7.15 MiB | 8.12 MiB | 999.45 KiB |
4a6664f+dirty | 7.15 MiB | 8.22 MiB | 1.07 MiB |
iOS (legacy) Performance metrics 🚀
|
Revision | Plain | With Sentry | Diff |
---|---|---|---|
728164b+dirty | 1256.10 ms | 1259.08 ms | 2.98 ms |
8900e1a+dirty | 1210.27 ms | 1218.66 ms | 8.39 ms |
ad6c299+dirty | 1244.76 ms | 1260.10 ms | 15.34 ms |
15c80ab+dirty | 1223.74 ms | 1228.96 ms | 5.22 ms |
b1e8712+dirty | 1256.02 ms | 1265.14 ms | 9.12 ms |
e2b64fe+dirty | 1232.22 ms | 1255.20 ms | 22.98 ms |
baa882f+dirty | 1218.00 ms | 1227.04 ms | 9.04 ms |
70caa60+dirty | 1218.27 ms | 1230.30 ms | 12.03 ms |
70e6261+dirty | 1220.09 ms | 1230.04 ms | 9.95 ms |
4a6664f+dirty | 1209.49 ms | 1208.63 ms | -0.86 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
728164b+dirty | 2.36 MiB | 2.88 MiB | 530.38 KiB |
8900e1a+dirty | 2.36 MiB | 2.83 MiB | 479.25 KiB |
ad6c299+dirty | 2.36 MiB | 2.84 MiB | 488.85 KiB |
15c80ab+dirty | 2.36 MiB | 2.83 MiB | 474.49 KiB |
b1e8712+dirty | 2.36 MiB | 2.84 MiB | 488.84 KiB |
e2b64fe+dirty | 2.36 MiB | 2.85 MiB | 495.80 KiB |
baa882f+dirty | 2.36 MiB | 3.08 MiB | 731.91 KiB |
70caa60+dirty | 2.36 MiB | 2.83 MiB | 479.27 KiB |
70e6261+dirty | 2.36 MiB | 3.03 MiB | 680.42 KiB |
4a6664f+dirty | 2.36 MiB | 3.04 MiB | 696.39 KiB |
iOS (new) Performance metrics 🚀
|
Revision | Plain | With Sentry | Diff |
---|---|---|---|
728164b+dirty | 1280.06 ms | 1285.26 ms | 5.20 ms |
8900e1a+dirty | 1268.36 ms | 1273.04 ms | 4.68 ms |
ad6c299+dirty | 1248.50 ms | 1248.88 ms | 0.38 ms |
15c80ab+dirty | 1248.41 ms | 1251.24 ms | 2.83 ms |
b1e8712+dirty | 1284.11 ms | 1297.82 ms | 13.71 ms |
e2b64fe+dirty | 1285.78 ms | 1297.56 ms | 11.78 ms |
baa882f+dirty | 1235.48 ms | 1229.02 ms | -6.46 ms |
70caa60+dirty | 1279.08 ms | 1281.54 ms | 2.46 ms |
70e6261+dirty | 1224.90 ms | 1231.02 ms | 6.12 ms |
4a6664f+dirty | 1218.77 ms | 1221.07 ms | 2.30 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
728164b+dirty | 2.92 MiB | 3.44 MiB | 533.26 KiB |
8900e1a+dirty | 2.92 MiB | 3.39 MiB | 485.96 KiB |
ad6c299+dirty | 2.92 MiB | 3.40 MiB | 494.12 KiB |
15c80ab+dirty | 2.92 MiB | 3.39 MiB | 481.56 KiB |
b1e8712+dirty | 2.92 MiB | 3.40 MiB | 494.15 KiB |
e2b64fe+dirty | 2.92 MiB | 3.41 MiB | 499.97 KiB |
baa882f+dirty | 2.92 MiB | 3.64 MiB | 738.56 KiB |
70caa60+dirty | 2.92 MiB | 3.39 MiB | 486.04 KiB |
70e6261+dirty | 2.92 MiB | 3.59 MiB | 686.11 KiB |
4a6664f+dirty | 2.92 MiB | 3.60 MiB | 702.09 KiB |
Hi @lucas-zimerman, I think waiting for the next drawn frame is a good fallback. But there is one party breaker hidden in the RN implementation. Compared to browsers implementation, in RN requestAnimationFrame -> CreateTimer -> Timer is hook to DisplayLink of JS Thread DisplayLink uses current thread -> JS Thread This means the callback runs after the React Native Node Tree is assembled and passed to native. So unless the JS loop is doing some heavy task, it will generally be executed before the render. We can fix that by implementing our own
The native implementation would the same method to hook into the render loop as RNSentryOnDrawReporterView but instead of component it would be native method of RNSentry. I think we can still use the JS It should work well with the current draft, replacing Let me know what you think, if my though process make sense, or I've missed something. |
The Android integration is done, we will now finish the iOS integration |
…ile, add js implementation as fallback
iOS integration should also be done and tests are also completed. |
📢 Type of change
📜 Description
This change introduces a new event emitter that uses the function requestAnimationFrame during a navigation,
requestAnimationFrame
is useful in this case because the callback is only invoked when all the screen frames are flushed, allowing us to have a good value for the time to display.The way this implementation works is quite simple:
requestAnimationFrame
received the callback, we use the time fromrequestAnimationFrame
and simulate a native event.This way we can patch
SentryEventEmitter
to receive the correct value when the Native part doesn't have any value to return.💡 Motivation and Context
Close #3934
💚 How did you test it?
The playground tab on our sample is a good case for testing, since it doesn't use navigation stack on it, the events on this condition are limited, not generating and required event by us in order to track the time to display.
I used it and other tabs to compare the difference between the original implementation and also
requestAnimationFrame
, and the time difference between each other was quite low:1St Tab
JS: requestAnimationFrame, "newFrameTimestampInSeconds" is 1724293664.8300002
Original: InitAsync Event received {"newFrameTimestampInSeconds":1724293664.8179998}
2Nd Tab
JS: requestAnimationFrame, "newFrameTimestampInSeconds" is 1724293761.688
Original: InitAsync Event received {"newFrameTimestampInSeconds":1724293761.689}
3Rd Tab
JS: requestAnimationFrame, "newFrameTimestampInSeconds" is 1724293824.887
Original: Android didn't emit an event for this page so it wasn't measured
Before this change on the playground screen:
https://sentry-sdks.sentry.io/performance/trace/10bd4bf28052404592f408f3cf58175a/?dataset=transactions&field=title&field=event.type&field=project&field=user.display&field=timestamp&field=replayId&fov=0%2C15046.88916015625&id=21705&name=&node=trace-root&project=5428561&query=&queryDataset=transaction-like&sort=-timestamp&source=discover&statsPeriod=1h×tamp=1724358725&topEvents=5&yAxis=count%28%29
After this change on the playground screen:
https://sentry-sdks.sentry.io/performance/trace/8cb478b4370e444fa4a7b9be778d51ab/?dataset=transactions&field=title&field=event.type&field=project&field=user.display&field=timestamp&field=replayId&fov=0%2C235&id=21705&name=&node=txn-b5a8ba18aa254fe79743133baf9071b2&project=5428561&query=&queryDataset=transaction-like&sort=-timestamp&source=discover&statsPeriod=1h×tamp=1724359145&topEvents=5&yAxis=count%28%29
📝 Checklist
sendDefaultPII
is enabled🔮 Next steps