diff --git a/.github/workflows/build-onnxsim.yml b/.github/workflows/build-onnxsim.yml new file mode 100644 index 0000000000..1339b7eb6d --- /dev/null +++ b/.github/workflows/build-onnxsim.yml @@ -0,0 +1,167 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on: https://github.com/onnxsim/onnxsim/blob/v0.7.3/.github/workflows/build-and-test.yml +name: Build onnxsim wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/onnxsim.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-onnxsim.yml' + - 'docs/packages/onnxsim.yaml' + - 'patches/onnxsim/**' + push: + branches: [main] + paths: + - '.github/workflows/build-onnxsim.yml' + - 'docs/packages/onnxsim.yaml' + - 'patches/onnxsim/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: onnxsim + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build onnxsim ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + # Upstream ships cp310/cp311/cp312-abi3 (no free-threaded wheel here). + # cp310 is dropped: onnx (the runtime dependency) has no riscv64 wheel + # for it on our registry, at any version, and no py3-none-any fallback + # either (it's a compiled extension). cp311 stays: onnx ships a + # riscv64 cp311 wheel, and nanobind/protobuf (the other build-time + # dependencies) resolve too, via their py3-none-any fallback wheels. + # `python` is a real matrix dimension (not folded into `include` + # alone) so both entries actually produce a job: an `include` list + # whose entries share no key with the base matrix collapses onto a + # single combination instead of adding one job per entry. + python: [cp311, cp312] + include: + - python: cp311 + # No riscv64 onnxruntime wheel on cp311; the rest of the suite still + # runs (onnxsim falls back to onnx's reference evaluator). + onnxruntime: '' + # onnx's reference BatchNormalization_9 (opset 9-13) always takes its + # momentum branch (the attribute defaults to 0.9, never None) and mixes + # batch statistics into the inference output, so the equivalence check + # rejects the correctly fused Conv; same failure on x86_64 without + # onnxruntime. Upstream CI always installs onnxruntime. + pytest_k: not test_fuse_conv_bn_into_conv and not test_fuse_convtranspose_bn + - python: cp312 + onnxruntime: onnxruntime + pytest_k: '' + + env: + ONNXSIM_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout onnxsim v${{ env.ONNXSIM_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: onnxsim/onnxsim + ref: v${{ env.ONNXSIM_VERSION }} + submodules: recursive + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Apply patches + run: git apply -v python-wheels/patches/onnxsim/${{ env.ONNXSIM_VERSION }}/*.patch + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + only: ${{ matrix.python }}-manylinux_riscv64 + env: + # The riscv64 manylinux image's own cmake (3.31.8) already satisfies + # CMakeLists.txt's cmake_minimum_required(3.22); upstream's own + # CIBW_BEFORE_BUILD only pip-installs cmake/ninja for its manylinux_2_28 + # x86_64/aarch64 images. + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + CIBW_ENVIRONMENT: >- + CMAKE_ARGS=" + -DONNX_USE_PROTOBUF_SHARED_LIBS=OFF + -DProtobuf_USE_STATIC_LIBS=ON + -DONNX_USE_LITE_PROTO=ON + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + " + ONNXSIM_RELEASE=${{ env.ONNXSIM_VERSION }} + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + # nanobind builds the onnxsim_cpp2py_export extension (CMakeLists.txt's + # ONNXSIM_PYTHON path); CMake locates it via `python -m nanobind + # --cmake_dir`, so it must already be importable before configure runs + # or CMake falls back to fetching it from GitHub. protobuf is needed + # for the same reason as onnxoptimizer's build. Both ship a + # py3-none-any wheel, so they install on any interpreter/arch. + CIBW_BEFORE_BUILD_LINUX: pip install nanobind protobuf + # Upstream's own suite additionally exercises onnxscript/torch/timm/ + # sympy/onnxslim/ultralytics/rfdetr paths; most guard the import with + # pytest.importorskip, so they collect fine and just skip without + # riscv64 wheels for those. onnxruntime does have a riscv64 wheel on + # our registry, but only from cp312 (matrix.onnxruntime). Five files + # import torch/timm/onnxruntime unconditionally at module level + # (no importorskip), which aborts collection outright rather than + # skipping when the import fails - not just deselecting their tests, + # so ignore the files themselves. + CIBW_TEST_REQUIRES: pytest pytest-xdist ${{ matrix.onnxruntime }} + CIBW_TEST_COMMAND: >- + pytest {project}/tests/ + -k "${{ matrix.pytest_k }}" + --ignore={project}/tests/test_python_api.py + --ignore={project}/tests/test_simple.py + --ignore={project}/tests/test_timm.py + --ignore={project}/tests/test_rfdetr.py + --ignore={project}/tests/test_yolo.py + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: onnxsim-${{ env.ONNXSIM_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish onnxsim ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: onnxsim-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/onnxsim.yaml b/docs/packages/onnxsim.yaml new file mode 100644 index 0000000000..7bbf039677 --- /dev/null +++ b/docs/packages/onnxsim.yaml @@ -0,0 +1,17 @@ +package-name: onnxsim +source-code: https://github.com/onnxsim/onnxsim +license: MIT AND (Apache-2.0 OR BSD-2-Clause) +warning: | + onnxsim vendors onnx-optimizer as a git submodule, which in turn vendors + onnx (MIT) as its own submodule; onnxsim links both, plus protobuf + (BSD-3-Clause), statically. protobuf pulls in abseil-cpp (Apache-2.0) the + same way onnx's own standalone build does (see docs/packages/onnx.yaml). + Abseil ships no NOTICE file to propagate, and onnx-optimizer is + Apache-2.0, so the wheel's own LICENSE already covers it. The Python + extension is built with nanobind rather than pybind11; nanobind ships a + single py3-none-any wheel with no compiled code of its own (it only + emits code into the extension it builds), so it needs no riscv64-specific + handling. +versions: +- version: 0.7.3 + patched: true diff --git a/patches/onnxsim/0.7.3/0001-tests-pin-ir_version-in-test_profiling-s-foldable-model.patch b/patches/onnxsim/0.7.3/0001-tests-pin-ir_version-in-test_profiling-s-foldable-model.patch new file mode 100644 index 0000000000..10189f2176 --- /dev/null +++ b/patches/onnxsim/0.7.3/0001-tests-pin-ir_version-in-test_profiling-s-foldable-model.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 24 Sep 2026 00:00:00 +0000 +Subject: [PATCH] tests: pin ir_version in test_profiling's _foldable_model + +Every other test file that builds an onnx.ModelProto by hand pins +ir_version explicitly (test_python_api.py, test_function_rewriter.py, +test_constant_fold_determinism.py, etc. all pass ir_version=... to +helper.make_model()). test_profiling.py's _foldable_model() is the one +holdout: it calls helper.make_model(graph, opset_imports=[...]) with no +ir_version, so the model is stamped with whatever onnx.IR_VERSION the +currently installed onnx package defines. + +onnxsim statically links a vendored onnx (via the onnx-optimizer git +submodule, frozen at a pinned commit) into its C++ core, and that +core's checker enforces its own, older notion of the max supported IR +version. Once the *installed* onnx package (an unpinned "onnx" runtime +dependency in pyproject.toml) is newer than whatever onnx-optimizer's +submodule was pinned to at release time, every one of +_foldable_model()'s callers in this file fails identically: + + RuntimeError: Your model ir_version 14 is higher than the + checker's (13). + +before reaching any of what the test actually means to check (the +profiler's spans, the OrtSession nesting, the env var save/restore). +This is a real ambient-versioning gap, not a riscv64-only symptom: the +same break reproduces on any platform the moment pip resolves an onnx +release newer than the vendored submodule tolerates, which is exactly +why every sibling test file already pins ir_version defensively - +test_profiling.py just missed doing the same for its one hand-built +model. + +Match the existing convention used throughout the suite (ir_version=10 +regardless of opset) so the fixture stays valid across the wide range +of onnx versions the unpinned runtime dependency can resolve to. + +Upstream-Status: To upstream [no push/issue access to onnxsim/onnxsim from this environment - only riseproject-dev/python-wheels is attached; the fix is a one-line ir_version pin matching every sibling test file's existing convention] + +Signed-off-by: Ludovic Henry +--- +diff --git a/tests/test_profiling.py b/tests/test_profiling.py +--- a/tests/test_profiling.py ++++ b/tests/test_profiling.py +@@ -29,7 +29,18 @@ + x = helper.make_tensor_value_info("x", TensorProto.FLOAT, [1, 4]) + y = helper.make_tensor_value_info("y", TensorProto.FLOAT, [1, 4]) + graph = helper.make_graph([add_const, add_x], "g", [x], [y], [a, b]) +- model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 17)]) ++ model = helper.make_model( ++ graph, ++ opset_imports=[helper.make_opsetid("", 17)], ++ # Pin ir_version like every other model-building test in this suite ++ # already does (test_python_api.py, test_function_rewriter.py, etc.): ++ # onnx.helper.make_model() otherwise stamps the installed onnx package's ++ # current onnx.IR_VERSION, which floats upward with each onnx release and ++ # can exceed what the vendored onnx-optimizer/onnx submodule's checker ++ # (frozen at a pinned commit) accepts, e.g. "Your model ir_version 14 is ++ # higher than the checker's (13)" once a newer onnx is installed. ++ ir_version=10, ++ ) + onnx.checker.check_model(model) + return model +