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

jonnybot pushed a commit to branch INDY-PERF-EXPLORATION
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 7d4eae31c66db413387bdd7f073732f8ecb14c5a
Author: Jonny Carter <[email protected]>
AuthorDate: Fri Feb 20 17:11:08 2026 -0600

    Simply split benchmark jobs in CI by class
---
 .github/workflows/groovy-performance.yml |  8 ++---
 subprojects/performance/build.gradle     | 53 ++++++++------------------------
 2 files changed, 16 insertions(+), 45 deletions(-)

diff --git a/.github/workflows/groovy-performance.yml 
b/.github/workflows/groovy-performance.yml
index ee9e2b64ed..350ad081f4 100644
--- a/.github/workflows/groovy-performance.yml
+++ b/.github/workflows/groovy-performance.yml
@@ -20,7 +20,7 @@ on:
   workflow_dispatch:
     inputs:
       benchmark_filter:
-        description: 'Filter by subpackage name (e.g., dispatch, orm, indy). 
Leave empty for all.'
+        description: 'Filter by benchmark class name (e.g., CallsiteBench, 
PropertyAccess). Leave empty for all.'
         required: false
         default: ''
       compare_baseline:
@@ -93,7 +93,7 @@ jobs:
     needs: build-jmh-jar
     if: github.event_name != 'pull_request'
     runs-on: ubuntu-latest
-    timeout-minutes: 60
+    timeout-minutes: 5
     strategy:
       fail-fast: false
       matrix: ${{ fromJson(needs.build-jmh-jar.outputs.matrix) }}
@@ -116,9 +116,9 @@ jobs:
             -Dgroovy.target.indy=${{ matrix.indy }} \
             -jar "$JAR" \
             "${{ matrix.pattern }}" \
-            -f 1 -wi 1 \
+            -f 3 -wi 3 -i 5 \
             -rf json -rff results.json
-        timeout-minutes: 45
+        timeout-minutes: 110
 
       - name: Upload results
         uses: actions/upload-artifact@v4
diff --git a/subprojects/performance/build.gradle 
b/subprojects/performance/build.gradle
index cdd4d067ef..a6a29445b9 100644
--- a/subprojects/performance/build.gradle
+++ b/subprojects/performance/build.gradle
@@ -34,9 +34,11 @@ performanceTests {
 
 def jmhResultsDir = layout.buildDirectory.dir("results/jmh")
 
-// ============================================================================
-// Threshold Parameter Sweep
-// ============================================================================
+jmh {
+    fork = 3
+    warmupIterations = 3
+    iterations = 5
+}
 
 // ============================================================================
 // Profiling Support
@@ -112,26 +114,18 @@ tasks.register('jmhGcProfile', JavaExec) {
 // ============================================================================
 
 /**
- * Discover all JMH benchmarks from the fat jar and group them by subpackage
- * into appropriately-sized chunks for parallel CI execution.
- *
- * Outputs build/jmh-groups.json — an array of {group, pattern} objects.
+ * Discover all JMH benchmarks from the fat jar and produce one group per
+ * benchmark class. Outputs build/jmh-groups.json for CI matrix generation.
  */
 tasks.register('jmhGroups') {
     group = 'benchmark'
-    description = 'Discover JMH benchmarks and output groups as JSON for CI 
matrix'
+    description = 'Discover JMH benchmark classes and output groups as JSON 
for CI matrix'
     dependsOn 'jmhJar'
 
     def outputFile = layout.buildDirectory.file("jmh-groups.json")
     outputs.file(outputFile)
 
     doLast {
-        // Time estimate: 1 fork × (1 warmup @10s + 1 iteration @10s) + ~5s 
overhead
-        def secondsPerMethod = 25
-        def maxSecondsPerJob = 600 // 10-minute target
-        def maxPerGroup = (maxSecondsPerJob / secondsPerMethod)
-
-        // List all benchmarks from the fat jar
         def benchmarks = providers.javaexec {
             mainClass = 'org.openjdk.jmh.Main'
             classpath = files(tasks.named('jmhJar'))
@@ -140,33 +134,10 @@ tasks.register('jmhGroups') {
             .collect { it.trim() }
             .findAll { it.startsWith('org.apache.groovy.') }
 
-        // Group by subpackage: bench.dispatch.* → "dispatch", bench.Foo → 
"core", plugin.* → "plugin"
-        def groups = benchmarks.groupBy { fqcn ->
-            def parts = (fqcn - 'org.apache.groovy.').split('\\.')
-            parts[0] == 'bench' ? (parts.length >= 4 ? parts[1] : 'core') : 
parts[0]
-        }.sort()
-
-        // Build entries, splitting large groups into right-sized chunks by 
class
-        def entries = groups.collectMany { name, methods ->
-            if (methods.size() <= maxPerGroup) {
-                def pattern = name == 'core'
-                    ? ".*(" + methods.collect { it.split('\\.')[-2] 
}.unique().sort().join('|') + ").*"
-                    : ".*\\.${name}\\..*"
-                return [[group: name, pattern: pattern, benchmarks: 
methods.size()]]
-            }
-            methods.groupBy { it.split('\\.')[-2] }.sort()
-                .inject([[classes: [], count: 0]]) { chunks, cls, meths ->
-                    def last = chunks.last()
-                    if (last.count + meths.size() > maxPerGroup && 
last.classes) {
-                        chunks << [classes: [cls], count: meths.size()]
-                    } else {
-                        last.classes << cls
-                        last.count += meths.size()
-                        chunks
-                    }
-                }.withIndex(1).collect { chunk, i ->
-                    [group: "${name}-${i}", pattern: ".*(" + 
chunk.classes.join('|') + ").*", benchmarks: chunk.count]
-                }
+        // One group per benchmark class: 
"org.apache.groovy.bench.orm.PropertyAccessBench.method" → "PropertyAccessBench"
+        def entries = benchmarks.groupBy { it[0..it.lastIndexOf('.') - 1] 
}.sort().collect { fqcn, methods ->
+            def className = fqcn[fqcn.lastIndexOf('.') + 1..-1]
+            [group: className, pattern: "${fqcn}.*", benchmarks: 
methods.size()]
         }
 
         def json = 
groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(entries))

Reply via email to