diff --git a/.github/workflows/perf-compare-v550.yml b/.github/workflows/perf-compare-v550.yml new file mode 100644 index 0000000..f6705b7 --- /dev/null +++ b/.github/workflows/perf-compare-v550.yml @@ -0,0 +1,241 @@ +name: 'Performance: setup-java v5.5.0 (CommonJS) vs main (ESM)' + +# Head-to-head performance comparison of setup-java between the last CommonJS +# release (v5.5.0) and the current `main` (which is now ESM + refreshed deps and +# cache/logging enhancements). The two versions run an IDENTICAL scenario; the +# ONLY difference is the pinned setup-java commit: +# - v5.5.0 -> commit 0f481fc (package.json has NO "type", i.e. CommonJS) +# - main -> commit f848fd1 (v6.0.0, "type": "module", i.e. ESM) +# Both declare `using: node24`, so this isolates the effect of the ESM rewrite, +# dependency bumps, and cache handling on real setup time. +# +# What we measure, per OS and per version: +# * setup_ms - wall-clock time of the `setup-java` step (node startup + +# JDK provisioning from the runner tool-cache + build-tool cache +# restore). Bracketed with Date.now() from the runner's node so +# it is portable across Ubuntu / Windows / macOS. +# * cache_hit - the action's `cache-hit` output for the Maven (~/.m2) cache. +# * m2_kb - size of ~/.m2/repository after the build (cache footprint). +# +# Two phases make the cache behavior observable in a single run: +# * COLD - build-tool cache is guaranteed empty (the cache key embeds the run +# id), so setup-java restores nothing and SAVES the cache in post. +# * WARM - `needs: cold`, so the cache saved by COLD is now present and +# setup-java restores it (cache-hit=true). WARM vs COLD shows the +# restore cost/benefit; v5.5.0 vs main shows the version delta. +# +# Temurin 21 is used on purpose: it is pre-provisioned in the runner tool-cache +# on all three OSes, so JDK "download" is a low-variance local copy and the +# timing reflects the action's own overhead + caching rather than network noise. + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + cold: + name: 'COLD ${{ matrix.ref.name }} (${{ matrix.os }})' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + ref: + - { name: 'v5.5.0 (CommonJS)', slug: 'v550', module: 'CommonJS' } + - { name: 'main (ESM)', slug: 'main', module: 'ESM' } + steps: + - uses: actions/checkout@v4 + + - name: Materialize per-run Maven project (unique, empty cache key) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + # Embed version + run id in the pom so the setup-java cache key is + # unique to THIS run and version -> COLD is a guaranteed miss and the + # matching WARM job (same content) restores exactly this cache. + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + + - name: 'setup-java v5.5.0 (CommonJS)' + id: setup_v550 + if: matrix.ref.slug == 'v550' + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: 'setup-java main (ESM)' + id: setup_main + if: matrix.ref.slug == 'main' + uses: actions/setup-java@f848fd197658fa2ff5c91f2c1823db7aed8b0519 # main (ESM) + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: Measure setup time and cache-hit + id: measure + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + HIT="${{ steps.setup_v550.outputs.cache-hit }}${{ steps.setup_main.outputs.cache-hit }}" + echo "setup_ms=$DUR" >> "$GITHUB_OUTPUT" + echo "cache_hit=$HIT" >> "$GITHUB_OUTPUT" + echo "COLD ${{ matrix.ref.name }} on ${{ matrix.os }}: setup=${DUR}ms cache-hit='${HIT}'" + + - name: Build (populates the Maven cache that WARM will restore) + shell: bash + run: mvn -B -ntp -f proj/pom.xml compile + + - name: Collect metrics + shell: bash + run: | + set -uo pipefail + if [ -d "$HOME/.m2/repository" ]; then M2=$(du -sk "$HOME/.m2/repository" | cut -f1); else M2=0; fi + cat > metric.json < cache hit) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + + - name: 'setup-java v5.5.0 (CommonJS)' + id: setup_v550 + if: matrix.ref.slug == 'v550' + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: 'setup-java main (ESM)' + id: setup_main + if: matrix.ref.slug == 'main' + uses: actions/setup-java@f848fd197658fa2ff5c91f2c1823db7aed8b0519 # main (ESM) + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: Measure setup time and cache-hit + id: measure + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + HIT="${{ steps.setup_v550.outputs.cache-hit }}${{ steps.setup_main.outputs.cache-hit }}" + echo "setup_ms=$DUR" >> "$GITHUB_OUTPUT" + echo "cache_hit=$HIT" >> "$GITHUB_OUTPUT" + echo "WARM ${{ matrix.ref.name }} on ${{ matrix.os }}: setup=${DUR}ms cache-hit='${HIT}'" + + - name: Collect metrics + shell: bash + run: | + set -uo pipefail + if [ -d "$HOME/.m2/repository" ]; then M2=$(du -sk "$HOME/.m2/repository" | cut -f1); else M2=0; fi + cat > metric.json < all.json + echo "Collected $(jq 'length' all.json) data points" + + { + echo "## setup-java performance: v5.5.0 (CommonJS) vs main (ESM)" + echo "" + echo "Identical scenario (Temurin 21 + Maven build). \`setup_ms\` is the" + echo "wall-clock time of the \`setup-java\` step. COLD = empty build-tool" + echo "cache (miss + save); WARM = cache restored (hit)." + echo "" + echo "### Raw measurements" + echo "" + echo "| OS | setup-java | module | phase | setup (ms) | cache-hit | .m2 (KB) |" + echo "|----|-----------|--------|-------|-----------:|-----------|---------:|" + jq -r 'sort_by(.os, .version, .phase)[] | "| \(.os) | \(.version) | \(.module) | \(.phase) | \(.setup_ms) | \(.cache_hit // "") | \(.m2_kb) |"' all.json + echo "" + echo "### v5.5.0 vs main (same OS + phase)" + echo "" + echo "| OS | phase | v5.5.0 (ms) | main (ms) | main − v5.5.0 (ms) |" + echo "|----|-------|------------:|----------:|-------------------:|" + jq -r ' + group_by(.os + "|" + .phase)[] + | { os: .[0].os, phase: .[0].phase, + v550: (map(select(.module=="CommonJS"))[0].setup_ms), + main: (map(select(.module=="ESM"))[0].setup_ms) } + | select(.v550 != null and .main != null) + | "| \(.os) | \(.phase) | \(.v550) | \(.main) | \(.main - .v550) |" + ' all.json + echo "" + echo "> Timings include ~sub-second inter-step runner overhead and vary" + echo "> run-to-run; re-run a few times or read the trend across OSes." + } >> "$GITHUB_STEP_SUMMARY" + + echo "----- raw -----" + cat all.json | jq -c '.[]' diff --git a/.github/workflows/perf-compare.yml b/.github/workflows/perf-compare.yml new file mode 100644 index 0000000..a65d41b --- /dev/null +++ b/.github/workflows/perf-compare.yml @@ -0,0 +1,241 @@ +name: 'Performance: setup-java v5.3.0 (CommonJS) vs main (ESM)' + +# Head-to-head performance comparison of setup-java between the last CommonJS +# release (v5.3.0) and the current `main` (which is now ESM + refreshed deps and +# cache/logging enhancements). The two versions run an IDENTICAL scenario; the +# ONLY difference is the pinned setup-java commit: +# - v5.3.0 -> commit ad2b381 (package.json has NO "type", i.e. CommonJS) +# - main -> commit fe9b749 ("type": "module", i.e. ESM) +# Both declare `using: node24`, so this isolates the effect of the ESM rewrite, +# dependency bumps, and cache handling on real setup time. +# +# What we measure, per OS and per version: +# * setup_ms - wall-clock time of the `setup-java` step (node startup + +# JDK provisioning from the runner tool-cache + build-tool cache +# restore). Bracketed with Date.now() from the runner's node so +# it is portable across Ubuntu / Windows / macOS. +# * cache_hit - the action's `cache-hit` output for the Maven (~/.m2) cache. +# * m2_kb - size of ~/.m2/repository after the build (cache footprint). +# +# Two phases make the cache behavior observable in a single run: +# * COLD - build-tool cache is guaranteed empty (the cache key embeds the run +# id), so setup-java restores nothing and SAVES the cache in post. +# * WARM - `needs: cold`, so the cache saved by COLD is now present and +# setup-java restores it (cache-hit=true). WARM vs COLD shows the +# restore cost/benefit; v5.3.0 vs main shows the version delta. +# +# Temurin 21 is used on purpose: it is pre-provisioned in the runner tool-cache +# on all three OSes, so JDK "download" is a low-variance local copy and the +# timing reflects the action's own overhead + caching rather than network noise. + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + cold: + name: 'COLD ${{ matrix.ref.name }} (${{ matrix.os }})' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + ref: + - { name: 'v5.3.0 (CommonJS)', slug: 'v530', module: 'CommonJS' } + - { name: 'main (ESM)', slug: 'main', module: 'ESM' } + steps: + - uses: actions/checkout@v4 + + - name: Materialize per-run Maven project (unique, empty cache key) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + # Embed version + run id in the pom so the setup-java cache key is + # unique to THIS run and version -> COLD is a guaranteed miss and the + # matching WARM job (same content) restores exactly this cache. + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + + - name: 'setup-java v5.3.0 (CommonJS)' + id: setup_v530 + if: matrix.ref.slug == 'v530' + uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: 'setup-java main (ESM)' + id: setup_main + if: matrix.ref.slug == 'main' + uses: actions/setup-java@fe9b749bcb36d9ac2a6c2cb1737d49b80e57ea06 # main (ESM) + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: Measure setup time and cache-hit + id: measure + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + HIT="${{ steps.setup_v530.outputs.cache-hit }}${{ steps.setup_main.outputs.cache-hit }}" + echo "setup_ms=$DUR" >> "$GITHUB_OUTPUT" + echo "cache_hit=$HIT" >> "$GITHUB_OUTPUT" + echo "COLD ${{ matrix.ref.name }} on ${{ matrix.os }}: setup=${DUR}ms cache-hit='${HIT}'" + + - name: Build (populates the Maven cache that WARM will restore) + shell: bash + run: mvn -B -ntp -f proj/pom.xml compile + + - name: Collect metrics + shell: bash + run: | + set -uo pipefail + if [ -d "$HOME/.m2/repository" ]; then M2=$(du -sk "$HOME/.m2/repository" | cut -f1); else M2=0; fi + cat > metric.json < cache hit) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + + - name: 'setup-java v5.3.0 (CommonJS)' + id: setup_v530 + if: matrix.ref.slug == 'v530' + uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: 'setup-java main (ESM)' + id: setup_main + if: matrix.ref.slug == 'main' + uses: actions/setup-java@fe9b749bcb36d9ac2a6c2cb1737d49b80e57ea06 # main (ESM) + with: + distribution: temurin + java-version: '21' + cache: maven + cache-dependency-path: proj/pom.xml + + - name: Measure setup time and cache-hit + id: measure + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + HIT="${{ steps.setup_v530.outputs.cache-hit }}${{ steps.setup_main.outputs.cache-hit }}" + echo "setup_ms=$DUR" >> "$GITHUB_OUTPUT" + echo "cache_hit=$HIT" >> "$GITHUB_OUTPUT" + echo "WARM ${{ matrix.ref.name }} on ${{ matrix.os }}: setup=${DUR}ms cache-hit='${HIT}'" + + - name: Collect metrics + shell: bash + run: | + set -uo pipefail + if [ -d "$HOME/.m2/repository" ]; then M2=$(du -sk "$HOME/.m2/repository" | cut -f1); else M2=0; fi + cat > metric.json < all.json + echo "Collected $(jq 'length' all.json) data points" + + { + echo "## setup-java performance: v5.3.0 (CommonJS) vs main (ESM)" + echo "" + echo "Identical scenario (Temurin 21 + Maven build). \`setup_ms\` is the" + echo "wall-clock time of the \`setup-java\` step. COLD = empty build-tool" + echo "cache (miss + save); WARM = cache restored (hit)." + echo "" + echo "### Raw measurements" + echo "" + echo "| OS | setup-java | module | phase | setup (ms) | cache-hit | .m2 (KB) |" + echo "|----|-----------|--------|-------|-----------:|-----------|---------:|" + jq -r 'sort_by(.os, .version, .phase)[] | "| \(.os) | \(.version) | \(.module) | \(.phase) | \(.setup_ms) | \(.cache_hit // "") | \(.m2_kb) |"' all.json + echo "" + echo "### v5.3.0 vs main (same OS + phase)" + echo "" + echo "| OS | phase | v5.3.0 (ms) | main (ms) | main − v5.3.0 (ms) |" + echo "|----|-------|------------:|----------:|-------------------:|" + jq -r ' + group_by(.os + "|" + .phase)[] + | { os: .[0].os, phase: .[0].phase, + v530: (map(select(.module=="CommonJS"))[0].setup_ms), + main: (map(select(.module=="ESM"))[0].setup_ms) } + | select(.v530 != null and .main != null) + | "| \(.os) | \(.phase) | \(.v530) | \(.main) | \(.main - .v530) |" + ' all.json + echo "" + echo "> Timings include ~sub-second inter-step runner overhead and vary" + echo "> run-to-run; re-run a few times or read the trend across OSes." + } >> "$GITHUB_STEP_SUMMARY" + + echo "----- raw -----" + cat all.json | jq -c '.[]' diff --git a/.github/workflows/perf-troubleshoot.yml b/.github/workflows/perf-troubleshoot.yml new file mode 100644 index 0000000..6a7200d --- /dev/null +++ b/.github/workflows/perf-troubleshoot.yml @@ -0,0 +1,209 @@ +name: 'Perf troubleshoot: warm-restore breakdown (v5.5.0 vs main)' + +# Diagnostic workflow to explain WHY the `setup-java` warm phase looked slower +# under `main` (ESM v6.0.0) on Windows/macOS in the headline comparison. +# +# The headline `setup_ms` times the ENTIRE setup-java step, which bundles three +# things: Node/ESM bootstrap -> JDK resolve (tool-cache) -> Maven cache +# restore (download + tar/zstd extract). This workflow decomposes that black box +# so we can attribute any version delta to a specific phase: +# +# T_nocache = setup-java with `cache:` OMITTED -> bootstrap + JDK only +# T_warm = setup-java with `cache: maven` and the cache pre-seeded (hit) +# T_restore = T_warm - T_nocache -> the cache-restore cost +# +# If the ESM slowdown lives in T_nocache, it is Node/ESM startup (a fixed cost +# most visible where the rest is fast). If it lives in T_restore, it implicates +# the @actions/cache dependency bump in v6.0.0 (tar/zstd/download behavior). +# +# The `warm` jobs run with ACTIONS_STEP_DEBUG=true so the action emits timestamped +# cache internals (resolved keys, "Cache Size", download, extract). The compare +# job pulls the raw job logs and slices the setup-java step so download-vs-extract +# is visible, especially on Windows (BSD tar / zstd). +# +# Pins (both `using: node24`, so runtime is constant): +# v5.5.0 -> 0f481fc (CommonJS, no package.json "type") +# main -> f848fd1 (ESM, "type": "module", v6.0.0) +# +# Dispatch this several times (it is re-run safe: the cache key embeds the run id) +# and read medians in the compare summary to beat hosted-runner variance. + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + # ---- seed: populate the Maven cache that the matching warm job restores ---- + seed: + name: 'SEED ${{ matrix.ref.name }} (${{ matrix.os }})' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + ref: + - { name: 'v5.5.0 (CommonJS)', slug: 'v550', module: 'CommonJS' } + - { name: 'main (ESM)', slug: 'main', module: 'ESM' } + steps: + - uses: actions/checkout@v4 + - name: Materialize per-run project (unique, shared with warm) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + - name: 'setup-java v5.5.0 (CommonJS)' + if: matrix.ref.slug == 'v550' + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 + with: { distribution: temurin, java-version: '21', cache: maven, cache-dependency-path: proj/pom.xml } + - name: 'setup-java main (ESM)' + if: matrix.ref.slug == 'main' + uses: actions/setup-java@f848fd197658fa2ff5c91f2c1823db7aed8b0519 # main (ESM) + with: { distribution: temurin, java-version: '21', cache: maven, cache-dependency-path: proj/pom.xml } + - name: Build to populate ~/.m2 (saved by the cache post-step) + shell: bash + run: mvn -B -ntp -f proj/pom.xml compile + + # ---- nocache: setup-java WITHOUT cache -> bootstrap + JDK only ---- + nocache: + name: 'NOCACHE ${{ matrix.ref.name }} (${{ matrix.os }})' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + ref: + - { name: 'v5.5.0 (CommonJS)', slug: 'v550', module: 'CommonJS' } + - { name: 'main (ESM)', slug: 'main', module: 'ESM' } + steps: + - uses: actions/checkout@v4 + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + - name: 'setup-java v5.5.0 (CommonJS) - no cache' + if: matrix.ref.slug == 'v550' + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 + with: { distribution: temurin, java-version: '21' } + - name: 'setup-java main (ESM) - no cache' + if: matrix.ref.slug == 'main' + uses: actions/setup-java@f848fd197658fa2ff5c91f2c1823db7aed8b0519 # main (ESM) + with: { distribution: temurin, java-version: '21' } + - name: Record T_nocache + id: m + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + echo "nocache ${{ matrix.ref.name }} on ${{ matrix.os }}: ${DUR}ms" + cat > metric.json < measures restore, with step-debug on ---- + warm: + name: 'WARM ${{ matrix.ref.name }} (${{ matrix.os }})' + needs: seed + runs-on: ${{ matrix.os }} + env: + ACTIONS_STEP_DEBUG: 'true' + ACTIONS_RUNNER_DEBUG: 'true' + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + ref: + - { name: 'v5.5.0 (CommonJS)', slug: 'v550', module: 'CommonJS' } + - { name: 'main (ESM)', slug: 'main', module: 'ESM' } + steps: + - uses: actions/checkout@v4 + - name: Materialize per-run project (same key as SEED -> cache hit) + shell: bash + run: | + set -euo pipefail + rm -rf proj && cp -r maven-sample-project proj + node -e "const fs=require('fs');const p='proj/pom.xml';let s=fs.readFileSync(p,'utf8');s=s.replace('',' \n');fs.writeFileSync(p,s)" + - name: Mark setup start + shell: bash + run: echo "T0=$(node -p 'Date.now()')" >> "$GITHUB_ENV" + - name: 'setup-java v5.5.0 (CommonJS) - warm' + id: setup_v550 + if: matrix.ref.slug == 'v550' + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 + with: { distribution: temurin, java-version: '21', cache: maven, cache-dependency-path: proj/pom.xml } + - name: 'setup-java main (ESM) - warm' + id: setup_main + if: matrix.ref.slug == 'main' + uses: actions/setup-java@f848fd197658fa2ff5c91f2c1823db7aed8b0519 # main (ESM) + with: { distribution: temurin, java-version: '21', cache: maven, cache-dependency-path: proj/pom.xml } + - name: Record T_warm + id: m + shell: bash + run: | + set -uo pipefail + DUR=$(( $(node -p 'Date.now()') - T0 )) + HIT="${{ steps.setup_v550.outputs.cache-hit }}${{ steps.setup_main.outputs.cache-hit }}" + echo "warm ${{ matrix.ref.name }} on ${{ matrix.os }}: ${DUR}ms hit='${HIT}'" + cat > metric.json < all.json + echo "points: $(jq 'length' all.json)" + { + echo "## Warm-restore breakdown: v5.5.0 (CJS) vs main (ESM v6.0.0)" + echo "" + echo "\`T_restore = T_warm - T_nocache\`. If a version delta lives in" + echo "**nocache**, it is Node/ESM bootstrap + JDK; if in **restore**, it is" + echo "the @actions/cache path (download + tar/zstd extract)." + echo "" + echo "| OS | version | T_nocache (ms) | T_warm (ms) | T_restore (ms) |" + echo "|----|---------|---------------:|------------:|---------------:|" + jq -r ' + group_by(.os + "|" + .version)[] + | { os: .[0].os, version: .[0].version, + nc: (map(select(.phase=="nocache").setup_ms)|add/length|floor), + wm: (map(select(.phase=="warm").setup_ms)|add/length|floor) } + | "| \(.os) | \(.version) | \(.nc) | \(.wm) | \(.wm - .nc) |" + ' all.json | sort + echo "" + echo "### main − v5.5.0 per phase" + echo "" + echo "| OS | Δ nocache | Δ restore |" + echo "|----|----------:|----------:|" + jq -r ' + group_by(.os)[] + | .[0].os as $os + | ( [.[]|select(.version|startswith("v5.5.0"))] ) as $v + | ( [.[]|select(.version|startswith("main"))] ) as $m + | ( ($v|map(select(.phase=="nocache").setup_ms)|add/length) ) as $vnc + | ( ($m|map(select(.phase=="nocache").setup_ms)|add/length) ) as $mnc + | ( ($v|map(select(.phase=="warm").setup_ms)|add/length) ) as $vwm + | ( ($m|map(select(.phase=="warm").setup_ms)|add/length) ) as $mwm + | "| \($os) | \(($mnc-$vnc)|floor) | \((($mwm-$mnc)-($vwm-$vnc))|floor) |" + ' all.json | sort + } >> "$GITHUB_STEP_SUMMARY" + echo "----- raw -----" + jq -c '.[]' all.json