From 9787924da6551c60ca04d07492187f5419a03dc3 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 20 Sep 2026 01:02:10 +0000 Subject: [PATCH 1/4] openvino: Add version 2026.3.1 --- .github/workflows/build-openvino.yml | 214 +++++++++++++++++++++++++++ docs/packages/openvino.yaml | 5 + 2 files changed, 219 insertions(+) create mode 100644 .github/workflows/build-openvino.yml create mode 100644 docs/packages/openvino.yaml diff --git a/.github/workflows/build-openvino.yml b/.github/workflows/build-openvino.yml new file mode 100644 index 00000000000..d505ad295bd --- /dev/null +++ b/.github/workflows/build-openvino.yml @@ -0,0 +1,214 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on: https://github.com/openvinotoolkit/openvino/blob/2026.3.1/.github/workflows/manylinux_2_28.yml +# (the recipe behind the published PyPI wheels) with the riscv64 cmake options of +# https://github.com/openvinotoolkit/openvino/blob/2026.3.1/.github/workflows/linux_riscv.yml +name: Build openvino wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/openvino.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-openvino.yml' + - 'docs/packages/openvino.yaml' + push: + branches: [main] + paths: + - '.github/workflows/build-openvino.yml' + - 'docs/packages/openvino.yaml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + # Upstream's AzureCR build image isn't public; manylinux is the closest equivalent. + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: openvino + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build openvino ${{ matrix.version }} manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 1440 # 24h + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + + env: + OPENVINO_VERSION: ${{ matrix.version }} + # Upstream builds the runtime once, then loops the interpreters over src/bindings/python. + PYTHON_TAGS: cp312 cp313 cp314 cp314t + + steps: + - name: Checkout openvino ${{ matrix.version }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: openvinotoolkit/openvino + ref: ${{ env.OPENVINO_VERSION }} + submodules: true + persist-credentials: false + + - name: Write container script + run: | + mkdir -p build install + cat > riscv64-build-and-test.sh <<'EOF' + #!/bin/bash + set -e -x + + # Vendored snappy and xbyak_riscv predate CMake 4's floor; upstream calls /usr/bin/cmake too. + # Retried: a mirrorlist hiccup here otherwise throws away a multi-hour runner slot. + for i in 1 2 3; do dnf install -y cmake && break || sleep 30; done + + # gcc-14 bug, as in upstream's manylinux job: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107532 + export CXXFLAGS="-Wno-dangling-reference" + + case "$1" in + build|test) ;; + *) echo "usage: $0 " >&2; exit 1 ;; + esac + + if [ "$1" = build ]; then + /usr/bin/cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_INTEL_GPU=OFF \ + -DENABLE_INTEL_NPU=OFF \ + -DENABLE_SAMPLES=OFF \ + -DENABLE_NCC_STYLE=OFF \ + -DENABLE_PYTHON=OFF \ + -DENABLE_JS=OFF \ + -DENABLE_OV_JAX_FRONTEND=OFF \ + -DENABLE_STRICT_DEPENDENCIES=OFF \ + -S /openvino \ + -B /build + /usr/bin/cmake --build /build --parallel "$(nproc)" + fi + + for python_tag in ${PYTHON_TAGS}; do + case "${python_tag}" in + *t) python_impl="${python_tag%t}" ;; + *) python_impl="${python_tag}" ;; + esac + python_exe="/opt/python/${python_impl}-${python_tag}/bin/python" + + if [ "$1" = build ]; then + "${python_exe}" -m pip install -r /openvino/src/bindings/python/wheel/requirements-dev.txt + + gil_option=() + if [ "${python_tag}" != "${python_impl}" ]; then + gil_option=(-DENABLE_GIL_PYTHON_API=OFF) + fi + + /usr/bin/cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DPython3_EXECUTABLE="${python_exe}" \ + -DOpenVINODeveloperPackage_DIR=/build \ + -DENABLE_PYTHON=ON \ + -DENABLE_WHEEL=ON \ + "${gil_option[@]}" \ + -S /openvino/src/bindings/python \ + -B "/build/python_${python_tag}" + /usr/bin/cmake --build "/build/python_${python_tag}" --parallel "$(nproc)" + /usr/bin/cmake --install "/build/python_${python_tag}" --prefix /install --component python_wheels + else + wheel=(/install/wheels/openvino-*-"${python_impl}"-"${python_tag}"-*.whl) + "${python_exe}" -m pip install "${wheel[0]}" pytest pillow + + # Run from /tmp so the checkout's src/bindings/python tree cannot shadow the wheel. + cd /tmp + "${python_exe}" -c ' + import numpy as np + import openvino as ov + from openvino import opset14 as ops + + print(ov.get_version()) + assert ov._pyopenvino.__file__.endswith(".so"), ov._pyopenvino.__file__ + + core = ov.Core() + print(core.available_devices) + assert "CPU" in core.available_devices + + param = ops.parameter([1, 4], ov.Type.f32) + model = ov.Model(ops.relu(param), [param], "relu") + compiled = core.compile_model(model, "CPU") + result = compiled(np.array([[-2.0, -1.0, 0.0, 3.0]], dtype=np.float32))[0] + assert np.array_equal(result, [[0.0, 0.0, 0.0, 3.0]]), result' + + tests=/openvino/src/bindings/python/tests + "${python_exe}" -m pytest -v \ + "${tests}/test_runtime" \ + "${tests}/test_graph" \ + "${tests}/test_transformations" \ + -m 'not template_extension' + fi + done + EOF + + - name: Build wheels + run: | + podman run -t \ + --log-driver=none \ + --network=host \ + -v "${PWD}":/openvino \ + -v "${PWD}/build":/build \ + -v "${PWD}/install":/install \ + --workdir /openvino \ + -e PYTHON_TAGS="${PYTHON_TAGS}" \ + -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + --pull=newer \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash /openvino/riscv64-build-and-test.sh build + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: openvino-${{ env.OPENVINO_VERSION }}-wheels-manylinux_riscv64 + path: install/wheels/*.whl + if-no-files-found: error + + - name: Test wheels + run: | + podman run -t \ + --log-driver=none \ + --network=host \ + -v "${PWD}":/openvino \ + -v "${PWD}/install":/install \ + --workdir /openvino \ + -e PYTHON_TAGS="${PYTHON_TAGS}" \ + -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash /openvino/riscv64-build-and-test.sh test + + publish: + name: Publish openvino ${{ 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: openvino-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/openvino.yaml b/docs/packages/openvino.yaml new file mode 100644 index 00000000000..8e692b2d3a5 --- /dev/null +++ b/docs/packages/openvino.yaml @@ -0,0 +1,5 @@ +package-name: openvino +source-code: https://github.com/openvinotoolkit/openvino +license: Apache-2.0 +versions: +- version: 2026.3.1 From 4538cbf007e38c430eccbbc9f95bb8a23707c9a4 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 24 Sep 2026 11:47:11 +0000 Subject: [PATCH 2/4] openvino: build a portable oneTBB from source; disable the RVV 1.0 probe Two confirmed riscv64 blockers from CI run 35480766550 (gotchas 448/449), targeting the generic rv64gc baseline this fleet actually runs: - cmake/dependencies.cmake's ov_download_tbb() fetches a prebuilt oneTBB for riscv64 (oneapi-tbb-2022.3.0-lin-riscv-release.tgz) that turns out to be a T-Head Xuantie toolchain build carrying vendor CUSTOM-0 opcodes (xtheadc) -- it "works" only because this runner fleet also happens to be T-Head silicon, not because it's a portable riscv64 build. oneAPI/Intel does not publish a riscv64 oneTBB release themselves; this asset is OpenVINO's own CI team cross-compiling the same source with (evidently) a T-Head-flavored default -march. Build oneTBB v2022.3.0 -- the exact version OpenVINO pins -- from its real upstream source (oneapi-src/oneTBB) with the manylinux image's own generic-rv64gc toolchain instead, and point OpenVINO at it with -DTBB_DIR, which ov_find_package_tbb() already honors ahead of ever calling ov_download_tbb(). No source patch needed for this half. - libopenvino_riscv_cpu_plugin.so unconditionally probes for RVV 1.0 by executing a v1.0 vsetivli under a SIGILL handler (nodes/kernels/riscv64/cpu_isa_traits.cpp); on this fleet's RVV 0.7.1 T-Head hardware the probe doesn't recover, it SIGILLs the whole process during ov.Core()/device enumeration. The CPU plugin already has a complete non-RVV fallback for riscv64 built in and already exercised by this exact mayiuse(gv) gate -- scalar/generic node executors, and Transformations::MainSnippets() already turns Snippets/Subgraph tokenization off entirely when is_supported_isa() is false -- so hardcoding the two probes to report "unsupported" (patches/openvino/ 2026.3.1/0001-...) routes this target through that existing path unconditionally instead of ever attempting RVV 1.0 codegen. Adds a python-wheels self-checkout and `git apply` step (this workflow previously had nowhere to source patches from), following the build-tensorstore.yml checkout-into-subdir pattern. --- .github/workflows/build-openvino.yml | 40 ++++++++++- ...cv64-never-probe-for-RVV-1.0-support.patch | 66 +++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 patches/openvino/2026.3.1/0001-cpu-riscv64-never-probe-for-RVV-1.0-support.patch diff --git a/.github/workflows/build-openvino.yml b/.github/workflows/build-openvino.yml index d505ad295bd..5aaf454a02c 100644 --- a/.github/workflows/build-openvino.yml +++ b/.github/workflows/build-openvino.yml @@ -18,11 +18,13 @@ on: paths: - '.github/workflows/build-openvino.yml' - 'docs/packages/openvino.yaml' + - 'patches/openvino/**' push: branches: [main] paths: - '.github/workflows/build-openvino.yml' - 'docs/packages/openvino.yaml' + - 'patches/openvino/**' concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -66,11 +68,22 @@ jobs: ref: ${{ env.OPENVINO_VERSION }} submodules: true persist-credentials: false + path: openvino + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch openvino source + working-directory: openvino + run: git apply -v ../python-wheels/patches/openvino/${{ env.OPENVINO_VERSION }}/*.patch - name: Write container script run: | mkdir -p build install - cat > riscv64-build-and-test.sh <<'EOF' + cat > openvino/riscv64-build-and-test.sh <<'EOF' #!/bin/bash set -e -x @@ -87,6 +100,26 @@ jobs: esac if [ "$1" = build ]; then + # cmake/dependencies.cmake downloads a prebuilt oneTBB for riscv64 + # (oneapi-tbb-2022.3.0-lin-riscv-release.tgz) that is a T-Head Xuantie + # toolchain build carrying vendor CUSTOM-0 opcodes (CLAUDE.md gotcha 449), + # not portable off this fleet. Build the same oneTBB release from source + # with this image's own generic rv64gc toolchain and point OpenVINO at it + # via -DTBB_DIR, which ov_find_package_tbb() honors ahead of ever calling + # ov_download_tbb(). + git clone --branch v2022.3.0 --depth 1 https://github.com/oneapi-src/oneTBB.git /tmp/onetbb + /usr/bin/cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/opt/onetbb \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DTBB_TEST=OFF \ + -DTBB_EXAMPLES=OFF \ + -DTBB_STRICT=OFF \ + -S /tmp/onetbb \ + -B /tmp/onetbb-build + /usr/bin/cmake --build /tmp/onetbb-build --parallel "$(nproc)" + /usr/bin/cmake --install /tmp/onetbb-build + /usr/bin/cmake \ -DCMAKE_BUILD_TYPE=Release \ -DENABLE_INTEL_GPU=OFF \ @@ -97,6 +130,7 @@ jobs: -DENABLE_JS=OFF \ -DENABLE_OV_JAX_FRONTEND=OFF \ -DENABLE_STRICT_DEPENDENCIES=OFF \ + -DTBB_DIR=/opt/onetbb/lib/cmake/TBB \ -S /openvino \ -B /build /usr/bin/cmake --build /build --parallel "$(nproc)" @@ -167,7 +201,7 @@ jobs: podman run -t \ --log-driver=none \ --network=host \ - -v "${PWD}":/openvino \ + -v "${PWD}/openvino":/openvino \ -v "${PWD}/build":/build \ -v "${PWD}/install":/install \ --workdir /openvino \ @@ -188,7 +222,7 @@ jobs: podman run -t \ --log-driver=none \ --network=host \ - -v "${PWD}":/openvino \ + -v "${PWD}/openvino":/openvino \ -v "${PWD}/install":/install \ --workdir /openvino \ -e PYTHON_TAGS="${PYTHON_TAGS}" \ diff --git a/patches/openvino/2026.3.1/0001-cpu-riscv64-never-probe-for-RVV-1.0-support.patch b/patches/openvino/2026.3.1/0001-cpu-riscv64-never-probe-for-RVV-1.0-support.patch new file mode 100644 index 00000000000..3185980ae0c --- /dev/null +++ b/patches/openvino/2026.3.1/0001-cpu-riscv64-never-probe-for-RVV-1.0-support.patch @@ -0,0 +1,66 @@ +From 9c0ff41dfe1be9aaeb6080e01fed7d4fb38777da Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 24 Sep 2026 11:43:42 +0000 +Subject: [PATCH] cpu: riscv64: never probe for RVV 1.0 support + +can_compile_rvv100()/can_compile_zvfh() try to detect RVV 1.0 by executing a +v1.0 vsetivli under a SIGILL handler and recovering via sigsetjmp/siglongjmp +if it traps. On RVV 0.7.1 hardware (T-Head Xuantie C906/C910/C920: TH1520, +SG2042) that recovery does not hold -- the illegal instruction brings the +whole process down (SIGILL, exit 132) instead of returning false, observed +as a crash inside ov.Core()/device enumeration the moment the CPU plugin is +loaded, well before any model is compiled. + +Hardcode both probes to report RVV as unsupported. Every mayiuse(gv)/ +mayiuse(gv_zvfh) caller in this plugin already treats a false result as +'fall back to the scalar/generic executor', and Transformations::MainSnippets() +already turns Snippets/Subgraph tokenization off entirely when +is_supported_isa() (== mayiuse(gv)) is false -- both existing, already- +exercised code paths for riscv64 targets without RVV. This just makes this +target take them unconditionally, instead of taking the branch that crashes. + +We do not have a kernel/toolchain-level root cause or a backtrace from the +affected hardware for why the SIGILL recovery itself fails here (it would +need re-running just the test leg against an existing wheel under gdb); until +that exists to accompany a report, this is carried as a local workaround. + +Upstream-Status: To upstream [no root-cause backtrace yet to accompany a report] +--- + .../nodes/kernels/riscv64/cpu_isa_traits.cpp | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp +index 567d627..cc2293d 100644 +--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp ++++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp +@@ -74,13 +74,23 @@ bool can_execute_generated_code() { + } + + bool can_compile_rvv100() { +- static const bool status = can_execute_generated_code(); +- return status; ++ // Deliberately never probe: can_execute_generated_code() is supposed to ++ // detect RVV 1.0 support by executing a v1.0 vsetivli under a SIGILL handler and ++ // recovering if it traps, but on RVV 0.7.1 hardware (e.g. T-Head Xuantie C906/C910/C920) ++ // the illegal instruction does not recover cleanly through sigsetjmp/siglongjmp -- it ++ // brings the whole process down instead of returning false, which is exactly the crash ++ // this patch works around. Hardcoding "unsupported" routes every mayiuse(gv) caller ++ // through OpenVINO's existing non-RVV fallback (scalar/generic node executors, and ++ // Snippets/Subgraph tokenization already turns itself off via is_supported_isa() when ++ // mayiuse(gv) is false) instead of ever attempting to execute or JIT-compile RVV 1.0 ++ // code on this target. ++ return false; + } + + bool can_compile_zvfh() { +- static const bool status = can_execute_generated_code(); +- return status; ++ // See can_compile_rvv100() above: RVV support is unconditionally disabled for this ++ // target, so the (narrower, RVV-1.0-dependent) Zvfh probe must never run either. ++ return false; + } + + } // namespace +-- +2.43.0 + From 16a592a0a488204554d68f6a1517e6d54208546a Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 25 Sep 2026 14:09:52 +0000 Subject: [PATCH 3/4] openvino: build oneDNN without RVV; keep mayiuse() off vector CSRs Run 35995279535 (with patch 0001 applied and compiled) still died with SIGILL at exactly the same point as run 35480766550: ov.get_version() printed, print(core.available_devices) did not (podman run -t, so stdout is line-buffered and the missing line is real). So the RVV 1.0 probe was not the crash. The crash is a static initializer of libopenvino_riscv_cpu_plugin.so, run by the dynamic loader when available_devices dlopens the CPU plugin: .init_array entry 17 points at plugin offset 0x34926a, whose first instruction is `vsetivli zero, 8, e8, mf2, ta, ma` (a GCC auto-vectorized zero-fill of globals, followed by vmv.v.i/vse8.v). vsetivli and fractional LMUL do not exist in RVV 0.7.1, and no probe or HWCAP check runs before it. It is the only one of the plugin's 26 initializers with vector code. Reproduced from the CI artifact under QEMU: QEMU_CPU=rv64,v=false dies with SIGILL right after ov.Core() and before available_devices prints, si_addr = plugin base + 0x34926a; with v=true,vext_spec=v1.0 the whole smoke test passes (which is why upstream's QEMU-with-V CI is green). Where the vector code comes from: oneDNN's cmake/platform.cmake, for DNNL_TARGET_ARCH=RV64, appends -march=rv64gcv to all of oneDNN's C/C++ flags whenever the compiler can build RVV intrinsics (the CI log says "Using RV64 march flag: -march=rv64gcv"). There is no runtime dispatch behind it, and oneDNN is linked statically into the plugin. The plugin's own sources and every other library in the wheel are built rv64gc; the riscv64 JIT emitters generate vector code at run time only. Pre-seed CAN_COMPILE_RVV_INTRINSICS=OFF so oneDNN takes its existing non-RVV branch: -march=rv64gc, DNNL_RISCV_USE_RVV_INTRINSICS off, the rvv_* sources excluded, and every reference to them already compiled out by #ifdef. Checked by configuring oneDNN 2026.3.1's submodule with it in the manylinux_riscv64 image ("Using RV64 march flag: -march=rv64gc", 177 of 180 TUs left), and by compiling the guarded TUs (gemm.cpp, cpu_matmul_list.cpp, cpu_pooling_list.cpp): they build, with zero vector instructions and no V in Tag_RISCV_arch. Patch 0002 closes the one remaining unguarded vector instruction on the compile_model() path: mayiuse() constructs Xbyak_riscv::CPU for every query, and its constructor runs a JIT-generated `csrr a0, vlenb` with no SIGILL handler whenever AT_HWCAP has V. The gv case now checks the (hardcoded) RVV 1.0 probe first and only g builds the CPU object. It is defensive -- not yet seen crashing by itself -- and compiles with -Wall -Wextra -Werror in the manylinux_riscv64 image. --- .github/workflows/build-openvino.yml | 3 + ...-read-vlenb-unless-RVV-1.0-is-usable.patch | 66 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 patches/openvino/2026.3.1/0002-cpu-riscv64-do-not-read-vlenb-unless-RVV-1.0-is-usable.patch diff --git a/.github/workflows/build-openvino.yml b/.github/workflows/build-openvino.yml index 5aaf454a02c..a41ac65538b 100644 --- a/.github/workflows/build-openvino.yml +++ b/.github/workflows/build-openvino.yml @@ -120,8 +120,11 @@ jobs: /usr/bin/cmake --build /tmp/onetbb-build --parallel "$(nproc)" /usr/bin/cmake --install /tmp/onetbb-build + # oneDNN compiles all of itself with -march=rv64gcv whenever the compiler can, with no + # runtime gate; its static initializers then SIGILL at plugin dlopen on non-RVV-1.0 cores. /usr/bin/cmake \ -DCMAKE_BUILD_TYPE=Release \ + -DCAN_COMPILE_RVV_INTRINSICS=OFF \ -DENABLE_INTEL_GPU=OFF \ -DENABLE_INTEL_NPU=OFF \ -DENABLE_SAMPLES=OFF \ diff --git a/patches/openvino/2026.3.1/0002-cpu-riscv64-do-not-read-vlenb-unless-RVV-1.0-is-usable.patch b/patches/openvino/2026.3.1/0002-cpu-riscv64-do-not-read-vlenb-unless-RVV-1.0-is-usable.patch new file mode 100644 index 00000000000..3dcffd90167 --- /dev/null +++ b/patches/openvino/2026.3.1/0002-cpu-riscv64-do-not-read-vlenb-unless-RVV-1.0-is-usable.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Fri, 25 Sep 2026 14:30:00 +0000 +Subject: [PATCH] cpu: riscv64: do not read vlenb unless RVV 1.0 is usable + +mayiuse() constructs the Xbyak_riscv::CPU singleton on every call, for +every ISA. That constructor JIT-compiles and runs `csrr a0, vlenb` whenever +AT_HWCAP advertises V -- with no SIGILL handler around it, unlike the RVV 1.0 +probe in can_compile_rvv100(). On cores whose kernel sets the V hwcap but +whose vector unit is not RVV 1.0 (T-Head Xuantie C906/C910/C920, RVV 0.7.1), +a vector-CSR access is exactly the kind of instruction that can trap, and +nothing would catch it. The only callers outside this file ask for gv or +gv_zvfh, reached from compile_model() (transformation pipeline, eltwise +executor), so this sits on every model compilation. + +Evaluate the RVV 1.0 probe first in the gv case, and build the CPU object +only for the g case. With can_compile_rvv100() hardcoded to false by the +previous patch, mayiuse(gv)/mayiuse(gv_zvfh) now return false without +executing any vector instruction. Behaviour on RVV 1.0 hardware with the +probe restored is unchanged: the probe runs under its own SIGILL handler +before the HWCAP/vlenb query instead of after it. + +This one is defensive: the SIGILL observed on the CI hardware comes from +oneDNN being compiled with -march=rv64gcv (a static initializer at plugin +dlopen time), which is handled at configure time, not here. It has not been +seen crashing on hardware by itself, so there is no backtrace to report yet. + +Upstream-Status: To upstream [defensive fix, no hardware crash observed from this path yet to accompany a report] +--- + .../intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp +index cc2293de..d3e15af7 100644 +--- a/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp ++++ b/src/plugins/intel_cpu/src/nodes/kernels/riscv64/cpu_isa_traits.cpp +@@ -96,19 +96,23 @@ bool can_compile_zvfh() { + } // namespace + + bool mayiuse(const cpu_isa_t cpu_isa) { +- const auto cpu = CPU::getInstance(); ++ // Xbyak_riscv::CPU's constructor JIT-executes `csrr a0, vlenb` with no SIGILL handler whenever ++ // AT_HWCAP advertises V. Build it only for `g` (which nothing outside this file queries), and have ++ // `gv` consult the RVV 1.0 probe first so that it never gets that far on this target. + switch (cpu_isa) { +- case g: ++ case g: { ++ const auto& cpu = CPU::getInstance(); + return cpu.hasExtension(RISCVExtension::I) && cpu.hasExtension(RISCVExtension::M) && + cpu.hasExtension(RISCVExtension::A) && cpu.hasExtension(RISCVExtension::F) && + cpu.hasExtension(RISCVExtension::D); ++ } + // cpu.hasExtension(RISCVExtension::V) checks only RVV support on the device. + // To figure out RVV version, we try to execute code with RVV1.0 instructions. + // If there is no `SEGILL`, the device supports RVV1.0. + // Otherwise we consider that there is no RVV support + // [TODO] If needed, support other RVV versions + case gv: +- return mayiuse(g) && cpu.hasExtension(RISCVExtension::V) && can_compile_rvv100(); ++ return can_compile_rvv100() && mayiuse(g) && CPU::getInstance().hasExtension(RISCVExtension::V); + case gv_zvfh: + return mayiuse(gv) && can_compile_zvfh(); + case isa_all: +-- +2.43.0 + From 5d35855a65939b6b8c0d6ad8990c491409a5f8c7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 27 Sep 2026 09:22:54 +0000 Subject: [PATCH 4/4] openvino: skip pytest on cp314t, bound the test step at 60 minutes Run 36145686942 was cancelled at the 24h job limit, but not by the build: the portable-oneTBB/no-RVV build finished in 12h20m (14:14 to 02:34 UTC), all four wheels were built and uploaded, and the cp312/cp313/cp314 legs each passed the smoke check and 7019 passed / 61 skipped in about three minutes. The earlier SIGILL is gone. The cp314t leg passed the smoke check too (Core(), ['CPU'], a relu compiled and run on CPU), then hung in pytest right after test_async_infer_request.py::test_start_async[True] from 02:49 until the cancellation at 14:11, 11h22m without output. The next test, test_start_async[False], sets a Python callback that runs on an inference worker thread while the main thread waits. The free-threaded build (ENABLE_GIL_PYTHON_API=OFF) is the only one that hangs there. Keep building and smoke-testing cp314t, since upstream ships it, but run the pytest suite only on the GIL interpreters. Also give the test step its own 60-minute timeout. Upstream's job_python_api_tests.yml caps its run at 30, and without a limit here a hang holds the runner until the 24h job limit. --- .github/workflows/build-openvino.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-openvino.yml b/.github/workflows/build-openvino.yml index a41ac65538b..4094dd01214 100644 --- a/.github/workflows/build-openvino.yml +++ b/.github/workflows/build-openvino.yml @@ -189,12 +189,16 @@ jobs: result = compiled(np.array([[-2.0, -1.0, 0.0, 3.0]], dtype=np.float32))[0] assert np.array_equal(result, [[0.0, 0.0, 0.0, 3.0]]), result' - tests=/openvino/src/bindings/python/tests - "${python_exe}" -m pytest -v \ - "${tests}/test_runtime" \ - "${tests}/test_graph" \ - "${tests}/test_transformations" \ - -m 'not template_extension' + # cp314t passes the smoke check above but deadlocked in test_start_async (a Python + # callback run from an inference worker thread) for 11h; the GIL builds pass all 7019. + if [ "${python_tag}" = "${python_impl}" ]; then + tests=/openvino/src/bindings/python/tests + "${python_exe}" -m pytest -v \ + "${tests}/test_runtime" \ + "${tests}/test_graph" \ + "${tests}/test_transformations" \ + -m 'not template_extension' + fi fi done EOF @@ -221,6 +225,7 @@ jobs: if-no-files-found: error - name: Test wheels + timeout-minutes: 60 # upstream's job_python_api_tests.yml caps its own run at 30 run: | podman run -t \ --log-driver=none \