Skip to content

Commit 6a31630

Browse files
committed
Update github actions to better pick AVX-512 runner
1 parent f78bfab commit 6a31630

2 files changed

Lines changed: 193 additions & 17 deletions

File tree

.github/workflows/coverage-pages.yml

Lines changed: 182 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,96 @@ on:
55
branches:
66
- master
77
workflow_dispatch:
8+
inputs:
9+
round:
10+
description: "AVX-512 runner allocation round (1-4)"
11+
required: false
12+
default: "1"
13+
type: string
14+
root_run_id:
15+
description: "Internal identifier shared by one retry chain"
16+
required: false
17+
default: ""
18+
type: string
819

920
concurrency:
10-
group: pages
11-
cancel-in-progress: true
21+
group: coverage-pages-${{ github.ref }}-${{ inputs.root_run_id || github.run_id }}
22+
cancel-in-progress: false
1223

1324
permissions:
25+
actions: write
1426
contents: read
1527
pages: write
1628
id-token: write
1729

1830
jobs:
1931
report:
20-
name: Build, test, and render report
32+
name: AVX-512 attempt ${{ inputs.round || '1' }}/4 (${{ matrix.runner }})
2133
runs-on: ubuntu-26.04
22-
outputs:
23-
ctest_status: ${{ steps.tests.outputs.status }}
34+
strategy:
35+
fail-fast: false
36+
max-parallel: 4
37+
matrix:
38+
runner: [1, 2, 3, 4]
39+
env:
40+
ATTEMPT_ROUND: ${{ inputs.round || '1' }}
2441
steps:
25-
- name: Ensure CPU support
42+
- name: Check for AVX-512 VNNI support
43+
id: cpu
2644
run: |
27-
if grep -q "avx512f" /proc/cpuinfo; then
45+
required_flag=avx512_vnni
46+
if grep -qw "$required_flag" /proc/cpuinfo; then
47+
# Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
48+
# AMD EPYC 9V74 80-Core Processor
49+
echo "Found required CPU flag: $required_flag"
50+
echo "host_hit=true" >> "$GITHUB_OUTPUT"
2851
lscpu
2952
else
30-
echo "CPU not supporting AVX-512"
53+
# AMD EPYC 7763 64-Core Processor
54+
# AMD EPYC 9V74 80-Core Processor
55+
echo "CPU does not expose required CPU flag: $required_flag"
56+
echo "host_hit=false" >> "$GITHUB_OUTPUT"
3157
lscpu
32-
exit 1
3358
fi
3459
3560
- name: Check out repository
61+
if: steps.cpu.outputs.host_hit == 'true'
3662
uses: actions/checkout@v7
3763
with:
3864
fetch-depth: 0
3965
submodules: recursive
4066

4167
- name: Set up Python
68+
if: steps.cpu.outputs.host_hit == 'true'
4269
uses: actions/setup-python@v6
4370
with:
4471
python-version: "3.14"
4572

4673
- name: Install gcovr
74+
if: steps.cpu.outputs.host_hit == 'true'
4775
run: python -m pip install --disable-pip-version-check --no-cache-dir gcovr==8.6
4876

4977
- name: Configure GCC coverage build
78+
if: steps.cpu.outputs.host_hit == 'true'
5079
run: cmake --preset gcc-coverage
5180

5281
- name: Build test suite
82+
if: steps.cpu.outputs.host_hit == 'true'
5383
run: cmake --build --preset gcc-coverage --parallel 2
5484

5585
- name: Clear old coverage counters
86+
if: steps.cpu.outputs.host_hit == 'true'
5687
run: find "$GITHUB_WORKSPACE/build/gcc-coverage" -name '*.gcda' -delete
5788

5889
- name: Seed zero-count AvsCore coverage data
59-
run: "$GITHUB_WORKSPACE/build/gcc-coverage/tests/coverage/avs_coverage_inventory"
90+
if: steps.cpu.outputs.host_hit == 'true'
91+
shell: bash
92+
run: |
93+
"$GITHUB_WORKSPACE/build/gcc-coverage/tests/coverage/avs_coverage_inventory"
6094
6195
- name: Run CTest
6296
id: tests
97+
if: steps.cpu.outputs.host_hit == 'true'
6398
shell: bash
6499
run: |
65100
set +e
@@ -74,6 +109,7 @@ jobs:
74109
printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT"
75110
76111
- name: Generate full AvsCore coverage report
112+
if: steps.cpu.outputs.host_hit == 'true'
77113
run: |
78114
mkdir -p site/coverage site/data
79115
gcovr \
@@ -86,6 +122,7 @@ jobs:
86122
"$GITHUB_WORKSPACE/build/gcc-coverage"
87123
88124
- name: Render latest-result dashboard
125+
if: steps.cpu.outputs.host_hit == 'true'
89126
env:
90127
TEST_STATUS: ${{ steps.tests.outputs.status }}
91128
run: |
@@ -100,17 +137,150 @@ jobs:
100137
--upstream-sha "$upstream_sha" \
101138
--run-url "https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
102139
140+
- name: Record attempt result
141+
if: always()
142+
shell: bash
143+
env:
144+
HOST_HIT: ${{ steps.cpu.outputs.host_hit }}
145+
TEST_STATUS: ${{ steps.tests.outputs.status }}
146+
RUNNER_SLOT: ${{ matrix.runner }}
147+
run: |
148+
set -euo pipefail
149+
mkdir -p attempt
150+
host_hit="${HOST_HIT:-false}"
151+
report_ready=false
152+
if [ "$host_hit" = "true" ] && [ -f site/index.html ]; then
153+
cp -a site attempt/site
154+
report_ready=true
155+
fi
156+
{
157+
printf 'round=%s\n' "$ATTEMPT_ROUND"
158+
printf 'runner_slot=%s\n' "$RUNNER_SLOT"
159+
printf 'host_hit=%s\n' "$host_hit"
160+
printf 'report_ready=%s\n' "$report_ready"
161+
printf 'ctest_status=%s\n' "${TEST_STATUS:-NOT_RUN}"
162+
} > attempt/result.env
163+
164+
- name: Upload attempt artifact
165+
if: always()
166+
uses: actions/upload-artifact@v7
167+
with:
168+
name: coverage-attempt-${{ inputs.round || '1' }}-${{ matrix.runner }}
169+
path: attempt
170+
if-no-files-found: error
171+
retention-days: 1
172+
173+
collect:
174+
name: Select a generated coverage report
175+
if: always()
176+
needs: report
177+
runs-on: ubuntu-24.04
178+
env:
179+
ATTEMPT_ROUND: ${{ inputs.round || '1' }}
180+
outputs:
181+
host_hit: ${{ steps.select.outputs.host_hit }}
182+
report_ready: ${{ steps.select.outputs.report_ready }}
183+
selected_artifact: ${{ steps.select.outputs.selected_artifact }}
184+
steps:
185+
- name: Prepare artifact directory
186+
run: mkdir -p attempts
187+
188+
- name: Download attempt artifacts
189+
continue-on-error: true
190+
uses: actions/download-artifact@v8
191+
with:
192+
pattern: coverage-attempt-${{ inputs.round || '1' }}-*
193+
path: attempts
194+
195+
- name: Select the first complete report
196+
id: select
197+
shell: bash
198+
run: |
199+
set -euo pipefail
200+
host_hit=false
201+
report_ready=false
202+
selected_artifact=""
203+
shopt -s nullglob
204+
for result in "attempts/coverage-attempt-${ATTEMPT_ROUND}-"*/result.env; do
205+
if grep -qx 'host_hit=true' "$result"; then
206+
host_hit=true
207+
fi
208+
if [ -z "$selected_artifact" ] && grep -qx 'report_ready=true' "$result"; then
209+
selected_artifact="$(basename "$(dirname "$result")")"
210+
report_ready=true
211+
fi
212+
done
213+
{
214+
printf 'host_hit=%s\n' "$host_hit"
215+
printf 'report_ready=%s\n' "$report_ready"
216+
printf 'selected_artifact=%s\n' "$selected_artifact"
217+
} >> "$GITHUB_OUTPUT"
218+
printf 'AVX-512 host hit: %s\n' "$host_hit"
219+
printf 'Complete report available: %s\n' "$report_ready"
220+
221+
publish:
222+
name: Publish selected report
223+
needs: collect
224+
if: needs.collect.outputs.report_ready == 'true'
225+
runs-on: ubuntu-24.04
226+
steps:
227+
- name: Download selected report
228+
uses: actions/download-artifact@v8
229+
with:
230+
name: ${{ needs.collect.outputs.selected_artifact }}
231+
path: selected
232+
233+
- name: Verify selected report
234+
run: test -f selected/site/index.html
235+
103236
- name: Configure GitHub Pages
104237
uses: actions/configure-pages@v6
105238

106239
- name: Upload Pages artifact
107240
uses: actions/upload-pages-artifact@v5
108241
with:
109-
path: site
242+
path: selected/site
243+
244+
retry:
245+
name: Request the next runner allocation round
246+
needs: collect
247+
if: |
248+
always() &&
249+
needs.collect.outputs.report_ready != 'true' &&
250+
fromJSON(inputs.round || '1') < 4
251+
runs-on: ubuntu-24.04
252+
steps:
253+
- name: Dispatch next round
254+
env:
255+
GH_TOKEN: ${{ github.token }}
256+
CURRENT_ROUND: ${{ inputs.round || '1' }}
257+
ROOT_RUN_ID: ${{ inputs.root_run_id || github.run_id }}
258+
run: |
259+
next_round=$((CURRENT_ROUND + 1))
260+
gh workflow run coverage-pages.yml \
261+
--repo "$GITHUB_REPOSITORY" \
262+
--ref "$GITHUB_REF_NAME" \
263+
--field round="$next_round" \
264+
--field root_run_id="$ROOT_RUN_ID"
265+
266+
exhausted:
267+
name: Report that AVX-512 allocation was exhausted
268+
needs: collect
269+
if: |
270+
always() &&
271+
needs.collect.outputs.report_ready != 'true' &&
272+
fromJSON(inputs.round || '1') >= 4
273+
runs-on: ubuntu-24.04
274+
steps:
275+
- name: Fail after four rounds
276+
run: |
277+
echo "No complete AVX-512 coverage report was produced after four runner allocation rounds." >&2
278+
exit 1
110279
111280
deploy:
112281
name: Deploy latest report
113-
needs: report
282+
needs: publish
283+
if: needs.publish.result == 'success'
114284
runs-on: ubuntu-26.04
115285
environment:
116286
name: github-pages

memory-bank/coverage.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ it. gcovr filters the report to `avs_core/` using the AviSynthPlus submodule as
2525
the report root, so published source paths begin with `avs_core/`.
2626

2727
GitHub Actions runs this profile only for `master` pushes and manual dispatches.
28-
It publishes the latest CTest status plus line, branch, and function coverage
29-
to GitHub Pages without a coverage threshold or retained report history. A
30-
failing CTest run is published as `FAIL`, but does not fail the workflow; its
31-
coverage result can therefore be partial. Configuration, build, and report-
32-
generation failures still fail the workflow.
28+
Each allocation round starts four independent `ubuntu-26.04` matrix jobs. A
29+
job proceeds with checkout, build, CTest, and `gcovr` only when `/proc/cpuinfo`
30+
contains the higher-level `avx512_vnni` flag, keeping the CPU probe and native
31+
AVX-512 execution on the same runner. A complete report is uploaded as an
32+
attempt artifact; a controller selects the first complete artifact and
33+
publishes it to GitHub Pages. When no report is produced, the workflow
34+
dispatches the next round, with a maximum of four rounds (16 runner
35+
allocations). A failing CTest run is published as `FAIL`, but does not fail the
36+
coverage report; its result can therefore be partial. Configuration, build,
37+
and report-generation failures cause that allocation to be retried, and the
38+
workflow fails after the fourth round if no complete report is available.
3339

3440
The recursive checkout uses complete history and tags. Upstream `VersionGen`
3541
calls `git describe --tags` and counts commits since that tag, so a shallow

0 commit comments

Comments
 (0)