You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/06/02 03:54:43 UTC

(groovy) 01/01: GROOVY-12034: Apply "fat-free lambda" patterns to Groovy (fix graphs and build warnings)

This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch fatFreeSpike
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 415e86e47d18579337ed3d02ca9122407992bfef
Author: Paul King <pa...@asert.com.au>
AuthorDate: Tue Jun 2 13:54:29 2026 +1000

    GROOVY-12034: Apply "fat-free lambda" patterns to Groovy (fix graphs and build warnings)
---
 .../main/groovy/org.apache.groovy-performance.gradle   | 18 +++++++++++++++++-
 .../performance/dashboard/jmh-adhoc-summary.html       | 14 +++++++++++---
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/build-logic/src/main/groovy/org.apache.groovy-performance.gradle b/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
index b57422bed4..1a9456b844 100644
--- a/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
+++ b/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
@@ -42,7 +42,12 @@ repositories {
 }
 
 dependencies {
-    jmh project(':')
+    // Use jmhImplementation (not the bare `jmh` bucket): the jmh compile/runtime
+    // classpaths carry the full attribute set, so Gradle selects the shaded
+    // (jarjar) Groovy variant. The bare `jmh` configuration under-specifies
+    // attributes and falls back to the un-shaded *raw* variant, which put a second
+    // Groovy jar (plus duplicate asm/antlr) on the jmh classpath.
+    jmhImplementation project(':')
     testImplementation project(':')
     testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit6}"
     testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit6}"
@@ -102,6 +107,17 @@ tasks.named('test') {
 tasks.named('jmh') {
     inputs.property('benchInclude', project.findProperty('benchInclude') ?: '')
     dependsOn tasks.named('jmhClasses')
+    // me.champeau.jmh builds a self-contained uber jar (the jmhJar artifact) and
+    // then runs benchmarks with a classpath of: the `jmh` configuration + that
+    // uber jar + the test runtime classpath. That puts Groovy core on the run
+    // classpath three times — the `jmh` config even resolves the un-shaded *raw*
+    // Groovy variant (dragging duplicate asm/antlr) — which trips
+    // MetaClassRegistryImpl's "duplicate concurrent module" warning. The uber jar
+    // already contains everything needed to run, so clear the two loose
+    // collections and let it be the single source: every class (Groovy included)
+    // then appears exactly once.
+    jmhClasspath.setFrom()
+    testRuntimeClasspath.setFrom()
 }
 
 tasks.named('jmhJar') {
diff --git a/subprojects/performance/dashboard/jmh-adhoc-summary.html b/subprojects/performance/dashboard/jmh-adhoc-summary.html
index 912b7920eb..9e4e8065ba 100644
--- a/subprojects/performance/dashboard/jmh-adhoc-summary.html
+++ b/subprojects/performance/dashboard/jmh-adhoc-summary.html
@@ -134,10 +134,18 @@
 
   // "findAllG_lambdasCurryWith (size=10000)" -> {family, variant, size}
   // NB: findAll must precede find in the alternation so it wins the match.
+  // Two name shapes reach us, depending on which github-action-benchmark tool
+  // produced the series:
+  //   alloc (customSmallerIsBetter): "findAllG_lambdasCurryWith (size=10000)"
+  //   throughput (jmh tool):         'org.apache.groovy.adhoc.FatFreeLambdaBench.findAllG_lambdasCurryWith ( {"size":"10000"} )'
+  // Pull the method token (findAll/find/count + variant) and the size wherever
+  // they appear, instead of anchoring on one exact layout. NB: findAll must
+  // precede find in the alternation so it wins the match.
   function parseName(name) {
-    const m = name.match(/^(findAll|find|count)([^ ]+?)\s*\(size=(\d+)\)\s*$/);
-    if (!m) return null;
-    return { family: m[1], variant: m[2].replace(/^_/, ''), size: m[3] };
+    const fam = name.match(/(findAll|find|count)([A-Za-z0-9_]+)/);
+    const sz = name.match(/size["'\s:=]*?(\d+)/);
+    if (!fam || !sz) return null;
+    return { family: fam[1], variant: fam[2].replace(/^_/, ''), size: sz[1] };
   }
 
   // Shape a bench list into { variants:[...], bySize:{size:{variant:value}} } for one family.