Skip to content

GROOVY-10307: backport JMH benchmarks from master to Groovy 5#2494

Open
jamesfredley wants to merge 1 commit intoapache:GROOVY_5_0_Xfrom
jamesfredley:groovy-10307-jmh-benchmarks-groovy5
Open

GROOVY-10307: backport JMH benchmarks from master to Groovy 5#2494
jamesfredley wants to merge 1 commit intoapache:GROOVY_5_0_Xfrom
jamesfredley:groovy-10307-jmh-benchmarks-groovy5

Conversation

@jamesfredley
Copy link
Copy Markdown
Contributor

Summary

Backport JMH benchmarks for invokedynamic performance patterns and Grails-like workload simulations from master to the GROOVY_5_0_X branch, enabling performance comparison testing on Groovy 5. Companion to #2393 (which targets GROOVY_4_0_X).

The benchmark sources are taken from the latest master content (15+ follow-up fixes after the original GROOVY-10307 commit, including the SwitchPoint invalidation regression suite and Copilot review feedback).

Changes

New JMH benchmarks (16 files)

Core Groovy performance (org.apache.groovy.perf):

  • ClosureBench - closure creation, reuse, capture, delegation, nesting, currying, composition, trampoline, collection operations
  • GStringBench - GString interpolation, concatenation, lazy evaluation
  • GroovyIdiomBench - Groovy idioms (safe navigation, elvis, spread, with/tap, destructuring)
  • LoopsBench - for/while/each/times/upto loop patterns
  • MetaclassBench - dynamic method dispatch overhead with metaclass changes
  • MethodInvocationBench - method dispatch (instance, static, overloaded, polymorphic, interface, dynamic)
  • OperatorBench - operator overloading, comparisons, range operations
  • PropertyAccessBench - property get/set patterns (direct, dynamic, nested)
  • RunnerRegistryBench - GroovyRunnerRegistry iterator performance

Grails-like patterns (org.apache.groovy.perf.grails):

  • CallSiteInvalidationBench - SwitchPoint invalidation overhead for cross-type and same-type metaclass changes
  • CategoryBench - category usage patterns (single, nested, simultaneous, shadowing)
  • DynamicDispatchBench - methodMissing, propertyMissing, invokeMethod, ExpandoMetaClass injection
  • GrailsLikePatternsBench - composite patterns (service chains, controller actions, domain validation, config DSL, markup builder, full request cycle)
  • GrailsWorkloadBench - collection closure chains, spread operator, nested closure delegation, GString interpolation, project metrics aggregation
  • MetaclassChangeBench - metaclass modification impact (expando additions, replacements, multi-class cascade, burst/steady-state, closure dispatch)
  • MetaclassVariationBench - per-instance ExpandoMetaClass overhead (GORM domain class enhancement pattern)

Build changes

  • Updated org.apache.groovy-performance.gradle to support indy property for toggling invokedynamic mode in JMH compilation (-Pindy=true|false, defaults to true)
  • Added jmh task input tracking and jmhJar output configuration
  • Migrated the performance subproject from JUnit 4 to JUnit 5 (using versions.junit5 / versions.junit5Platform since GROOVY_5_0_X does not yet define junit6)
  • Updated DummyTest.groovy to use org.junit.jupiter.api.Test

CI workflows

  • groovy-jmh.yml - runs JMH benchmarks with invokedynamic enabled (matrix: bench, core, grails suites)
  • groovy-jmh-classic.yml - runs JMH benchmarks with classic (non-indy) bytecode

Groovy 5 compatibility adaptation

  • DynamicDispatchBench: moved DynamicFinder, DynamicProperties, and MethodInterceptor from static inner classes to package-level classes because Groovy 5 does not support methodMissing/propertyMissing on static inner classes (same adaptation as GROOVY-10307: backport JMH benchmarks from master to Groovy 4 #2393, since the compiler restriction applies to both Groovy 4 and Groovy 5; master allows this on Groovy 6).

Verification

  • ./gradlew :performance:jmhClasses (indy mode) - BUILD SUCCESSFUL
  • ./gradlew :performance:jmhClasses -Pindy=false (classic mode) - BUILD SUCCESSFUL
  • ./gradlew :performance:jmh -PbenchInclude=GroovyIdiomBench.elvis - 3 elvis benchmarks completed successfully producing valid JMH output
  • ./gradlew :performance:test - BUILD SUCCESSFUL (verifies the JUnit 5 migration)

Copilot AI review requested due to automatic review settings April 26, 2026 18:05
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Backports the GROOVY-10307 JMH benchmark suite (core Groovy + Grails-like patterns) onto the Groovy 5 branch and wires up build/CI support to run the benchmarks in indy vs classic mode for performance comparisons.

Changes:

  • Adds new JMH benchmarks under subprojects/performance/src/jmh/groovy covering invokedynamic/metaclass invalidation patterns and common Groovy idioms.
  • Updates the performance build logic to support -Pindy=true|false, JMH input tracking, and migrates the performance test setup from JUnit 4 to JUnit 5.
  • Adds GitHub Actions workflows to run the JMH suites in indy and classic modes.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
subprojects/performance/src/test/groovy/DummyTest.groovy Switches the placeholder test to JUnit Jupiter.
build-logic/src/main/groovy/org.apache.groovy-performance.gradle Adds JUnit 5 deps, indy toggle for JMH Groovy compilation, and JMH task input/output wiring.
.github/workflows/groovy-jmh.yml New CI workflow to run JMH suites with indy enabled and upload results.
.github/workflows/groovy-jmh-classic.yml New CI workflow to run JMH suites with indy disabled and upload results.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/ClosureBench.groovy Adds closure-focused microbenchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/GStringBench.groovy Adds GString creation/interpolation benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/GroovyIdiomBench.groovy Adds idiomatic Groovy feature benchmarks (safe-nav, elvis, spread, etc.).
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/LoopsBench.groovy Adds loop/iteration pattern benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/MetaclassBench.groovy Adds metaclass-change invalidation benchmark.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/MethodInvocationBench.groovy Adds method invocation/dispatch benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/OperatorBench.groovy Adds operator dispatch benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/PropertyAccessBench.groovy Adds property access pattern benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/RunnerRegistryBench.java Adds GroovyRunnerRegistry iterator benchmark.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/CallSiteInvalidationBench.groovy Adds SwitchPoint invalidation workload benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/CategoryBench.groovy Adds category-scope invalidation benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/DynamicDispatchBench.groovy Adds methodMissing/propertyMissing/invokeMethod dispatch benchmarks (Groovy 5-compatible layout).
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/GrailsLikePatternsBench.groovy Adds composite “Grails-like” pattern workloads.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/GrailsWorkloadBench.groovy Adds workload-style Grails demo-app pattern benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/MetaclassChangeBench.groovy Adds metaclass churn / invalidation cascade benchmarks.
subprojects/performance/src/jmh/groovy/org/apache/groovy/perf/grails/MetaclassVariationBench.groovy Adds per-instance ExpandoMetaClass variation benchmarks.

Comment thread .github/workflows/groovy-jmh-classic.yml Outdated
Comment thread build-logic/src/main/groovy/org.apache.groovy-performance.gradle
Comment thread .github/workflows/groovy-jmh.yml Outdated
Backport JMH benchmarks for invokedynamic performance patterns and Grails-like workload simulations from master to the GROOVY_5_0_X branch, enabling performance comparison testing on Groovy 5.

New benchmarks cover core Groovy performance (closures, GStrings, method invocation, operators, property access, loops, metaclass overhead) and Grails-specific patterns (call site invalidation, categories, dynamic dispatch, metaclass changes, per-instance metaclass variation, workload simulation, composite request-cycle patterns, and SwitchPoint invalidation).

Adapt DynamicDispatchBench for Groovy 5 compatibility: move classes using methodMissing/propertyMissing to package level since Groovy 5 does not support these on static inner classes.

Migrate the performance subproject from JUnit 4 to JUnit 5 (versions.junit5 / versions.junit5Platform) to match the JUnit setup used elsewhere on GROOVY_5_0_X. Update the performance gradle plugin to support indy/classic mode selection for JMH compilation. Add CI workflows for running JMH benchmarks in both indy and classic modes.

Assisted-by: claude-code:claude-4.6-opus
@jamesfredley jamesfredley force-pushed the groovy-10307-jmh-benchmarks-groovy5 branch from 91b08bb to b503135 Compare April 26, 2026 18:17
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.1396%. Comparing base (fb2164b) to head (b503135).

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                @@
##             GROOVY_5_0_X      #2494   +/-   ##
=================================================
  Coverage         67.1396%   67.1396%           
+ Complexity          29435      29434    -1     
=================================================
  Files                1382       1382           
  Lines              116797     116797           
  Branches            20481      20481           
=================================================
  Hits                78417      78417           
+ Misses              31889      31888    -1     
- Partials             6491       6492    +1     

see 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

3 participants