Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,56 @@ jobs:
run: |
cd docs && make html

pytest-linux-386:
pytest-linux-container:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- arch_name: linux/386
qemu_platform: 386
image_name: gfloat-linux-386:py310-uv
image_tar: /tmp/gfloat-linux-386-image.tar
cache_prefix: linux-386-image
test_script: etc/test-linux-386.sh
- arch_name: linux/arm32
qemu_platform: arm
image_name: gfloat-linux-arm32:py310-uv
image_tar: /tmp/gfloat-linux-arm32-image.tar
cache_prefix: linux-arm32-image
test_script: etc/test-linux-arm32.sh

steps:
- uses: actions/checkout@v6

- name: Restore cached linux/386 docker image
id: cache-linux-386-image
- name: Restore cached test image (${{ matrix.arch_name }})
id: cache-test-image
uses: actions/cache@v5
with:
path: /tmp/gfloat-linux-386-image.tar
key: ${{ runner.os }}-linux-386-image-${{ hashFiles('etc/linux-386.Dockerfile', 'requirements.txt', 'requirements-dev.txt', 'pyproject.toml') }}
path: ${{ matrix.image_tar }}
key: ${{ runner.os }}-${{ matrix.cache_prefix }}-${{ hashFiles('etc/linux-container.Dockerfile', 'requirements.txt', 'requirements-dev.txt', 'pyproject.toml') }}

- name: Enable QEMU for 32-bit emulation
- name: Enable QEMU emulation (${{ matrix.arch_name }})
uses: docker/setup-qemu-action@v4
with:
platforms: 386
platforms: ${{ matrix.qemu_platform }}

- name: Load cached linux/386 docker image
- name: Load cached test image (${{ matrix.arch_name }})
run: |
if [ -f /tmp/gfloat-linux-386-image.tar ]; then
docker load -i /tmp/gfloat-linux-386-image.tar
if [ -f "${{ matrix.image_tar }}" ]; then
docker load -i "${{ matrix.image_tar }}"
fi

- name: Ensure linux/386 test image is available
- name: Ensure test image is available (${{ matrix.arch_name }})
run: |
bash etc/test-linux-386.sh load
bash "${{ matrix.test_script }}" load

- name: Run full unit tests on linux/386
- name: Run unit tests (${{ matrix.arch_name }})
run: |
bash etc/test-linux-386.sh run -vv test
bash "${{ matrix.test_script }}" run -vv test

- name: Save linux/386 docker image to cache path
- name: Save test image to cache path (${{ matrix.arch_name }})
if: always()
run: |
docker image inspect gfloat-linux-386:py310-uv >/dev/null 2>&1
docker save gfloat-linux-386:py310-uv -o /tmp/gfloat-linux-386-image.tar
docker image inspect "${{ matrix.image_name }}" >/dev/null 2>&1
docker save "${{ matrix.image_name }}" -o "${{ matrix.image_tar }}"
2 changes: 2 additions & 0 deletions etc/linux-386.Dockerfile → etc/linux-container.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*

RUN python -m pip install -U --no-cache-dir pip

RUN NINJAFLAGS='-v' python -m pip install -v --no-cache-dir \
"numpy<2"

Expand Down
84 changes: 5 additions & 79 deletions etc/test-linux-386.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,11 @@

[ -n "${BASH_VERSION:-}" ] || exec bash "$0" "$@"

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"

IMAGE="gfloat-linux-386:py310-uv"
PLATFORM="linux/386"
DOCKERFILE="etc/linux-386.Dockerfile"
MODE="all"

if [[ "${1:-}" == "all" || "${1:-}" == "load" || "${1:-}" == "build" || "${1:-}" == "run" ]]; then
MODE="$1"
shift
fi

usage() {
echo "Usage: bash etc/test-linux-386.sh [all|load|build|run] [pytest args...]"
echo " load Build image only if missing"
echo " build Force rebuild image"
echo " run Run tests (image must already exist)"
echo " (no arg) Build image if missing, then run tests"
echo ""
echo "Examples:"
echo " bash etc/test-linux-386.sh run test/test_encode.py::test_encode[binary32]"
echo " bash etc/test-linux-386.sh run -k stochastic -q"
}

build_image() {
docker buildx build \
--progress=plain \
--platform "${PLATFORM}" \
--load \
-t "${IMAGE}" \
-f "${REPO_DIR}/${DOCKERFILE}" \
"${REPO_DIR}"
}

run_tests() {
docker run --rm \
--platform "${PLATFORM}" \
-v "${REPO_DIR}:/work" \
-w /work \
"${IMAGE}" \
bash -lc '
set -euo pipefail
export PYTHONPATH="/work/src${PYTHONPATH:+:${PYTHONPATH}}"
python -m pytest "$@"
' _ "$@"
}

if [[ "${MODE}" != "all" && "${MODE}" != "load" && "${MODE}" != "build" && "${MODE}" != "run" ]]; then
usage
exit 2
fi

echo "Running unit tests in Docker (${PLATFORM})"

if ! docker info >/dev/null 2>&1; then
echo "Docker daemon is not running; start Docker and rerun this script." >&2
exit 1
fi

if [[ "${MODE}" == "build" ]]; then
echo "Force-building test image ${IMAGE} for ${PLATFORM}"
build_image
fi

if [[ "${MODE}" == "load" || "${MODE}" == "all" ]]; then
if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then
echo "Building test image ${IMAGE} for ${PLATFORM} (cached after first build)"
build_image
fi
fi

if [[ "${MODE}" == "run" || "${MODE}" == "all" ]]; then
if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then
echo "Image ${IMAGE} not found. Run 'bash etc/test-linux-386.sh load' first." >&2
exit 1
fi
export GFLOAT_TEST_IMAGE="gfloat-linux-386:py310-uv"
export GFLOAT_TEST_PLATFORM="linux/386"
export GFLOAT_TEST_DOCKERFILE="etc/linux-container.Dockerfile"
export GFLOAT_TEST_SCRIPT_NAME="test-linux-386.sh"

run_tests "$@"
fi
exec bash "${SCRIPT_DIR}/test-linux-container.sh" "$@"
14 changes: 14 additions & 0 deletions etc/test-linux-arm32.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

# Copyright (c) 2024 Graphcore Ltd. All rights reserved.

[ -n "${BASH_VERSION:-}" ] || exec bash "$0" "$@"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

export GFLOAT_TEST_IMAGE="gfloat-linux-arm32:py310-uv"
export GFLOAT_TEST_PLATFORM="linux/arm/v7"
export GFLOAT_TEST_DOCKERFILE="etc/linux-container.Dockerfile"
export GFLOAT_TEST_SCRIPT_NAME="test-linux-arm32.sh"

exec bash "${SCRIPT_DIR}/test-linux-container.sh" "$@"
89 changes: 89 additions & 0 deletions etc/test-linux-container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash

# Copyright (c) 2024 Graphcore Ltd. All rights reserved.

[ -n "${BASH_VERSION:-}" ] || exec bash "$0" "$@"

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"

IMAGE="${GFLOAT_TEST_IMAGE:?GFLOAT_TEST_IMAGE is required}"
PLATFORM="${GFLOAT_TEST_PLATFORM:?GFLOAT_TEST_PLATFORM is required}"
DOCKERFILE="${GFLOAT_TEST_DOCKERFILE:?GFLOAT_TEST_DOCKERFILE is required}"
SCRIPT_NAME="${GFLOAT_TEST_SCRIPT_NAME:-$(basename "$0")}"

MODE="all"
if [[ "${1:-}" == "all" || "${1:-}" == "load" || "${1:-}" == "build" || "${1:-}" == "run" ]]; then
MODE="$1"
shift
fi

usage() {
echo "Usage: bash etc/${SCRIPT_NAME} [all|load|build|run] [pytest args...]"
echo " load Build image only if missing"
echo " build Force rebuild image"
echo " run Run tests (image must already exist)"
echo " (no arg) Build image if missing, then run tests"
echo ""
echo "Examples:"
echo " bash etc/${SCRIPT_NAME} run test/test_encode.py::test_encode[binary32]"
echo " bash etc/${SCRIPT_NAME} run -k stochastic -q"
}

build_image() {
docker buildx build \
--progress=plain \
--platform "${PLATFORM}" \
--load \
-t "${IMAGE}" \
-f "${REPO_DIR}/${DOCKERFILE}" \
"${REPO_DIR}"
}

run_tests() {
docker run --rm \
--platform "${PLATFORM}" \
-v "${REPO_DIR}:/work" \
-w /work \
"${IMAGE}" \
bash -lc '
set -euo pipefail
export PYTHONPATH="/work/src${PYTHONPATH:+:${PYTHONPATH}}"
python -m pytest "$@"
' _ "$@"
}

if [[ "${MODE}" != "all" && "${MODE}" != "load" && "${MODE}" != "build" && "${MODE}" != "run" ]]; then
usage
exit 2
fi

echo "Running unit tests in Docker (${PLATFORM})"

if ! docker info >/dev/null 2>&1; then
echo "Docker daemon is not running; start Docker and rerun this script." >&2
exit 1
fi

if [[ "${MODE}" == "build" ]]; then
echo "Force-building test image ${IMAGE} for ${PLATFORM}"
build_image
fi

if [[ "${MODE}" == "load" || "${MODE}" == "all" ]]; then
if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then
echo "Building test image ${IMAGE} for ${PLATFORM} (cached after first build)"
build_image
fi
fi

if [[ "${MODE}" == "run" || "${MODE}" == "all" ]]; then
if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then
echo "Image ${IMAGE} not found. Run 'bash etc/${SCRIPT_NAME} load' first." >&2
exit 1
fi

run_tests "$@"
fi