Skip to content

Port CUDA sources to MUSA in place#87

Open
yeahdongcn wants to merge 9 commits into
mainfrom
xd/inplace-csrc-porting
Open

Port CUDA sources to MUSA in place#87
yeahdongcn wants to merge 9 commits into
mainfrom
xd/inplace-csrc-porting

Conversation

@yeahdongcn

@yeahdongcn yeahdongcn commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

What

Port CUDA sources to MUSA in place as the single default path of the setuptools build:

  • Drive torch_musa's SimplePorting with musa_dir_path == cuda_dir_path and an identity extension map, so ported .cu/.cuh sources keep their original names and locations — no <dir>_musa mirror, no .cu to .mu / .cuh to .muh rename.
  • Original #include and source paths therefore resolve as-is: no per-file include rewriting, and no second source tree that could cause cross-tree #pragma once ODR.
  • Restrict in-place content substitution to portable C/C++/CUDA sources and headers, leaving build scripts, templates, docs, and MUSA-native .mu/.muh files byte-for-byte unchanged.
  • Port each source's parent directory alongside the include roots.
  • Move the torch/headeronly/util/* to c10/util/* header rewrites into the data-type mappings.
  • Publish the fixed in-place behavior as torchada 0.1.70. No 0.1.70 artifact was published before this PR, so this remains the final release identity.

Why

Consumers that drive this build (vLLM-MUSA, SGLang sgl-kernel) otherwise carry hand-maintained patches whose only job is to rewrite #include directives so mirrored and renamed ported sources resolve. Porting in place removes that class of downstream patch.

MUSA-native .mu/.muh files must not undergo CUDA-to-MUSA substitutions: they are already MUSA source, and rewriting their inline assembly caused the runtime regression found during on-device verification. A native MUSA source that includes a ported third-party header should use its real .cuh name; .muh remains reserved for MUSA-native headers.

Verification

  • Mapping suite: 83 passed, 4 build-gated skipped.
  • Version/platform suite: 10 passed; changed-file Black and isort checks passed.
  • Built torchada-0.1.70-py3-none-any.whl successfully and verified its wheel metadata reports version 0.1.70.
  • Real SimplePorting container check: .cu/.cuh/.h ported in place; non-source and MUSA-native files remained byte-identical; no <dir>_musa mirror was created.
  • Fresh vLLM-MUSA mp_31 builds succeeded locally and on an S5000 using this code.
  • Single-GPU vLLM-MUSA smoke passed on one visible S5000 with TP=1, Qwen3-0.6B BF16, FlashAttention 3, and valid non-empty generation. The final 0.1.70 correction changes only version metadata/tests.

Cross-repository consumer: MooreThreads/vllm-musa#95.

torch_musa's SimplePorting is driven in place (destination == source) with
an identity extension map, so ported .cu/.cuh sources keep their names and
locations. Original #include and source paths resolve as-is: no per-file
include rewriting, and no second source tree that could cause cross-tree
#pragma once ODR.

In-place content substitution is restricted to compiled C/C++/CUDA sources
and headers, so build scripts, templates, and docs in a ported directory are
left byte-for-byte unchanged. Each source's parent directory is ported
alongside the include roots. The headeronly->c10 header rewrites live in the
data-type mappings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@augmentcode

augmentcode Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR switches torchada’s CUDA→MUSA extension porting to run in place (no <dir>_musa mirror and no .cu/.cuh renaming), so original include paths and source paths keep working without downstream patching.

Changes:

  • Bump version to 0.1.70 (pyproject + __init__.__version__)
  • Make EXT_REPLACED_MAPPING an identity map for cu/cuh (stop .cu→.mu, .cuh→.muh)
  • Remove mapping rules that rewrote .cuh includes to .muh in cuda_runtime
  • Add data-type mapping rewrites for missing torch/headeronly/util/* headers to equivalent c10/util/* includes
  • Patch torch_musa.SimplePorting.modify_file to (a) only substitute within compiled sources/headers and (b) read-before-write to support src==dst porting
  • Update MUSA BuildExtension workflow to port project-local include roots/source dirs in place and keep ext.sources/include_dirs unchanged
  • Adjust tests to assert no mirror directory is created and that .cu/.cuh names remain unchanged

Technical Notes: In-place compilation relies on the patched _is_musa_file path selecting MUSA compile rules for .cu/.cuh while avoiding include-path rewriting and cross-tree header ODR issues.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/torchada/utils/cpp_extension.py
Comment thread src/torchada/utils/cpp_extension.py Outdated
Comment thread src/torchada/utils/cpp_extension.py Outdated
Comment thread src/torchada/_mappings/data_types.py
Comment thread src/torchada/utils/cpp_extension.py
Use os.rmdir (not shutil.rmtree) for the leftover <dir>_musa so a non-empty
directory is never force-deleted. Check the full _PORTABLE_SOURCE_EXTS set in
the port gate so a directory of only .cc/.cpp sources is ported, not skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yeahdongcn

yeahdongcn commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

On-device verification caught a runtime regression — root-caused and fixed in 4a0126c (torchada 0.1.70).

The first in-place build passed build + import (rc=0) but produced degenerate garbage output ("rounds rounds…") on-device for Qwen3-8B (bf16 and FP8), while the pre-PR mirror build served correctly on the same host/image/model.

Root cause. In-place porting walks every file under a ported include root (csrc/ is one). Because .mu/.muh were in the porting allowlist, SimplePorting applied the CUDA→MUSA content mapping to the hand-written MUSA-native csrc/musa/*.{mu,muh} as well. The _mappings/compiler.py rule 'asm volatile' → 'if(0) asm volatile' — which neutralizes un-assemblable CUDA PTX — then guarded csrc/musa/vec_utils.muh's vload16_byp_slc inline-asm 16-byte load with if(0), so the load never executes and dst is returned uninitialized. That garbage feeds RMSNorm (fused_add_rmsnorm.mu) / GEMV (gemv.mu) → garbage logits → repeated-token output. The mirror build escaped because it compiled the untouched original .mu/.muh (its corrupted copies landed in the unused csrc_musa/ mirror).

Ruled out along the way: mcc codegen is byte-identical for .cu vs .mu under -x musa; the forward-path includes resolve to the single correct copy; a ccache-disabled rebuild still garbaged (so it was never stale objects).

Fix (4a0126c). Exclude .mu/.muh (MUSA-native — already MUSA, need no porting) from content substitution via a new _MUSA_NATIVE_EXTS, leaving them byte-identical. Genuinely-CUDA .cu under csrc/musa/ (e.g. quantization/*.cu using cudaStream_t/__nv_fp8_e4m3) still port correctly. 90a43e7 aligns a stale mirror-era build test with the in-place contract.

Verified on-device (S5000, native mp_31, image vllm-musa-0706-green:smoke, torchada 0.1.70, 256-tok prompt, all else held constant): PASS qwen3_8b_bf16 →Paris, PASS qwen3_8b_fp8 →Paris (FLASH_ATTN), PASS deepseek_v2_lite_fp8 →Paris (FLASH_MLA), PASS qwen35_35b_a3b_fp8 →Paris (fused MoE); vec_utils.muh asm preserved (no if(0)).

yeahdongcn and others added 2 commits July 9, 2026 16:36
In-place porting walks every file under a ported include root and applied the
CUDA->MUSA content substitution to hand-written MUSA-native .mu/.muh sources as
well. The asm-volatile neutralization rule -- which guards un-assemblable CUDA
PTX with if(0) -- then disabled valid MUSA inline asm (e.g. vec_utils.muh's
vectorized 16-byte load), leaving the result uninitialized and producing garbage
kernel output while still building cleanly.

Gate content substitution to CUDA/C++ extensions only and leave .mu/.muh
byte-identical: they are already MUSA and need no porting. Add _MUSA_NATIVE_EXTS
alongside _PORTABLE_SOURCE_EXTS and skip substitution for it in modify_file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
test_build_mixed_sources_extension still asserted the old <dir>_musa mirror and
.cu->.mu rename, contradicting its own docstring and the in-place porter. Assert
instead that no csrc_musa mirror is created and that sources keep their original
names and locations, matching test_cu_and_mu_coexist_in_place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yeahdongcn yeahdongcn force-pushed the xd/inplace-csrc-porting branch from e8f7086 to 90a43e7 Compare July 9, 2026 08:36
yeahdongcn and others added 4 commits July 9, 2026 16:44
Bump the torchada>= install-pin examples in README.md / README_CN.md and the
benchmark_history baseline version label to 0.1.70.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yeahdongcn

yeahdongcn commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

Version correction applied in 906a2d7: the final release remains torchada 0.1.70 because no 0.1.70 artifact has been published yet.

  • Runtime code is unchanged from the previously verified head.
  • Version/platform tests: 10 passed.
  • Changed-file Black, isort, and git diff --check passed.
  • Built torchada-0.1.70-py3-none-any.whl and verified its metadata reports version 0.1.70.
  • vLLM-MUSA PR #95 now consistently requires torchada>=0.1.70.

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