perf(core): Skip redundant setBreadcrumbs call on the addBreadcrumb path#5690
Closed
runningcode wants to merge 1 commit into
Closed
perf(core): Skip redundant setBreadcrumbs call on the addBreadcrumb path#5690runningcode wants to merge 1 commit into
runningcode wants to merge 1 commit into
Conversation
addBreadcrumb notified each scope observer twice: addBreadcrumb(crumb) followed by setBreadcrumbs(all). For PersistingScopeObserver the second call is a no-op right after an add (it only acts when the collection is empty), yet still acquires the synchronized-queue lock and re-iterates observers on every breadcrumb. Notify observers once per add. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ce3cd6e to
e6486b9
Compare
📲 Install BuildsAndroid
|
Contributor
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| abfcc92 | 304.04 ms | 370.33 ms | 66.29 ms |
| 4e3e79d | 365.83 ms | 477.62 ms | 111.79 ms |
| d8912da | 329.94 ms | 389.68 ms | 59.74 ms |
| d15471f | 294.13 ms | 399.49 ms | 105.36 ms |
| abf451a | 332.82 ms | 403.67 ms | 70.85 ms |
| 604a261 | 380.65 ms | 451.27 ms | 70.62 ms |
| 806307f | 357.85 ms | 424.64 ms | 66.79 ms |
| 22f4345 | 307.87 ms | 354.51 ms | 46.64 ms |
| d217708 | 375.27 ms | 415.68 ms | 40.41 ms |
| c3ee041 | 310.64 ms | 361.90 ms | 51.26 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| abfcc92 | 1.58 MiB | 2.13 MiB | 557.31 KiB |
| 4e3e79d | 0 B | 0 B | 0 B |
| d8912da | 0 B | 0 B | 0 B |
| d15471f | 1.58 MiB | 2.13 MiB | 559.54 KiB |
| abf451a | 1.58 MiB | 2.20 MiB | 635.29 KiB |
| 604a261 | 1.58 MiB | 2.10 MiB | 533.42 KiB |
| 806307f | 1.58 MiB | 2.10 MiB | 533.42 KiB |
| 22f4345 | 1.58 MiB | 2.29 MiB | 719.83 KiB |
| d217708 | 1.58 MiB | 2.10 MiB | 532.97 KiB |
| c3ee041 | 0 B | 0 B | 0 B |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves JAVA-606.
Description
Scope.addBreadcrumbnotified every scope observer twice per breadcrumb:observer.addBreadcrumb(crumb)followed byobserver.setBreadcrumbs(all). ForPersistingScopeObserverthe second call is a guaranteed no-op right after an add — it only does work when the collection is empty (the clear case) — yet it still acquires theSynchronizedQueuelock viaisEmpty()and re-iterates the observer list on every breadcrumb.This notifies observers once per add.
clearBreadcrumbsstill callssetBreadcrumbs.IScopeObserveris a public interface. In principle a third-party observer could implement onlysetBreadcrumbsand rely on it being called on every add, rather than the incrementaladdBreadcrumb. Removing the per-addsetBreadcrumbscall changes the observer notification contract on the add path.This PR treats that as an intentional contract clarification (observers must implement
addBreadcrumbfor incremental updates). Flagging for a maintainer decision — if we'd rather preserve the old contract, close this in favor of documentation only. Kept as draft for that reason.Source
Found via on-device Perfetto method-trace analysis of the Android SDK breadcrumb path. Part of Reduce SDK init time [Android].
🤖 Generated with Claude Code
Benchmark
Measured on-device with androidx Microbenchmark 1.4.1 (
benchmark-junit4) on a Samsung Galaxy A55 (SM-A556B), Android API 36 (release build, non-minified).The benchmark exercises the caller-side cost of a scope mutation with scope persistence enabled (
enableScopePersistence = true,cacheDirPathset, nobeforeBreadcrumb). The async serialize + disk write is dispatched to a no-op executor so it never runs on the measured thread — mirroring production, where it runs off-thread. Each branch is compared against its base commit (aab952b82e); the per-branch delta isolates this change.allocationCountis deterministic;timeNshas ~±10 ns run-to-run noise on a non-rooted device (unlocked clocks), so it is reported as a median and reproduced across 2 runs.How it was done
A local, uncommitted androidx microbenchmark module (
sentry-android-integration-tests/sentry-uitest-android-microbenchmark) depending on:sentry, with aBenchmarkRulelooping the scope mutation. Run with:Result —
scope.addBreadcrumb()As expected, dropping the redundant per-observer
setBreadcrumbscall is a small time/lock win with no allocation change. ThesetTagcontrol path was unchanged.