CI: build the prebuilts from this repository, not from a fetched tarball - #8
Conversation
The pipeline resolved an upstream release tag, fetched that tree, applied
the patch set in patches/, and built the result. That made every
published binary depend on a foreign repository at build time and left
three fixes living as diffs that had to be kept applying to a tree we do
not control.
All three are already commits here, merged as PRs 2, 3 and 4. So build
this checkout. patches/ is deleted; there is nothing left to re-apply.
The tag still names the upstream release the tree descends from, read
from our own history rather than from an API, with the head sha as the
-u suffix:
master-813-bfbef5b-u22e2879
Two details worth keeping.
HIGHEST reachable release, not nearest. git describe answers "nearest",
and on a merge-shaped history that is wrong: this tree reaches
master-813 through a merge 73 commits back and master-811 on its own
line 13 commits back, so describe names the build after 811 and
understates what it contains.
The -u suffix is now always present, which is what it should have been.
Studio's installer treats a -u tag as mirror-only and goes straight to
this repository's releases instead of trying an upstream download that
is guaranteed to 404. A build of ours is never a stock upstream build,
so it should never carry a bare upstream tag.
Supply-chain aging is kept and re-pointed: it now guards the age of the
upstream release the tree descends from rather than the moment a
release appeared. Our own commits on top are reviewed here, so they are
not what the delay is for.
assemble_metadata keeps its --patches flag, always empty, so existing
manifest readers do not have to change.
The prebuilts now build this tree, but that alone only ships what is already merged. The llama.cpp pipeline exists to ship a reviewed mix: an aged upstream base plus a set of pull requests pinned to exact commits, merged at build time. This adds the same mechanism here. scripts/unsloth/pr-set.json lists PRs to merge, each pinned to a 40-hex commit copied from the PR's commits tab. Only that commit is built, so an author pushing more commits cannot change what the nightly ships. Non-open required pins fail the build rather than silently publishing without them, because dropping a pin changes the tag and would ship a quietly different binary under a new name. additive_merge.py, vendored from unslothai/llama.cpp, resolves the one conflict shape that is mechanical (both sides only added, at a place the merge base had nothing) and refuses to guess at anything else. One deliberate difference from llama.cpp. There the base is a pristine upstream release, so every Unsloth change has to stay pinned and open, and merging one into fork master drops it from the nightly. Here the base is our own tree, so a merged fix is simply in it and its pin is deleted. That is why the three MiniMax-H3 fixes need no pins. Only PRs in this repository may be pinned. To carry a fix that exists as an upstream pull request, vendor it here as a PR first and pin that. The build fetches from nowhere else. The tag suffix absorbs the set: with no pins it is the head sha, with pins it hashes the pinned number:sha pairs together with the head sha, so a repin or a reorder yields a new tag and a rebuild while an unchanged set still matches an existing release and skips. The existing -u shape is kept rather than llama.cpp's -mix-, because Studio's installer keys mirror-only resolution on it. Verified locally against this tree: the schema gate passes, an empty set yields master-813-bfbef5b-u692a7c8, a one-pin set yields a different suffix, and both match the installer's mirror-only pattern.
|
Second commit on this branch answers the question the first one only half answered. The goal for these prebuilts is the one
{
"prs": [
"https://github.com/unslothai/stable-diffusion.cpp/pull/8/commits/<40-hex-sha>"
]
}Only that commit is built, so an author pushing more commits cannot change what the nightly ships. The same guards as llama.cpp: a schema gate, a check that the pinned sha really is a commit of that PR (a wrong paste would build arbitrary code while the manifest blames a PR number), and a rule that a non-open required pin fails the build rather than silently publishing without it, since dropping a pin changes the tag and would ship a quietly different binary under a new name. The gate lives in
One deliberate difference from llama.cppThere the base is a pristine upstream release, so every Unsloth change has to stay pinned and open, and merging one into fork master silently drops it from the nightly. Here the base is our own tree, so a merged fix is simply in it and its pin is deleted. That is why the three MiniMax-H3 fixes need no pins at all: they are commits, not diffs to re-apply. The other difference is cosmetic. llama.cpp tags a mix Only this repository's PRs may be pinnedTo carry a fix that exists as an upstream pull request, vendor it here as a PR first and pin that. The build fetches from nowhere else. Verified locally against this tree |
The CPU/Apple matrix rests on the assumption that a GPU host runs the diffusers path instead. MiniMax-H3 breaks that assumption: its diffusers path wants ~68.5 GB of VRAM, so every consumer card falls back to the GGUF engine, and on Linux that engine had no accelerated build to fall back to. Measured on one box, 65 s/step at 320x192 across 96 CPU threads, against 21.5 s/step at 960x544 from a local CUDA build of the same tag: four hours per clip versus eleven minutes. The new leg is continue-on-error and is not in the coverage gate, which still lists exactly the five CPU/Apple assets. assemble collects bundles by the sd-*-bin-* pattern, so the CUDA asset is published when it built and simply absent when it did not; a broken CUDA toolchain can never hold back the assets Studio falls back to. sm_75 through sm_120, which is the first toolkit able to emit sm_100 and sm_120 and covers everything from Turing up. The CUDA runtime libraries are copied in beside the binaries with an $ORIGIN rpath, because a host with an NVIDIA driver does not necessarily have a CUDA runtime installed and we must not lean on the copies torch keeps. package_bundle matched runtime libraries on Path.suffix, which reads ".12" for libcudart.so.12 and dropped it. It now matches the ".so." infix as well, so a versioned soname ships under the exact name DT_NEEDED spells.
e0741d5 to
994faa9
Compare
cuda-toolkit installs sub-packages as cuda-<name>-12-8, and cuBLAS does not use that prefix, so apt could not find cuda-cublas-12-8 or cuda-cublas_dev-12-8 and the leg died before it compiled anything. They belong in non-cuda-sub-packages as libcublas and libcublas-dev. cudart-dev joins the list too, since cudart on its own is the runtime and carries no headers to compile against. The libcublas debs land in the system multiarch directory rather than under the toolkit root, so the bundling step now searches both.
|
The CUDA leg is green and I verified the asset on a real GPU box rather than trusting the build. Run: Downloaded
Running it: Compute capability 10.0 is The three worries in the PR body are settled:
Two follow-ups, neither blockingSize. The bundle is 1.15 GiB compressed, 1.55 GiB unpacked. Version stamping. |
The pipeline resolved an upstream release tag, fetched that tree, applied the patch set in
patches/, and built the result. That made every published binary depend on a foreign repository at build time, and it left three fixes living as diffs that had to be kept applying to a tree we do not control.All three are already commits here, merged as #2, #3 and #4. So build this checkout instead.
patches/is deleted; there is nothing left to re-apply, and the "every patch must be open upstream, delete on merge" bookkeeping goes with it.Tag naming
The tag still names the upstream release the tree descends from, read from our own history rather than from an API, with the head sha as the
-usuffix:Two details worth calling out.
Highest reachable release, not nearest.
git describeanswers "nearest", and on a merge-shaped history that is the wrong answer. This tree reachesmaster-813through a merge 73 commits back, andmaster-811on its own line 13 commits back, sodescribenames the build after 811 and understates what it actually contains:The
-usuffix is now always present, which is what it should have been all along. Studio's installer treats a-utag as mirror-only and goes straight to this repository's releases, instead of first trying an upstream download that is guaranteed to 404. A build of ours is never a stock upstream build, so it should never wear a bare upstream tag.What is unchanged
Supply-chain aging is kept, re-pointed: it now guards the age of the upstream release the tree descends from, rather than the moment a release appeared. Our own commits on top are reviewed here, so they are not what the delay is for.
assemble_metadata.pykeeps its--patchesflag, always empty, so existing manifest readers do not have to change.sd-prebuilt-manifest.jsonrecords the commit, which is now the precise answer to "what is in this binary".Asset names, the coverage gate, the fingerprint gate and the atomic draft-then-publish are all untouched.
Follow-up
The next scheduled run publishes a new tag, so
studio/install_sd_cpp_prebuilt.py'sDEFAULT_TAGin unslothai/unsloth needs bumping to it once that release exists. The current pin resolves fine until then.Added: a Linux CUDA prebuilt
This pipeline was written on the premise that a GPU host runs diffusers/torch, so the native engine only needed CPU and Apple builds. MiniMax-H3 falsifies that premise. Its diffusers path wants roughly 68.5 GB of VRAM, so every consumer card falls back to the GGUF engine, and on Linux that engine had no accelerated build to fall back to.
Measured on one box, same tag, same model:
-DSD_CUDA=ONHigher resolution and eleven minutes instead of four and a half hours.
The new
build-linux-cudajob iscontinue-on-errorand is deliberately not in the coverage gate, which still lists exactly the same five CPU/Apple assets.assemblecollects bundles with thesd-*-bin-*pattern, so the CUDA asset is published when it built and simply absent when it did not. A broken CUDA toolchain cannot hold back the assets Studio falls back to.Details worth review:
sm_75;80;86;89;90;100;120. 12.8 is the first toolkit that can emitsm_100(B200) andsm_120(RTX 50), and nothing older than Turing is a realistic host for a 20 GB video denoiser. The existing Windows CUDA leg inbuild.ymluses the same list plus 61 and 70.libcudart.so.12,libcublas.so.12andlibcublasLt.so.12are copied beside the binaries with an$ORIGINrpath.package_bundle.pyhad to change to allow that. It matched runtime libraries onPath.suffix, which reads.12forlibcudart.so.12, so the copied libraries would have been silently dropped from the zip and the binaries would have shipped with unsatisfiableDT_NEEDEDentries. It now also matches the.so.infix, so a versioned soname ships under the exact name the linker asks for. Verified locally against a fixture directory.No installer change is needed on the Studio side:
resolve_release_assetalready maps a Linuxcudaaccelerator onto acudaasset token, and_LINUX_ACCEL_MARKERSalready containscuda.The open questions are all things only a real run can answer: whether the toolkit plus the build fits in the freed disk, how long seven architectures take against the job timeout, and whether the bundled runtime actually resolves on a clean host. A dispatch run is in flight.