Repository navigation
Conversation
luhenry
added a commit
that referenced
this pull request
Oct 15, 2026
luhenry
marked this pull request as draft
October 15, 2026 12:13
luhenry
added a commit
that referenced
this pull request
Oct 15, 2026
mip: the real compiled dependency is the separate cbcbox package (already tracked here, PR #3260); mip itself is a pure cffi dlopen wrapper with no native content of its own. cyipopt: PyPI ships source-only by design across every platform; upstream's own README recommends conda-forge instead. pytidylib: pure ctypes wrapper that dlopen's the system libtidy, already packaged for riscv64 on Debian/Ubuntu. pycld3: parked as stale/unmaintained upstream (last release 2021, wheels capped at cp39), not a fresh riscv64-specific gap.
cbcbox ships a prebuilt binary distribution of the CBC MILP solver
(COIN-OR Branch and Cut): a py3-none-manylinux*_{x86_64,aarch64} wheel
built by compiling OpenBLAS, SuiteSparse AMD, and the CoinUtils/Osi/
Clp/Cgl/Cbc stack from source and bundling the resulting binaries and
shared libraries. The architecture-specific code is cleanly gated
behind an x86_64 check (AVX2/Haswell variants only); the generic build
path already exercised on aarch64 compiles with a plain Fortran/C++
toolchain and has no riscv64-blocking assumptions.
Mirror the upstream wheel.yml's Linux ARM64 jobs (compile generic +
compile debug, then package with cibuildwheel, compilation skipped)
on manylinux_2_39_riscv64, since manylinux2014 (upstream's own tag for
x86_64/aarch64) predates riscv64 entirely. OpenBLAS's DYNAMIC_ARCH
build supports riscv64 natively (RISCV64_GENERIC/ZVL128B/ZVL256B
kernels, confirmed against the pinned v0.3.31 source), Rocky Linux
10's riscv64 AppStream repo carries gcc-gfortran, and PyPI's patchelf
package (used directly by cbcbox's own bundling logic, not auditwheel)
ships a manylinux_2_31_riscv64 wheel.
cbcbox bumps its version on master without ever pushing a git tag for
most releases (v2.931-v2.933 are tagged, 2.934/2.935 are not), so pin
the exact commit that carries version = "2.935": its timestamp sits
about 3h20m before the 2.935 wheels were uploaded to PyPI, with no
further pyproject.toml change in between.
setup.py's custom bdist_wheel only maps linux_x86_64/linux_aarch64 to
their manylinux2014 wheel tag; patch in a linux_riscv64 mapping to
manylinux_2_39_riscv64 (patches/cbcbox/2.935/), since upstream has no
riscv64 CI of its own to carry this.
Note for later review: cbcbox's own bundling logic does not copy a
LICENSE file for the vendored OpenBLAS/SuiteSparse AMD (BSD) next to
the COIN-OR (EPL-2.0) ones it does copy -- a pre-existing gap on the
already-published x86_64/aarch64 wheels, not introduced by or specific
to this riscv64 port.
package_linux_riscv64's cibuildwheel step builds and tests the wheel as a single action, so its 61-case MILP-solve pytest suite inherits whatever is left of the job's timeout-minutes: 300. On run 42301146079 that suite was genuinely progressing (28/61 cases passed in ~4h52m, each taking minutes on this fleet's riscv64 hardware, not hung) when the job hit its 5h ceiling and GitHub Actions auto-cancelled it mid-test, losing the already-built wheel in the process (gotcha 598). Split testing into its own step, with the wheel uploaded first and its own generous-but-bounded timeout, and give the job enough headroom overall for the suite to actually finish.
_publish-wheel.yml now requires a matrix input (main's "publish: Validate effective wheel targets"), but this PR branch forked before that landed and cbcbox has never been merged to main, so build-cbcbox.yml never picked up the matching one-line update every already-published package's workflow got. The merge ref combines the new required-input _publish-wheel.yml with this branch's old build-cbcbox.yml, so any/every run has failed startup with "Input matrix is required, but not provided". Pass it the same way the mass-update commit did for every other package's publish job.
Real test log (run 43082576749, job 130832260080) shows a genuine SIGABRT, not just slowness: "Fatal glibc error: pthread_mutex_lock.c:94 (___pthread_mutex_lock): assertion failed: mutex->__data.__owner == 0", with the crash's own stack trace going through libopenblas.so!blas_memory_alloc -> pthread_mutex_lock while CBC was mid-solve under its own -threads=3 branch-and-bound parallelism (CoinUtils/ Clp's dense-factorization update calling into OpenBLAS's dgetrs_ from one of CBC's worker threads). This is the classic nested-parallelism hazard: CBC already parallelizes the search itself, and OpenBLAS's own pthread thread pool then additionally tries to parallelize the BLAS calls each worker thread makes, so N CBC threads each spawn M OpenBLAS threads fighting over OpenBLAS's shared memory-pool lock - evidently exposing a real bug in OpenBLAS's pthread-backend locking on this architecture. Re-examining the run's 5 reported failures with this in mind: the 2 "wrong objective value" assertions (mzzv11, neos-860300) and 2 of the 3 test_solve_parallel TimeoutExpired failures are downstream symptoms of this same corruption/abort, not independent slowness or correctness bugs in CBC's own solve logic - the previous diagnosis of "just needs a higher time limit" undersold what's actually happening here. OPENBLAS_NUM_THREADS=1 is this repo's existing, established fix for exactly this class of problem (see build-statsmodels.yml, build-pyscf.yml, build-torchft.yml, build-ligo-skymap.yml): forcing OpenBLAS's BLAS calls to stay single-threaded lets CBC's own -threads=N remain the only level of parallelism, removing the oversubscription/locking hazard rather than papering over it with a longer timeout.
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
cbcbox2.935Compiles OpenBLAS, SuiteSparse AMD, and the CoinUtils/Osi/Clp/Cgl/Cbc stack from source and bundles the resulting CBC MILP solver binaries and shared libraries. Upstream publishes no riscv64 wheel.
Mirrors upstream's
wheel.ymlLinux ARM64 jobs (compile generic + debug, then package with compilation skipped).Differs from upstream
manylinux_2_39_riscv64(dnf) instead ofmanylinux2014_aarch64/manylinux_2_28_aarch64(yum) - manylinux2014 predates riscv64 entirelyMatrix: cp313 only, compiled once - final wheel is tagged
py3-none, same as upstream's own aarch64/x86_64 jobsTesting: same as upstream
License: EPL-2.0 (CoinUtils/Osi/Clp/Cgl/Cbc); wheel also bundles OpenBLAS and SuiteSparse AMD (BSD-3-Clause) and libgfortran (GPL, from the build image) with no licence text for the first two, same as upstream's existing x86_64/aarch64 wheels.
Patches
0001-setup.py-map-riscv64-to-manylinux_2_39_riscv64-in-th.patch- Inappropriate [no riscv64 CI upstream to exercise it]. Without it the wheel is tagged plainlinux_riscv64, which pip rejects; riscv64-only.Not pre-validated locally (no docker/riscv64 available in this sandbox); CI runs cbcbox's own MIP-instance test suite.