Skip to content

Use Java 25 as the default compiler toolchain - #12305

Open
AlexeyKuznetsov-DD wants to merge 3 commits into
masterfrom
alexeyk/use-java-25
Open

AlexeyKuznetsov-DD wants to merge 3 commits into
masterfrom
alexeyk/use-java-25

Conversation

@AlexeyKuznetsov-DD

Copy link
Copy Markdown
Contributor

What Does This Do

Uses JDK 25 as the default Java and Groovy compiler toolchain, matching the Gradle daemon JDK. Java compilation whose
toolchain matches the daemon can run in-process instead of starting a compiler JVM for each older module toolchain.

The emitted bytecode version remains explicit and is independent of the compiler JDK. Normal Java compilation uses
--release <bytecodeVersion>. Code that intentionally references newer or unpublished JDK APIs while emitting older
bytecode supplies unsetReleaseFlagReason and uses -source/-target instead.

Toolchain 8, 11, or 21 is retained only where required by compiler or source compatibility, including old Scala compilers,
JDK internals, old Error Prone/NullAway versions, legacy jars, and a JDK 21 preview API removed in JDK 25. Every non-25
selection must include an explanation; Gradle configuration fails otherwise.

This also centralizes the Kotlin DSL configureCompiler bridge and upgrades the malformed AspectJ 1.8.13 dependency used
by the Zuul instrumentation to 1.8.14 so it can be read by modern javac.

Motivation

Many modules selected JDK 8, 11, 17, or 21 only to control their bytecode level. Because those toolchains differ from the
JDK 25 Gradle daemon, Gradle starts and warms additional compiler JVMs. Using JDK 25 for compilation while preserving each
module's bytecode and API compatibility removes unnecessary process overhead without raising the runtime requirement of
the produced artifacts.

Additional Notes

Local ./gradlew assemble --rerun-tasks benchmark, with the daemon on JDK 25, one warm-up followed by three measured runs,
and the full process tree sampled:

Metric master This PR Change
Wall time, mean 126.2 s 94.9 s -24.8%
CPU time, mean 771 s 591 s -23.4%
Peak RSS, mean 18.5 GB 18.3 GB -0.9% (noise)

A fresh uncached :instrumentationLatestDepTest process-tree comparison with six Gradle workers showed the reduction in
JVM creation directly:

Metric master-based baseline This PR
Forked JVMs 80 59-65
Peak concurrent JVMs 35 26-27

That is about 15-21 fewer JVM forks (19-26%) and 8-9 fewer JVMs at peak. Groovy, Scala/Zinc, tests, and genuine older-JDK
exceptions still fork as required, so this does not eliminate all worker JVMs. Peak memory was effectively unchanged in
the repeated assemble benchmark; the demonstrated improvements are fewer processes, lower CPU use, and shorter build
time.

Validation:

  • ./gradlew assemble
  • focused production and test compilation for migrated and retained-toolchain modules
  • both Akka HTTP 10.6 Scala test compilation tasks, plus their Java 11 test suites (296 tests, 0 failures)
  • agent JAR comparison against master; class-file versions were unchanged and differences were limited to expected
    compiler-generated metadata and synthetic representation
  • full GitLab pipeline passed end to end

JDK 25 is an explicit compiler policy. When the daemon toolchain changes, update this default and its audit guard together.
The benchmark used a warm dependency cache on one machine; assemble also includes non-compilation work.

Contributor Checklist

Jira ticket: [PROJ-IDENT]

@AlexeyKuznetsov-DD AlexeyKuznetsov-DD added tag: no release notes Changes to exclude from release notes type: refactoring comp: tooling Build & Tooling tag: ai generated Largely based on code generated by an AI or LLM labels Aug 26, 2026
@AlexeyKuznetsov-DD AlexeyKuznetsov-DD self-assigned this Aug 26, 2026
@datadog-official

datadog-official Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 59.09% (-0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 47ba511 | Docs | View more details | Give us feedback!

@pr-commenter

pr-commenter Bot commented Aug 26, 2026

Copy link
Copy Markdown

Debugger benchmarks

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
ci_job_date 1789592007 1789592334
end_time 2026-09-16T20:54:57 2026-09-16T21:00:24
git_branch master alexeyk/use-java-25
git_commit_sha 0e8becf 47ba511
start_time 2026-09-16T20:53:28 2026-09-16T20:58:54
See matching parameters
Baseline Candidate
ci_job_id 2051469863 2051469863
ci_pipeline_id 138010028 138010028
cpu_model Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz
git_commit_date 1789591290 1789591290

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 9 metrics, 6 unstable metrics.

See unchanged results
scenario Δ mean agg_http_req_duration_min Δ mean agg_http_req_duration_p50 Δ mean agg_http_req_duration_p75 Δ mean agg_http_req_duration_p99 Δ mean throughput
scenario:noprobe unstable
[-19.648µs; +59.915µs] or [-6.009%; +18.324%]
unstable
[-26.743µs; +82.724µs] or [-7.512%; +23.237%]
unstable
[-32.959µs; +92.630µs] or [-8.909%; +25.039%]
unstable
[-290.117µs; +526.541µs] or [-25.565%; +46.399%]
same
scenario:basic same same same unstable
[-110.296µs; +194.212µs] or [-11.111%; +19.564%]
unstable
[-162.228op/s; +162.228op/s] or [-7.300%; +7.300%]
scenario:loop same same same same same
Request duration reports for reports
gantt
    title reports - request duration [CI 0.99] : candidate=None, baseline=None
    dateFormat X
    axisFormat %s
section baseline
noprobe (356.007 µs) : 335, 377
.   : milestone, 356,
basic (339.82 µs) : 332, 347
.   : milestone, 340,
loop (8.127 ms) : 8057, 8196
.   : milestone, 8127,
section candidate
noprobe (383.998 µs) : 314, 454
.   : milestone, 384,
basic (344.054 µs) : 337, 351
.   : milestone, 344,
loop (8.124 ms) : 8060, 8188
.   : milestone, 8124,
Loading
  • baseline results
Scenario Request median duration [CI 0.99]
noprobe 356.007 µs [335.126 µs, 376.887 µs]
basic 339.82 µs [332.32 µs, 347.319 µs]
loop 8.127 ms [8.057 ms, 8.196 ms]
  • candidate results
Scenario Request median duration [CI 0.99]
noprobe 383.998 µs [313.536 µs, 454.459 µs]
basic 344.054 µs [337.128 µs, 350.979 µs]
loop 8.124 ms [8.06 ms, 8.188 ms]

@dd-octo-sts

dd-octo-sts Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.87 s 14.68 s [+0.5%; +2.1%] (maybe worse)
startup:insecure-bank:tracing:Agent 13.64 s 13.73 s [-1.5%; +0.2%] (no difference)
startup:petclinic:appsec:Agent 17.05 s 16.93 s [-0.2%; +1.5%] (no difference)
startup:petclinic:iast:Agent 16.93 s 17.06 s [-1.5%; +0.0%] (no difference)
startup:petclinic:profiling:Agent 16.66 s 16.55 s [-3.7%; +5.0%] (no difference)
startup:petclinic:sca:Agent 17.02 s 16.73 s [+0.8%; +2.6%] (maybe worse)
startup:petclinic:tracing:Agent 15.63 s 16.19 s [-7.6%; +0.6%] (no difference)

Commit: 47ba5112 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@pr-commenter

pr-commenter Bot commented Aug 26, 2026

Copy link
Copy Markdown

Kafka / producer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alexeyk/use-java-25
git_commit_date 1789576632 1789591290
git_commit_sha 0e8becf 47ba511
See matching parameters
Baseline Candidate
ci_job_date 1789592521 1789592521
ci_job_id 2051469860 2051469860
ci_pipeline_id 138010028 138010028
cpu_model Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz
jdkVersion 11.0.31 11.0.31
jmhVersion 1.36 1.36
jvm /usr/lib/jvm/java-11-openjdk-amd64/bin/java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
jvmArgs -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=15002 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=15002 -Dhttp.nonProxyHosts=localhost *.localhost
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-0-8q58mkpz 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-0-8q58mkpz 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 3 metrics, 0 unstable metrics.

See unchanged results
scenario Δ mean throughput
scenario:not-instrumented/KafkaProduceBenchmark.benchProduce same
scenario:only-tracing-dsm-disabled-benchmarks/KafkaProduceBenchmark.benchProduce unsure
[+350.170op/s; +6943.705op/s] or [+0.201%; +3.983%]
scenario:only-tracing-dsm-enabled-benchmarks/KafkaProduceBenchmark.benchProduce same

@pr-commenter

pr-commenter Bot commented Aug 26, 2026

Copy link
Copy Markdown

Kafka / consumer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alexeyk/use-java-25
git_commit_date 1789576632 1789591290
git_commit_sha 0e8becf 47ba511
See matching parameters
Baseline Candidate
ci_job_date 1789592576 1789592576
ci_job_id 2051469862 2051469862
ci_pipeline_id 138010028 138010028
cpu_model Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz
jdkVersion 11.0.31 11.0.31
jmhVersion 1.36 1.36
jvm /usr/lib/jvm/java-11-openjdk-amd64/bin/java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
jvmArgs -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=15002 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=15002 -Dhttp.nonProxyHosts=localhost *.localhost
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-0-4ye5hlle 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-0-4ye5hlle 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 3 metrics, 0 unstable metrics.

See unchanged results
scenario Δ mean throughput
scenario:not-instrumented/KafkaConsumerBenchmark.benchConsume same
scenario:only-tracing-dsm-disabled-benchmarks/KafkaConsumerBenchmark.benchConsume unsure
[+2367.039op/s; +14140.772op/s] or [+0.978%; +5.841%]
scenario:only-tracing-dsm-enabled-benchmarks/KafkaConsumerBenchmark.benchConsume same

@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD marked this pull request as ready for review September 11, 2026 20:05
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD requested a review from a team as a code owner September 11, 2026 20:05
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-11T20:13:27.507027Z 0d016ae Draft marked ready
🔒 Security Review Completed 2026-09-11T20:09:29.069677Z 0d016ae Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@bric3

bric3 commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

I'll be reviewing this tomorrow morning.

@bric3

bric3 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Compared the exact CI artifacts with the repository-pinned jardiff-cli:0.2.0:

Summary:

  • No classes were added or removed, and class-file versions are unchanged.
  • 90 classes differ. Most changes are compiler metadata, constant-pool/member ordering, or synthetic lambda numbering.
  • The only instruction-level differences are shown below.
Focused jardiff output
--- datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.class
+++ datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.class
@@ -48,22 +70,9 @@
-    ICONST_3
-    ANEWARRAY datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource
-    DUP
-    ICONST_0
-    GETSTATIC datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.ALLOCATE_DIRECT : Ldatadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource;
-    AASTORE
-    DUP
-    ICONST_1
-    GETSTATIC datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.MMAP : Ldatadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource;
-    AASTORE
-    DUP
-    ICONST_2
-    GETSTATIC datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.JNI : Ldatadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource;
-    AASTORE
+    INVOKESTATIC datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource.$values ()[Ldatadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSource;

--- inst/datadog/trace/instrumentation/kafka_clients38/TextMapExtractAdapter.classdata
+++ inst/datadog/trace/instrumentation/kafka_clients38/TextMapExtractAdapter.classdata
@@ -132,9 +132,9 @@
-    INVOKEVIRTUAL java/nio/ByteBuffer.flip ()Ljava/nio/ByteBuffer;
+    INVOKEVIRTUAL java/nio/ByteBuffer.flip ()Ljava/nio/Buffer;

--- inst/datadog/trace/instrumentation/springweb6/HandleMatchAdvice.classdata
+++ inst/datadog/trace/instrumentation/springweb6/HandleMatchAdvice.classdata
@@ -53,9 +53,9 @@
-    INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
+    INVOKEINTERFACE jakarta/servlet/http/HttpServletRequest.getClass ()Ljava/lang/Class; (itf)

--- inst/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.classdata
+++ inst/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.classdata
@@ -397,9 +404,9 @@
-    INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
+    INVOKEINTERFACE org/springframework/web/servlet/View.getClass ()Ljava/lang/Class; (itf)

All affected classes remain Java 8 bytecode:

  • The generated enum initialization moved into $values() without changing behavior.
  • ByteBuffer.flip(): Buffer is the Java 8-compatible descriptor.
  • The invokeinterface getClass() form is the expected JDK-8272715 output and is already handled by Muzzle.

Spring 6 itself requires Java 17, but that does not change the agent's Java 8 bytecode requirement. I found no additional actionable issue.

* @param unsetReleaseFlagReason If not blank, `--release` option will not be applied.
*/
def configureCompiler(AbstractCompile it, int toolchainVersion, JavaVersion compatibilityVersion = null, String unsetReleaseFlagReason = null) {
def configureCompiler(AbstractCompile it, int toolchainVersion, JavaVersion bytecodeVersion, String unsetReleaseFlagReason) {

@bric3 bric3 Sep 18, 2026

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.

suggestion: I would avoid passing 25 at every call site. It matches the Gradle daemon so in it's somewhat already configured.

I'm thinking about an overload or a default param, where only the bytecodeVersion is needed. Unless, exceptionally, the toolchainVersion is, and when it's not needed use the Gradle Daemon version via JavaLanguageVersion.current()?

This should keep the explicit toolchain version only for JDK 8/11/21 exceptions.

tasks.named("compileMain_java11Java", JavaCompile) {
configureCompiler(it, 11, JavaVersion.VERSION_1_8)
// Do not lift this offset: these JFR bootstrap classes run on Java 8 JFR backports.
configureCompiler(it, 25, JavaVersion.VERSION_1_8, "Uses jdk.jfr module (Java 11+) at Java 8 bytecode")

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.

suggestion: I would avoid repeating the java version if the gradle daemon matches. I.e. make that a default (with the gradle daemon jvm), and use exceptions where needed. See the configureCompiler discussion.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: tooling Build & Tooling tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants