From 4df375487cd49312fb55e8a1908bcd4bb544e79a Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 11 Aug 2026 17:08:20 +0700 Subject: ci: sysview capture in HIL jobs, performance report on the sticky comment The HIL job captures the sysview-flagged boards after the functional tests; a compare job turns base-vs-PR reports into sysview-comment, and pr_comment.yml appends it to the HIL sticky comment. Every job is capped above the pool guard. --- .github/workflows/build.yml | 129 +++++++++++++++++++++++++++++++++++++++ .github/workflows/pr_comment.yml | 13 ++++ 2 files changed, 142 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 70555b111..551241543 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -627,6 +627,76 @@ jobs: if [ -n "$RERUN_ARGS" ]; then SEL_ARGS=''; fi python3 test/hil/hil_test.py --retry 1 ${{ matrix.test_args }} $SEL_ARGS ${{ env.HIL_JSON }} $RERUN_ARGS + - name: Get SystemView capture dependencies + # sysview_ci.py capture builds device/cdc_msc for the sysview-flagged boards on + # this runner. "Clean workspace" above wipes the checkout every run, so this always + # re-clones (get_deps.py's own already-at-pinned-commit skip never gets a chance to + # apply here); scoping to just the sysview-flagged boards keeps it to a handful of + # shallow (depth=1) clones rather than the full job matrix's dependency set. + # N8: board list derived from $HIL_JSON itself -- the same "sysview" key sysview_ci.py's + # own select_boards() checks -- instead of a hardcoded pair that silently drifts out of + # sync with test/hil/tinyusb.json (a third sysview board added the documented way would + # otherwise just build failed here, inside a continue-on-error step, with nothing to say + # why). + if: ${{ !cancelled() && github.run_attempt == '1' }} + continue-on-error: true + run: | + BOARDS=$(python3 -c " + import json + cfg = json.load(open('$HIL_JSON')) + print(' '.join(b['name'] for b in cfg['boards'] if 'sysview' in b)) + ") + if [ -z "$BOARDS" ]; then + echo "no sysview-flagged boards in $HIL_JSON, nothing to fetch deps for" + exit 0 + fi + ARGS="" + for b in $BOARDS; do ARGS="$ARGS -b $b"; done + python3 tools/get_deps.py $ARGS + + - name: SystemView capture + # Best-effort perf capture, never gates the job: same board scope as the test + # step above, restricted to -b (sysview_ci.py capture has no -bt/--accumulate, + # unlike hil_test.py, so those tokens are dropped from the selection string). + # Skipped on re-run attempts (run_attempt != 1): a re-run recaptures every board + # instead of just the ones that failed, wasting shared-rig time for no report benefit. + if: ${{ !cancelled() && github.run_attempt == '1' }} + continue-on-error: true + env: + SEL_ARGS_TINYUSB: ${{ needs.set-matrix.outputs.hil_args_tinyusb }} + SEL_RUN_TINYUSB: ${{ needs.set-matrix.outputs.hil_run_tinyusb }} + SEL_ARGS_HFP: ${{ needs.set-matrix.outputs.hil_args_hfp }} + SEL_RUN_HFP: ${{ needs.set-matrix.outputs.hil_run_hfp }} + run: | + case "$HIL_JSON" in + *tinyusb.json) SEL_ARGS="$SEL_ARGS_TINYUSB"; SEL_RUN="$SEL_RUN_TINYUSB" ;; + *hfp.json) SEL_ARGS="$SEL_ARGS_HFP"; SEL_RUN="$SEL_RUN_HFP" ;; + esac + if [ "$SEL_RUN" = "false" ]; then echo "SystemView capture skipped by PR selection (no affected boards on this rig)"; exit 0; fi + if [ -n "$RERUN_ARGS" ]; then SEL_ARGS="$RERUN_ARGS"; fi + SYSVIEW_BOARD_ARGS="" + set -- $SEL_ARGS + while [ $# -gt 0 ]; do + case "$1" in + # a trailing bare -b (no board name after it) has no pair to consume; shift just + # the one token instead of falling through to an un-shifted, endlessly looping $1 + -b) [ $# -ge 2 ] && { SYSVIEW_BOARD_ARGS="$SYSVIEW_BOARD_ARGS -b $2"; shift 2; } || shift ;; + *) shift ;; + esac + done + python3 test/hil/sysview_ci.py capture ${{ env.HIL_JSON }} \ + $SYSVIEW_BOARD_ARGS --out sysview-out + + - name: Upload SystemView captures + if: ${{ !cancelled() && github.run_attempt == '1' }} + continue-on-error: true + uses: actions/upload-artifact@v7 + with: + name: sysview-${{ matrix.display }} + path: sysview-out/sysview-*.json + if-no-files-found: ignore + overwrite: true + - name: Upload HIL report if: always() && github.event_name == 'pull_request' uses: actions/upload-artifact@v7 @@ -636,6 +706,65 @@ jobs: if-no-files-found: ignore overwrite: true + # --------------------------------------- + # Compare this run's SystemView captures (uploaded by hil-tinyusb) against the base + # branch's latest captures on the same workflow, producing a sticky-comment-ready + # markdown table. hfp.json has no sysview-flagged boards, so its capture step never + # uploads anything; only tinyusb.json's captures ever feed this. + # --------------------------------------- + sysview-report: + needs: hil-tinyusb + if: always() && github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v6 + + - name: Download PR SystemView captures + uses: actions/download-artifact@v5 + continue-on-error: true + with: + pattern: sysview-* + path: pr-sysview + merge-multiple: true + + - name: Download base branch SystemView captures + uses: dawidd6/action-download-artifact@v11 + with: + workflow: build.yml + workflow_conclusion: '' + branch: ${{ github.base_ref }} + name: sysview-.* + name_is_regexp: true + path: base-sysview + continue-on-error: true + + - name: Flatten base captures + # name_is_regexp downloads each matching artifact into its own subdirectory; + # sysview_ci.py report globs sysview-*.json directly in the directory it's given. + run: | + mkdir -p base-sysview-flat + find base-sysview -mindepth 2 -maxdepth 2 -name 'sysview-*.json' \ + -exec cp {} base-sysview-flat/ \; 2>/dev/null || true + + - name: Generate SystemView report + id: report + continue-on-error: true # informational comment: a generator crash must not red the PR + run: | + python3 test/hil/sysview_ci.py report base-sysview-flat pr-sysview -o sysview_report.md + if [ -s sysview_report.md ]; then + echo "found=true" >> "$GITHUB_OUTPUT" + fi + + - name: Upload SystemView Comment Artifact + if: steps.report.outputs.found == 'true' + uses: actions/upload-artifact@v7 + with: + name: sysview-comment + path: sysview_report.md + if-no-files-found: ignore + overwrite: true + # --------------------------------------- # Hardware in the loop (HIL) - espressif boards only # Same rig as hil-tinyusb (tinyusb.json) but gated only on the slow esp-idf build, diff --git a/.github/workflows/pr_comment.yml b/.github/workflows/pr_comment.yml index 868e56405..e1d9a118a 100644 --- a/.github/workflows/pr_comment.yml +++ b/.github/workflows/pr_comment.yml @@ -95,6 +95,15 @@ jobs: path: hil-reports continue-on-error: true + - name: Download SystemView report + uses: actions/download-artifact@v5 + with: + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + name: sysview-comment + path: sysview-comment + continue-on-error: true + - name: Combine rig reports (one table per rig) id: combine run: | @@ -124,6 +133,10 @@ jobs: echo done } > hil_combined.md + if [ -s sysview-comment/sysview_report.md ]; then + echo >> hil_combined.md + cat sysview-comment/sysview_report.md >> hil_combined.md + fi # Fork PRs can influence report content and this job posts in base-repo context, so # neutralize @-mentions (insert a zero-width space) to prevent notification abuse. zwsp=$(printf '\342\200\213') -- cgit v1.3.1