Skip to content

perf(instrumentation): Resolve SDK class availability at build time - #1375

Open
romtsn wants to merge 3 commits into
mainfrom
romtsn/feat/java-654-sdk-optimization
Open

perf(instrumentation): Resolve SDK class availability at build time#1375
romtsn wants to merge 3 commits into
mainfrom
romtsn/feat/java-654-sdk-optimization

Conversation

@romtsn

@romtsn romtsn commented Jul 30, 2026

Copy link
Copy Markdown
Member

Resolve the availability of optional Sentry SDK classes from the app's dependency graph and inject the results into LoadClass during bytecode instrumentation. The optimization is independent from tracing instrumentation, enabled by default, and can be disabled with sentry.sdkOptimization.enabled = false.

The visitor safely ignores older SDK versions without the availability field. Applications using the supporting SDK avoid reflective availability probes during startup, while unknown class names still fall back to reflection.

Supporting SDK change: getsentry/sentry-java#5875

On a Pixel 2 XL, map construction and lookups were about 160× faster than the equivalent absent-heavy 11-class reflection batch. In the absent-heavy startup macrobenchmark, SDK initialization was 1.08% faster and full startup was 0.88% faster, though variance exceeded the measured delta. The representative 10-present/1-absent case showed no measurable improvement.

Verified with Spotless and focused visitor/plugin tests.

Refs JAVA-654

Add an independently configurable ASM visitor that derives known optional classes from resolved modules and injects their availability into LoadClass. Avoid repeated reflection during SDK startup.

Refs JAVA-654
Co-Authored-By: Codex <noreply@openai.com>
@linear-code

linear-code Bot commented Jul 30, 2026

Copy link
Copy Markdown

JAVA-654

Document the build-time SDK class availability optimization introduced in #1375.

Refs JAVA-654
Co-Authored-By: Codex <noreply@openai.com>
Use zero placeholders and document that visitMaxs triggers frame and max computation.

Refs LINEAR-JAVA-654

Co-Authored-By: Codex <noreply@openai.com>
@romtsn
romtsn marked this pull request as ready for review July 30, 2026 14:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 94d96e4. Configure here.

instrumentationContext.apiVersion.get(),
nextClassVisitor,
resolveClassAvailability(modules),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale availability after dependency changes

High Severity

SdkOptimizationParameters only exposes the modules service as @Internal, so AGP's incremental ASM transform has no @Input fingerprint for the computed availability map. Availability is injected into LoadClass inside the Sentry jar; adding or removing a mapped dependency like Timber leaves that jar unchanged, so prior instrumentation can be reused and the SDK keeps trusting outdated true/false entries.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 94d96e4. Configure here.

return LoadClassClassVisitor(
instrumentationContext.apiVersion.get(),
nextClassVisitor,
resolveClassAvailability(modules),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variants share mutable module state

Medium Severity

All variants register and write into one SentryModulesService instance, then this visitor reads that shared mutable map while injecting availability. Parallel resolution of variant classpaths can overwrite another variant's modules, so debug-only dependencies such as Timber can be recorded as present or absent for the wrong variant.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 94d96e4. Configure here.

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good!

One more thing, should we detect an incompatible version of the sentry-java sdk and then show an error?

* We detect sentry-android SDK version using configurations.incoming.afterResolve. This is
* guaranteed to be executed BEFORE any of the build tasks/transforms are started.
*
* After detecting the sdk state, we use Gradle's shared build service to persist the state

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

good to delete this. this is false, build services are not kept across builds.

import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes

internal class LoadClassClassVisitor(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think a small javadoc on this one would be helpful


open class SdkOptimizationExtension @Inject constructor(objects: ObjectFactory) {
/** Enables build-time optimizations of the Sentry SDK. Defaults to true. */
val enabled: Property<Boolean> = objects.property(Boolean::class.java).convention(true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

aren't we going to have different optimizations? like properties, manifest and this one? Will they all be gated behind the same flag?

import javax.inject.Inject
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we name this StartupTimeOptimizations?

import org.gradle.api.provider.Property

open class SdkOptimizationExtension @Inject constructor(objects: ObjectFactory) {
/** Enables build-time optimizations of the Sentry SDK. Defaults to true. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/** Enables build-time optimizations of the Sentry SDK. Defaults to true. */
/** Enables run-time optimizations of the Sentry SDK at the cost of build time. Defaults to true. */

* between builds and also during a single build, because transforms are run in parallel.
*/
val sentryModulesService =
val sdkOptimizationEnabled = extension.sdkOptimization.enabled.get()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

like above, i think we should rename this to runtimeOptimizations or something similar

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