Skip to content

cuda: declare the qwen3_5 backend - #77

Draft
xiaoyu-xyz wants to merge 5 commits into
ThinkFlowLab:mainfrom
xiaoyu-xyz:cuda-qwen3_5-manifest
Draft

xiaoyu-xyz wants to merge 5 commits into
ThinkFlowLab:mainfrom
xiaoyu-xyz:cuda-qwen3_5-manifest

Conversation

@xiaoyu-xyz

@xiaoyu-xyz xiaoyu-xyz commented Oct 4, 2026 •

Copy link
Copy Markdown

Purpose

#19 added the kernels under src/backends/cuda/qwen3_5/ without declaring them, so the directory has kernel sources and no manifest. #25 defines the manifest and its checker, and against main the checker reports exactly that:

[error] qwen3_5: has kernel sources (attention.cu, common.cuh, elementwise.cu)
        but no qwen3_5.backend.json manifest

Three commits:

  1. The manifest. Values come from the merged files rather than from me: build.sh writes libqwen3_5_cuda.so and defaults arch to CUDA_COMPUTE_CAP-or-89 in a single -gencode flag, and the directory README says the tensor-core kernels need sm_80 or newer.
  2. The ABI version. The first commit said abi_version: 1; ops.h defines CS1_ABI_VERSION 4. Nothing caught that until cuda: add the backend contract and its checker #25's checker learned to read the header macro, which is what surfaced it.
  3. The CI step. ci.yml gains a cuda-contract job running src/backends/cuda/tests and check_contract.py --repo-root .. No CUDA toolkit, no GPU: both read files as text.

status is experimental, not validated. #19 validated the kernels, but a validated manifest asserts a tolerance and a reference entrypoint, and those are twu3202's to state rather than mine. Promoting it once a tolerance is recorded is a one-line change.

Merge order

This depends on #25, and the CI step needs both. The checker exits 1 on a tree with kernels and no declaration, which is main's state without this manifest — so the CI step cannot land before it. And the step runs src/backends/cuda/tests and check_contract.py, both of which arrive in #25, so it cannot land before that either. The job comments say so, and its failure message names #25 rather than reporting a bare missing file.

Test Result

Simulating the two CI steps against #25@6b3f0e6 + #77@67c7b65: 66 tests, OK and check_contract exit 0 with 1 backend(s), 0 error(s), 0 warning(s).

The manifest itself: parses, all nine declared sources exist, the directory holds no source file the manifest omits, and the ABI check cross-checks ops.h's CS1_ABI_VERSION 4 against abi_version: 4.

Deliberately not included: numerics and reference. Both are about a parity claim this does not make.

ThinkFlowLab#19 added the kernels under src/backends/cuda/qwen3_5/ but left them
undeclared, so the directory has kernel sources and no manifest. ThinkFlowLab#25 defines the
manifest and its checker, and running that checker against main reports exactly
that:

    [error] qwen3_5: has kernel sources (attention.cu, common.cuh,
            elementwise.cu) but no qwen3_5.backend.json manifest

This adds the declaration, with the values the merged files already state:

- sources: the nine kernel and header files, from the directory listing.
- build.script and build.output: what build.sh actually writes,
  libqwen3_5_cuda.so.
- build.default_arch 89 and build.architectures [89]: build.sh defaults `arch` to
  CUDA_COMPUTE_CAP-or-89 and passes it to a single -gencode flag.
- build.min_capability 80: the README says "Tensor-core kernels need sm_80 or
  newer".

status is `experimental`, not `validated`. ThinkFlowLab#19 validated the kernels, but this
manifest is written by someone other than their author and a `validated` manifest
asserts a tolerance and a reference entrypoint, which are twu3202's to state. A
declaration that the backend exists and how it builds is useful on its own and
does not put words in anyone's mouth; promoting it is a one-line change once the
tolerance is recorded.

Checked with the checker from ThinkFlowLab#25: `1 backend(s), 0 error(s), 0 warning(s)`, and
with discover_buildable.py from #2, which reports it as compile-checkable.
The manifest said abi_version 1. ThinkFlowLab#19's ops.h defines CS1_ABI_VERSION 4, so the
declaration disagreed with the library it describes.

Nothing caught it when this was written, because the checker did not read
headers. ThinkFlowLab#25 now does: it reads the `#define <PREFIX>_ABI_VERSION N` out of the
declared sources and requires the manifest to match, which is what surfaced this.

    abi_version is 1 but ops.h defines CS1_ABI_VERSION 4

also strengthens the description in the same PR.
Nothing ran `src/backends/cuda/tests` or `check_contract.py`: the only Python
discovery in this workflow is `tests/benchmarks`.

Two things make this land here rather than with the checker. The step needs
`check_contract.py`, which arrives in ThinkFlowLab#25. And the checker exits 1 on a tree that
has kernels but no declaration for them, which is main's state until the manifest
in this branch lands — so wiring it up first would redden main. Both are stated
in the job's comment and in its failure message, so a wrong merge order is
self-explanatory rather than a bare "file not found".

No CUDA toolkit and no GPU: the checker and its tests read files as text.
The first version ran `discover -s src/backends/cuda/tests`, which finds the
contract checker's tests and nothing else. Kernel tests sit beside their kernels
-- `src/backends/cuda/scoring/test_scoring.py` is 17 of them -- so a backend that
merges later would have had no test coverage at all while appearing to be
covered.

The step now loops over `src/backends/cuda/*/` and discovers in any directory
holding `test_*.py`. `-t` has to point at the directory itself rather than the
repository root: the kernel directories are not packages, so `-t .` fails with
"Start directory is not importable".

Simulated on a tree carrying both: 17 from `scoring/`, 66 from `tests/`.
The job failed on its own branch, in five seconds:

    ImportError: Start directory is not importable: 'src/backends/cuda/tests'

The checker and its tests live in ThinkFlowLab#25, so on ThinkFlowLab#77's tree there is nothing to run.
The guard I wrote checked for `check_contract.py` alone and ran *after* the test
step, so the first step failed before the guard was reached and the message
explaining the dependency never printed.

Now a first step decides whether the prerequisites are present and the three
steps run only if they are; otherwise the job reports a notice naming ThinkFlowLab#25 and
passes. That is what makes either merge order work: green on this branch before
ThinkFlowLab#25 lands, and running by itself once it does.

Verified both ways: with ThinkFlowLab#25's files absent all three steps skip, and with them
present 66 checker tests, 66 kernel tests and the contract check all pass.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant