CXL test runner #38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: CXL test runner | |
| # yamllint disable-line rule:truthy | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| kernel_repo: | |
| description: "Kernel repo: owner/name OR full git URL" | |
| required: true | |
| default: "AlisonSchofield/linux-kernel" | |
| kernel_branch: | |
| description: "Kernel branch (or tag/SHA)" | |
| required: true | |
| default: "cxl-testme" | |
| ndctl_repo: | |
| description: "ndctl repo: owner/name OR full git URL" | |
| required: true | |
| default: "pmem/ndctl" | |
| ndctl_branch: | |
| description: "ndctl branch (or tag/SHA)" | |
| required: true | |
| default: "pending" | |
| timeout_min: | |
| description: "Guest timeout (minutes)" | |
| required: true | |
| default: "35" | |
| jobs: | |
| build: | |
| runs-on: ubuntu-24.04 | |
| env: | |
| # Inputs | |
| KERNEL_REPO: ${{ inputs.kernel_repo }} | |
| KERNEL_BRANCH: ${{ inputs.kernel_branch }} | |
| NDCTL_REPO: ${{ inputs.ndctl_repo }} | |
| NDCTL_BRANCH: ${{ inputs.ndctl_branch }} | |
| RUN_TIMEOUT_MIN: ${{ inputs.timeout_min }} | |
| # Pinned runner behavior (not user-configurable ATM) | |
| RUN_OPTS: --cxl-test-run --ndctl-build | |
| # Pinned image selection | |
| MKOSI_DISTRO: ubuntu | |
| MKOSI_RELEASE: noble | |
| # Pinned runner identity strings (for output / cache keys) | |
| RUNNER_OS_LABEL: ubuntu-24.04 | |
| ARCH_LABEL: x86_64 | |
| steps: | |
| - name: checkout run_qemu (this repo) | |
| uses: actions/checkout@v4 | |
| with: | |
| path: run_qemu | |
| # Free disk space on GitHub runner | |
| - name: apt-get remove for disk space | |
| run: | | |
| df -h | |
| sudo apt-get remove -y '^aspnetcore-.*' '^dotnet-.*' | |
| sudo apt-get remove -y 'php.*' '^mongodb-.*' '^mysql-.*' | |
| sudo apt-get remove -y azure-cli '^google-cloud*' | |
| sudo apt-get remove -y '^llvm-.*' | |
| sudo apt-get autoremove -y | |
| sudo apt-get install -y bc | |
| df -h | |
| - name: rm -rf for disk space | |
| run: | | |
| df -h | |
| sudo docker image prune --all --force || true | |
| df -h | |
| _dirs=( /usr/local/lib/android /usr/share/dotnet /usr/local/.ghcup ) | |
| sudo du -shc "${_dirs[@]}" || true | |
| sudo rm -rf "${_dirs[@]}" | |
| df -h | |
| - name: apt install mkosi and run_qemu requirements | |
| run: | | |
| sudo apt-get update | |
| # Kernel build deps | |
| sudo apt install -y build-essential flex bison libelf-dev libssl-dev ccache | |
| # run_qemu deps | |
| sudo apt install -y mkosi | |
| sudo apt install -y dracut-core qemu-utils ovmf mtools qemu-system-x86 | |
| pip3 install qemu.qmp | |
| - name: mkosi v20 fixes on Ubuntu 24.04 | |
| run: | | |
| cd /usr/lib/python3/dist-packages | |
| sudo git apply "${{ github.workspace }}/run_qemu/Patches/ubuntu/24.04/mkosi/"*.patch | |
| - name: apt install Ubuntu 24.04 requirements for mkosi | |
| run: | | |
| sudo apt install -y systemd-ukify systemd-boot | |
| - name: apt install ndctl build dependencies | |
| run: | | |
| grep -vE '^[[:blank:]]*#' .github/workflows/ubuntu-ndctl-build-deps | \ | |
| xargs sudo apt install -y | |
| - name: argbash | |
| run: | | |
| AB_VER=2.10.0 | |
| wget https://github.com/matejak/argbash/archive/refs/tags/${AB_VER}.tar.gz | |
| tar xf ${AB_VER}.tar.gz | |
| sudo apt install -y autoconf | |
| sudo make -C argbash-${AB_VER}/resources install PREFIX=/usr/local/ | |
| - name: set week number for caches | |
| id: weeks | |
| run: | | |
| printf 'now=%s\n' "$(date +%Y-w%U)" >> "$GITHUB_OUTPUT" | |
| printf 'previous=%s\n' "$(date +%Y-w%U -d '7 days ago')" >> "$GITHUB_OUTPUT" | |
| - name: compute cache key suffixes | |
| id: cachekeys | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| k="$(printf '%s\n' "$KERNEL_REPO@$KERNEL_BRANCH" | sha256sum | awk '{print $1}')" | |
| n="$(printf '%s\n' "$NDCTL_REPO@$NDCTL_BRANCH" | sha256sum | awk '{print $1}')" | |
| echo "kernel_key=$k" >> "$GITHUB_OUTPUT" | |
| echo "ndctl_key=$n" >> "$GITHUB_OUTPUT" | |
| - name: Fetch ccache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/ccache/ | |
| key: ccache_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ steps.cachekeys.outputs.kernel_key }}_${{ steps.weeks.outputs.now }} | |
| restore-keys: | | |
| ccache_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ steps.cachekeys.outputs.kernel_key }}_${{ steps.weeks.outputs.previous }} | |
| ccache_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ steps.cachekeys.outputs.kernel_key }} | |
| ccache_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }} | |
| - name: ensure clean checkout dirs | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| rm -rf ndctl kernel | |
| # Checkout that supports either "owner/name" OR full git URL. | |
| - name: checkout ndctl | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "$NDCTL_REPO" =~ ^https?://|^git://|^ssh://|^git@ ]]; then | |
| git clone --depth 1 --branch "$NDCTL_BRANCH" "$NDCTL_REPO" ndctl | |
| else | |
| git clone --depth 1 --branch "$NDCTL_BRANCH" "https://github.com/${NDCTL_REPO}.git" ndctl | |
| fi | |
| - name: checkout kernel | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "$KERNEL_REPO" =~ ^https?://|^git://|^ssh://|^git@ ]]; then | |
| git clone --depth 1 --branch "$KERNEL_BRANCH" "$KERNEL_REPO" kernel | |
| else | |
| git clone --depth 1 --branch "$KERNEL_BRANCH" "https://github.com/${KERNEL_REPO}.git" kernel | |
| fi | |
| - name: Ensure mkosi apt cache dirs exist | |
| run: | | |
| mkdir -p kernel/qbuild/mkosi.cache/{cache/apt,lib/apt} | |
| # Cache only mkosi's apt caches (safe + small; avoids rootfs/ssh key permission issues) | |
| - name: Restore mkosi apt cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| kernel/qbuild/mkosi.cache/cache/apt | |
| kernel/qbuild/mkosi.cache/lib/apt | |
| key: mkosiapt_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ env.MKOSI_DISTRO }}_${{ env.MKOSI_RELEASE }}_${{ steps.weeks.outputs.now }} | |
| restore-keys: | | |
| mkosiapt_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ env.MKOSI_DISTRO }}_${{ env.MKOSI_RELEASE }}_${{ steps.weeks.outputs.previous }} | |
| mkosiapt_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }}_${{ env.MKOSI_DISTRO }}_${{ env.MKOSI_RELEASE }} | |
| mkosiapt_${{ env.RUNNER_OS_LABEL }}_${{ env.ARCH_LABEL }} | |
| fail-on-cache-miss: false | |
| - name: show revisions under test | |
| run: | | |
| echo "Kernel repo: $KERNEL_REPO" | |
| echo "Kernel branch: $KERNEL_BRANCH" | |
| git -C kernel rev-parse HEAD | |
| git -C kernel log -1 --oneline | |
| echo | |
| echo "ndctl repo: $NDCTL_REPO" | |
| echo "ndctl branch: $NDCTL_BRANCH" | |
| git -C ndctl rev-parse HEAD | |
| git -C ndctl log -1 --oneline | |
| echo | |
| echo "Runner: $RUNNER_OS_LABEL" | |
| echo "Arch: $ARCH_LABEL" | |
| echo "mkosi image: $MKOSI_DISTRO $MKOSI_RELEASE" | |
| echo "run_qemu opts: $RUN_OPTS" | |
| echo "timeout (min): $RUN_TIMEOUT_MIN" | |
| - name: defconfig | |
| working-directory: ${{ github.workspace }}/kernel | |
| run: | | |
| make defconfig ARCH=x86_64 | |
| ./scripts/kconfig/merge_config.sh .config ../run_qemu/.github/workflows/cxl-test.cfg | |
| - name: disable AppArmor | |
| run: | | |
| if test -e /proc/sys/kernel/apparmor_restrict_unprivileged_unconfined; then | |
| sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0 | |
| sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| fi | |
| - name: build kernel | |
| run: | | |
| ccache --show-stats | |
| cd kernel | |
| PATH=/usr/lib/ccache:"$PATH" make -j $(nproc) | |
| - name: run_qemu.sh | |
| run: | | |
| set -x | |
| mkosi --version | |
| qemu-system-x86_64 --version || true | |
| which qemu-system-x86_64 || true | |
| ccache --show-stats | |
| cp run_qemu/contrib/tmpfs_workspace.tmpl run_qemu/mkosi_tmpl_portable/ | |
| rm -f /tmp/rq_0.log | |
| touch /tmp/rq_0.log | |
| chmod a+rw /tmp/rq_0.log | |
| cd kernel | |
| ( | |
| PATH=/usr/lib/ccache:"$PATH" \ | |
| distro=${MKOSI_DISTRO} rev=${MKOSI_RELEASE} \ | |
| ndctl='${{ github.workspace }}/ndctl' \ | |
| ../run_qemu/run_qemu.sh -v ${RUN_OPTS} \ | |
| --rebuild=kmod \ | |
| --no-kvm \ | |
| --timeout=${RUN_TIMEOUT_MIN} \ | |
| --debug | |
| ) 2>&1 | tee -a /tmp/rq_0.log | |
| exit ${PIPESTATUS[0]} | |
| - name: check if qemu died early | |
| if: ${{ always() }} | |
| run: | | |
| echo "=== qemu processes ===" | |
| ps -ef | grep -v grep | grep qemu-system-x86_64 || echo "no qemu process" | |
| echo "=== QMP socket ===" | |
| ls -la /tmp/run_qemu_qmp_0 || true | |
| - name: show bios and serial logs | |
| if: ${{ always() }} | |
| run: | | |
| echo "=== /tmp/rq_0.log tail ===" | |
| tail -n 200 /tmp/rq_0.log || true | |
| echo "=== bios_debug.log ===" | |
| tail -n 200 kernel/bios_debug.log 2>/dev/null || tail -n 200 bios_debug.log 2>/dev/null || true | |
| - name: summarize test results | |
| if: ${{ always() }} | |
| run: | | |
| set -euo pipefail | |
| RAW=/tmp/rq_0.log | |
| CLEAN=/tmp/rq_0.clean.log | |
| # Remove ANSI escapes + CRs so matching is reliable. | |
| perl -pe 's/\e\[[0-9;]*[A-Za-z]//g; s/\r$//;' "$RAW" > "$CLEAN" || true | |
| # Helper to drop the leading kernel timestamp + "foo.log:" prefix for readability. | |
| strip_prefix() { | |
| sed -E 's/^\[[[:space:]]*[0-9]+\.[0-9]+\][[:space:]]+[^:]+:[[:space:]]+//' | |
| } | |
| { | |
| echo "# CXL test results" | |
| echo | |
| echo "## Inputs" | |
| echo "- Kernel: ${KERNEL_REPO} @ ${KERNEL_BRANCH}" | |
| echo "- ndctl: ${NDCTL_REPO} @ ${NDCTL_BRANCH}" | |
| echo "- Runner: ${RUNNER_OS_LABEL}" | |
| echo "- mkosi: ${MKOSI_DISTRO} ${MKOSI_RELEASE}" | |
| echo "- timeout: ${RUN_TIMEOUT_MIN} min" | |
| echo | |
| echo "## Revisions" | |
| echo "Kernel:" | |
| git -C kernel log -1 --oneline || true | |
| echo | |
| echo "ndctl:" | |
| git -C ndctl log -1 --oneline || true | |
| echo | |
| echo "## Per-test results" | |
| # Print only the FIRST contiguous block of "N/M ndctl:cxl / ..." lines. | |
| strip_prefix < "$CLEAN" | awk ' | |
| /======= meson-test\.log =======/ {exit} | |
| /^[[:space:]]*[0-9]+\/[0-9]+[[:space:]]+ndctl:cxl[[:space:]]*\// { | |
| printing=1 | |
| next | |
| } | |
| printing { exit } # stop after first block ends | |
| ' || echo "(no per-test lines found in /tmp/rq_0.log)" | |
| echo | |
| echo "## Totals" | |
| # Print the FIRST scoreboard block only, then stop. | |
| strip_prefix < "$CLEAN" | awk ' | |
| /======= meson-test\.log =======/ {exit} | |
| /^[[:space:]]*Ok:[[:space:]]/ {p=1} | |
| p && /^[[:space:]]*(Ok:|Expected Fail:|Fail:|Unexpected Pass:|Skipped:|Timeout:)[[:space:]]/ {print; next} | |
| p { exit } # stop after first totals block ends | |
| ' || true | |
| echo | |
| echo "See the uploaded artifact: /tmp/rq_0.log" | |
| } | tee /tmp/cxl-test-summary.md | |
| cat /tmp/cxl-test-summary.md >> "$GITHUB_STEP_SUMMARY" | |
| - name: upload logs | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: logs | |
| if-no-files-found: warn | |
| path: | | |
| /tmp/rq_0.log | |
| kernel/bios_debug.log | |
| bios_debug.log | |
| - name: ccache stats | |
| run: | | |
| ccache --show-stats | |
| ccache --show-config | grep dir || true |