Skip to content

Conversation

buenaflor
Copy link
Contributor

@buenaflor buenaflor commented Sep 4, 2025

📜 Description

Performance improvement -> reduces possible UI jank as it offloads captureEnvelope from the main isolate

Main points:

  • Adds a long lived worker specifically for handling capturing envelopes for Android and iOS on init
  • Uses the JNI/FFI methods
  • Since JNI/FFI is hard to mock the main tests are done via the e2e and integration tests

💡 Motivation and Context

Closes #3166

💚 How did you test it?

Unit test, integration test, e2e test, manual test

📝 Checklist

  • I reviewed submitted code
  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPii is enabled
  • I updated the docs if needed
  • All tests passing
  • No breaking changes

🔮 Next steps

Adjust AndroidReplayRecorder to use the new setup

Copy link
Contributor

github-actions bot commented Sep 4, 2025

iOS Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1253.19 ms 1261.94 ms 8.75 ms
Size 5.53 MiB 6.00 MiB 486.71 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
aeb02f2 1244.29 ms 1256.55 ms 12.26 ms
54acf91 1257.65 ms 1277.96 ms 20.31 ms
73a3c38 1263.37 ms 1277.90 ms 14.53 ms
944b773 1252.82 ms 1254.08 ms 1.27 ms
827bf09 1261.86 ms 1276.41 ms 14.55 ms
192b44c 1269.08 ms 1275.52 ms 6.44 ms
c1e775e 1263.08 ms 1275.32 ms 12.24 ms
cf443d2 1255.79 ms 1248.38 ms -7.40 ms
81f83eb 1259.53 ms 1273.39 ms 13.86 ms
0fb3800 1256.60 ms 1266.28 ms 9.68 ms

App size

Revision Plain With Sentry Diff
aeb02f2 7.86 MiB 9.44 MiB 1.58 MiB
54acf91 20.70 MiB 22.46 MiB 1.75 MiB
73a3c38 7.86 MiB 9.44 MiB 1.58 MiB
944b773 5.53 MiB 6.00 MiB 479.98 KiB
827bf09 7.86 MiB 9.44 MiB 1.58 MiB
192b44c 5.53 MiB 5.96 MiB 444.33 KiB
c1e775e 20.70 MiB 22.46 MiB 1.75 MiB
cf443d2 5.53 MiB 6.00 MiB 479.99 KiB
81f83eb 7.86 MiB 9.44 MiB 1.58 MiB
0fb3800 7.86 MiB 9.44 MiB 1.58 MiB

Previous results on branch: enh/long-lived-envelope-worker

Startup times

Revision Plain With Sentry Diff
7efb747 1242.94 ms 1243.30 ms 0.36 ms
06ee227 1230.00 ms 1230.40 ms 0.40 ms
e2ae6a3 1249.42 ms 1253.49 ms 4.07 ms
10d9419 1228.74 ms 1225.90 ms -2.84 ms
03f8118 1263.06 ms 1267.69 ms 4.63 ms
71ba593 1247.98 ms 1250.84 ms 2.87 ms
79d9ff9 1266.81 ms 1271.29 ms 4.47 ms
8325952 1253.63 ms 1247.92 ms -5.71 ms
53c6036 1259.98 ms 1261.67 ms 1.69 ms
62bb12b 1264.79 ms 1260.16 ms -4.63 ms

App size

Revision Plain With Sentry Diff
7efb747 5.53 MiB 6.00 MiB 486.71 KiB
06ee227 5.53 MiB 6.00 MiB 486.01 KiB
e2ae6a3 5.53 MiB 6.00 MiB 486.24 KiB
10d9419 5.53 MiB 6.00 MiB 486.00 KiB
03f8118 5.53 MiB 6.00 MiB 479.95 KiB
71ba593 5.53 MiB 6.00 MiB 486.22 KiB
79d9ff9 5.53 MiB 6.00 MiB 486.07 KiB
8325952 5.53 MiB 6.00 MiB 486.78 KiB
53c6036 5.53 MiB 6.00 MiB 486.02 KiB
62bb12b 5.53 MiB 6.00 MiB 486.01 KiB

Copy link
Contributor

github-actions bot commented Sep 4, 2025

Android Performance metrics 🚀

  Plain With Sentry Diff
Startup time 453.22 ms 438.06 ms -15.16 ms
Size 13.93 MiB 15.06 MiB 1.13 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
6b69699 456.06 ms 557.44 ms 101.38 ms
192b44c 472.26 ms 477.34 ms 5.08 ms
1f639ee 429.98 ms 476.60 ms 46.62 ms
6f47800 451.04 ms 509.64 ms 58.60 ms
7cfee3b 498.78 ms 516.98 ms 18.20 ms
7cfbbd6 499.69 ms 592.24 ms 92.55 ms
73dca78 476.53 ms 522.21 ms 45.68 ms
32914d8 461.96 ms 495.47 ms 33.51 ms
2cf9161 454.12 ms 512.67 ms 58.55 ms
6bcdc99 440.23 ms 435.77 ms -4.46 ms

App size

Revision Plain With Sentry Diff
6b69699 6.54 MiB 7.70 MiB 1.17 MiB
192b44c 13.93 MiB 14.93 MiB 1.00 MiB
1f639ee 13.93 MiB 15.00 MiB 1.06 MiB
6f47800 6.54 MiB 7.69 MiB 1.15 MiB
7cfee3b 6.54 MiB 7.70 MiB 1.17 MiB
7cfbbd6 6.54 MiB 7.70 MiB 1.17 MiB
73dca78 6.54 MiB 7.69 MiB 1.15 MiB
32914d8 6.54 MiB 7.70 MiB 1.16 MiB
2cf9161 6.54 MiB 7.70 MiB 1.16 MiB
6bcdc99 13.93 MiB 15.00 MiB 1.06 MiB

Previous results on branch: enh/long-lived-envelope-worker

Startup times

Revision Plain With Sentry Diff
69d5111 436.04 ms 444.10 ms 8.06 ms
a603960 429.91 ms 445.76 ms 15.84 ms
53c6036 445.09 ms 455.83 ms 10.74 ms
7efb747 503.90 ms 550.11 ms 46.21 ms
06ee227 483.22 ms 488.79 ms 5.57 ms
10d9419 453.07 ms 479.09 ms 26.02 ms
e2ae6a3 492.72 ms 505.13 ms 12.41 ms
79d9ff9 481.20 ms 500.58 ms 19.38 ms
03f8118 456.31 ms 468.04 ms 11.73 ms
532d2b3 517.87 ms 508.88 ms -9.00 ms

App size

Revision Plain With Sentry Diff
69d5111 13.93 MiB 15.06 MiB 1.13 MiB
a603960 13.93 MiB 15.00 MiB 1.06 MiB
53c6036 13.93 MiB 15.06 MiB 1.13 MiB
7efb747 13.93 MiB 15.06 MiB 1.13 MiB
06ee227 13.93 MiB 15.06 MiB 1.13 MiB
10d9419 13.93 MiB 15.06 MiB 1.13 MiB
e2ae6a3 13.93 MiB 15.06 MiB 1.13 MiB
79d9ff9 13.93 MiB 15.06 MiB 1.13 MiB
03f8118 13.93 MiB 15.00 MiB 1.06 MiB
532d2b3 13.93 MiB 15.06 MiB 1.13 MiB

@buenaflor buenaflor force-pushed the enh/long-lived-envelope-worker branch from 9048e1f to 10d9419 Compare October 7, 2025 13:02
Copy link

codecov bot commented Oct 7, 2025

Codecov Report

❌ Patch coverage is 77.85714% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.90%. Comparing base (40c8f93) to head (4b440d0).

Files with missing lines Patch % Lines
...er/lib/src/native/cocoa/cocoa_envelope_sender.dart 58.06% 13 Missing ⚠️
...r/lib/src/native/java/android_envelope_sender.dart 60.60% 13 Missing ⚠️
...ckages/flutter/lib/src/isolate/isolate_worker.dart 93.10% 4 Missing ⚠️
...ckages/flutter/lib/src/isolate/isolate_logger.dart 94.44% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3232      +/-   ##
==========================================
+ Coverage   87.84%   88.90%   +1.06%     
==========================================
  Files         290       99     -191     
  Lines       10003     3533    -6470     
==========================================
- Hits         8787     3141    -5646     
+ Misses       1216      392     -824     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines +7 to +35
/// Static logger for Isolates that writes diagnostic messages to `dart:developer.log`.
///
/// Intended for worker/background isolates where a `SentryOptions` instance
/// or hub may not be available. Because Dart statics are isolate-local,
/// you must call [configure] once per isolate before using [log].
class IsolateLogger {
IsolateLogger._();

static late bool _debug;
static late SentryLevel _level;
static late String _loggerName;
static bool _isConfigured = false;

/// Configures this logger for the current isolate.
///
/// Must be called once per isolate before invoking [log].
/// Throws [StateError] if called more than once without calling [reset] first.
///
/// - [debug]: when false, suppresses all logs except [SentryLevel.fatal].
/// - [level]: minimum severity threshold (inclusive) when [debug] is true.
/// - [loggerName]: logger name for the call sites
static void configure(
{required bool debug,
required SentryLevel level,
required String loggerName}) {
if (_isConfigured) {
throw StateError(
'IsolateLogger.configure has already been called. It can only be configured once per isolate.');
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We gotta use a static logger since we cannot pass SentryFlutterOptions to another isolate as it's not serializable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the alternative would be not to log in isolates at all

void _captureEnvelope(Uint8List envelopeData) {
try {
final nsData = envelopeData.toNSData();
final envelope = cocoa.PrivateSentrySDKOnly.envelopeWithData(nsData);
Copy link
Collaborator

@denrase denrase Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to do some performance tests if using the background isolate here is really bringing more performance improvements than the overhead introduce by isolate communication.

Alternatively, if calling the plugin code or a new helper we add from here is possible, we could also do the cocoa.PrivateSentrySDKOnly.envelopeWithData(nsData); call on the plugin side and dispatch to the background there if this indeed is a bottleneck.

If possible, this would be way less code, making it more maintainable and we'd have no sending overhead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cocoa.PrivateSentrySDKOnly.envelopeWithData(nsData); call on the plugin side and dispatch to the background there if this indeed is a bottleneck.

the whole _captureEnvelope function is running in the bg isolate in this case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overhead introduce by isolate communication

Isolate communication overhead is essentially 0 since we use https://api.flutter.dev/flutter/dart-isolate/TransferableTypedData-class.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all in all I'd expect there to be almost no difference in speed but less load on the main isolate which is kind of hard to benchmark, I guess the best way would be to compare frame data

Copy link
Contributor Author

@buenaflor buenaflor Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have benchmarked this via a ~36mb envelope and

  • without bg isolate: significant UI jank that freezes the app for around 1.5 seconds
  • with bg isolate: no jank or freezing at all

@buenaflor buenaflor requested a review from denrase October 8, 2025 10:43
@buenaflor buenaflor marked this pull request as ready for review October 8, 2025 10:43
cursor[bot]

This comment was marked as outdated.

Copy link
Collaborator

@denrase denrase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Long-Running Envelope Worker Isolate for Android, iOS, macOS
2 participants