Skip to content

perf(core): Skip Hint allocation in addBreadcrumb without callback#5689

Merged
runningcode merged 1 commit into
mainfrom
no/java-605-avoid-hint-allocation
Jul 6, 2026
Merged

perf(core): Skip Hint allocation in addBreadcrumb without callback#5689
runningcode merged 1 commit into
mainfrom
no/java-605-avoid-hint-allocation

Conversation

@runningcode

@runningcode runningcode commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Resolves JAVA-605.

Description

Scope.addBreadcrumb(Breadcrumb, Hint) allocated a Hint unconditionally when the caller passed null, even though the Hint is only ever used to pass to the beforeBreadcrumb callback. When no callback is configured (the common case) the Hint — a HashMap + ArrayList + AutoClosableReentrantLock — was created and immediately discarded on every breadcrumb.

This moves the allocation inside the callback != null branch, so no Hint is allocated on the common path.

Pure allocation elimination, no behavior change.

Source

Found via on-device Perfetto method-trace analysis of the Android SDK (Scope#addBreadcrumb 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, cacheDirPath set, no beforeBreadcrumb). 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. allocationCount is deterministic; timeNs has ~±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 a BenchmarkRule looping the scope mutation. Run with:

./gradlew :sentry-android-integration-tests:sentry-uitest-android-microbenchmark:connectedReleaseAndroidTest \
  -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.suppressErrors=UNLOCKED

Result — scope.addBreadcrumb()

Metric main This PR Delta
allocationCount 7 3 -4 per breadcrumb
timeNs (median) ~242 ns 185 ns ~-24%

The 4 eliminated allocations are the Hint plus its HashMap, ArrayList, and AutoClosableReentrantLock. The setTag control path (unaffected by this change) was unchanged at ~127 ns / 3 allocs.

@linear-code

linear-code Bot commented Jul 2, 2026

Copy link
Copy Markdown

JAVA-605

@runningcode runningcode force-pushed the no/java-605-avoid-hint-allocation branch from 88119b9 to 3680ae4 Compare July 2, 2026 16:50
@sentry

sentry Bot commented Jul 2, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.47.0 (1) release

⚙️ sentry-android Build Distribution Settings

@runningcode runningcode marked this pull request as ready for review July 2, 2026 16:53
@runningcode runningcode marked this pull request as draft July 2, 2026 16:57
@runningcode runningcode marked this pull request as ready for review July 2, 2026 17:05
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 362.05 ms 419.80 ms 57.75 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3d205d0 352.15 ms 432.53 ms 80.38 ms
e59e22a 368.02 ms 432.00 ms 63.98 ms
806307f 357.85 ms 424.64 ms 66.79 ms
d364ace 384.53 ms 453.51 ms 68.98 ms
4c04bb8 307.93 ms 362.34 ms 54.41 ms
bb0ff41 312.86 ms 363.78 ms 50.92 ms
91bb874 310.68 ms 359.24 ms 48.56 ms
11f90db 314.26 ms 372.43 ms 58.17 ms
f6cdbf0 314.19 ms 357.59 ms 43.40 ms
8687935 332.52 ms 362.23 ms 29.71 ms

App size

Revision Plain With Sentry Diff
3d205d0 1.58 MiB 2.10 MiB 532.97 KiB
e59e22a 1.58 MiB 2.20 MiB 635.34 KiB
806307f 1.58 MiB 2.10 MiB 533.42 KiB
d364ace 1.58 MiB 2.11 MiB 539.75 KiB
4c04bb8 0 B 0 B 0 B
bb0ff41 0 B 0 B 0 B
91bb874 1.58 MiB 2.13 MiB 559.07 KiB
11f90db 0 B 0 B 0 B
f6cdbf0 0 B 0 B 0 B
8687935 1.58 MiB 2.19 MiB 619.17 KiB

Previous results on branch: no/java-605-avoid-hint-allocation

Startup times

Revision Plain With Sentry Diff
f1645b1 354.71 ms 435.38 ms 80.67 ms

App size

Revision Plain With Sentry Diff
f1645b1 0 B 0 B 0 B

Only allocate a Hint when a beforeBreadcrumb callback is set. addBreadcrumb
previously allocated a Hint (HashMap + ArrayList + lock) on every call even
though the Hint is only ever passed to the callback, wasting allocations on
the common no-callback path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@runningcode runningcode force-pushed the no/java-605-avoid-hint-allocation branch from 3680ae4 to 1916876 Compare July 6, 2026 12:50
@runningcode runningcode enabled auto-merge (squash) July 6, 2026 12:54
@runningcode runningcode merged commit 2d4376b into main Jul 6, 2026
68 of 70 checks passed
@runningcode runningcode deleted the no/java-605-avoid-hint-allocation branch July 6, 2026 13:01
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.

2 participants