Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,18 @@ the compatibility include directory on MUSA. Custom stable-ABI builds should
add `stable_compat_include_dir()` explicitly, and kernels that use `TORCH_BOX`
must force-include the path returned by `stable_compat_box_header()`. Both
helpers are available from `torchada.utils.cpp_extension`. The torch_musa 2.9
header backport runs lazily and best-effort at extension-build time; read-only
headers are left unchanged. A plain `import torchada` does not modify PyTorch or
torch_musa headers.
header backport runs lazily and best-effort at MUSA extension
build time on torch 2.9; read-only headers are left unchanged. Torch 2.11 and
newer provide the stable ABI directly, so the backport is skipped. A plain
`import torchada` does not modify PyTorch or torch_musa headers.

In-place CUDA-to-MUSA porting protects system include roots by default. Set
`TORCHADA_EXCLUDE_DIRS` to add excluded roots for your environment. Entries may
be directory paths or directory names and are separated by the platform path
separator; commas are also accepted. A name matches a complete path component,
so `TORCHADA_EXCLUDE_DIRS=torch_musa` excludes `/home/torch_musa` without the
full path. Explicit source directories remain eligible for porting even when
they are below an excluded root.

### Custom Ops

Expand Down Expand Up @@ -383,7 +392,7 @@ See `src/torchada/_mappings/` for 400+ mapping rules grouped by API domain.

```
# pyproject.toml or requirements.txt
torchada>=0.1.77
torchada>=0.1.78
```

### Step 2: Conditional Import
Expand Down
15 changes: 11 additions & 4 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,16 @@ torchada 还为近期 vLLM 和 SGLang 在 torch_musa 2.9 上使用的 libtorch
`torch.utils.cpp_extension.include_paths()` 会返回该兼容 include 目录。自定义
稳定 ABI 构建应显式加入 `stable_compat_include_dir()`;使用 `TORCH_BOX` 的内核
还必须通过编译器强制 include `stable_compat_box_header()` 返回的头文件。这两个
辅助函数都位于 `torchada.utils.cpp_extension`。torch_musa 2.9 头文件回补只会在
扩展构建时延迟、尽力执行;只读头文件保持不变。单纯 `import torchada` 不会修改
PyTorch 或 torch_musa 头文件。
辅助函数都位于 `torchada.utils.cpp_extension`。自定义 stable ABI 扩展应通过
上述方式显式加入兼容头。torch_musa 2.9 头文件回补会在 MUSA 扩展构建时延迟、
尽力执行;torch 2.11 及更新版本已经原生提供 stable ABI,因此会跳过回补。单纯
`import torchada` 不会修改 PyTorch 或 torch_musa 头文件。

原地 CUDA 到 MUSA 的转换会继续按原有规则保护系统 include 目录。可以通过环境变量
`TORCHADA_EXCLUDE_DIRS` 额外配置要排除的目录;每一项可以是目录路径,也可以是目录
名称,使用平台路径分隔符,也支持逗号分隔。名称会按完整路径组件匹配,因此
`TORCHADA_EXCLUDE_DIRS=torch_musa` 可以直接排除 `/home/torch_musa`,无需填写完整路径。
即使源目录位于排除目录下,扩展显式提供的源目录仍会执行转换。

### 自定义算子

Expand Down Expand Up @@ -368,7 +375,7 @@ if torchada.is_gpu_device(device): # 在 CUDA 和 MUSA 上都能工作

```
# pyproject.toml 或 requirements.txt
torchada>=0.1.77
torchada>=0.1.78
```

### 步骤 2:条件导入
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/benchmark_history.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Historical benchmark results for torchada performance tracking",
"results": [
{
"version": "0.1.77",
"version": "0.1.78",
"date": "2026-01-29",
"platform": "MUSA",
"pytorch_version": "2.7.1",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "torchada"
version = "0.1.77"
version = "0.1.78"
description = "Adapter package for torch_musa to act exactly like PyTorch CUDA"
readme = "README.md"
license = {text = "MIT"}
Expand Down
2 changes: 1 addition & 1 deletion src/torchada/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from torch.utils.cpp_extension import CUDAExtension, BuildExtension, CUDA_HOME
"""

__version__ = "0.1.77"
__version__ = "0.1.78"

from . import cuda, utils

Expand Down
1 change: 1 addition & 0 deletions src/torchada/_mappings/libtorch_stable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

MAPPING = {
'aoti_torch_get_current_cuda_stream': 'aoti_torch_get_current_musa_stream',
'torch_get_current_cuda_blas_handle': 'torch_get_current_musa_blas_handle',
'STABLE_TORCH_LIBRARY_IMPL(_C, CUDA': 'STABLE_TORCH_LIBRARY_IMPL(_C, PrivateUse1',
}
14 changes: 14 additions & 0 deletions src/torchada/csrc/stable_compat/torch/csrc/stable/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
// include it for torch::stable::Device / DeviceType. Provide them on the AOTI
// C-shim. The force-included box header pulls this in before <tensor.h> so the
// patched tensor_struct.h device() accessor can return it.
//
// Newer torch_musa provides a native device.h after this compatibility include
// directory in the search path. Forward to that complete wrapper (including
// device_inl.h), rather than including device_struct.h alone and silently
// dropping inline definitions such as the string constructor.
#if defined(__has_include_next)
#if __has_include_next(<torch/csrc/stable/device.h>)
#include_next <torch/csrc/stable/device.h>
#define TORCHADA_HAS_NATIVE_STABLE_DEVICE 1
#endif
#endif

#ifndef TORCHADA_HAS_NATIVE_STABLE_DEVICE
#include <torch/csrc/inductor/aoti_torch/c/shim.h>
#include <cstdint>
namespace torch {
Expand Down Expand Up @@ -40,3 +53,4 @@ struct Device {
};
} // namespace stable
} // namespace torch
#endif // TORCHADA_HAS_NATIVE_STABLE_DEVICE
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@
#include <torch/headeronly/core/ScalarType.h>
#include <torch/headeronly/macros/Macros.h>
#include <torch/headeronly/util/Exception.h> // STD_TORCH_CHECK
#include <torch/version.h>
#include <c10/core/ScalarType.h>

// torch 2.11+ provides these through ScalarType.h. Keep only the dispatch
// macros below on that version: torch_musa's generated compatible include tree
// may still omit Dispatch.h itself.
#if TORCH_VERSION_MAJOR < 2 || \
(TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR < 11)
namespace torch {
namespace headeronly {
namespace impl {
Expand All @@ -25,6 +31,7 @@ inline const char* toString(torch::headeronly::ScalarType t) {
}
} // namespace headeronly
} // namespace torch
#endif // torch < 2.11

#define THO_PRIVATE_CASE_TYPE_USING_HINT_TMPL(PRELUDE, enum_type, HINT, ...) \
case enum_type: { \
Expand Down
166 changes: 102 additions & 64 deletions src/torchada/csrc/stable_compat/torchada_stable_box.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,104 @@
#pragma once
#include <torch/version.h>
#include <torch/csrc/inductor/aoti_torch/c/shim.h>
#include <torch/headeronly/util/Exception.h>
#include <cstdint>
#include <musa_runtime.h>

// This header can be force-included unconditionally by downstream build files.
// PyTorch 2.11+ already provides the boxer, Device, HeaderOnlyArrayRef and the
// stable free functions below, so compiling the backport there would redefine
// native stable-ABI symbols.

// --- Always-on shims (needed on every torch_musa version) ---
// CUDA_VERSION guards in the kernels: define low so the sm100/Blackwell fast
// paths (also gated on cc_major>=10) compile out on MUSA. torchada also passes
// -DCUDA_VERSION=0 via the build, but define here for direct/JIT use.
#ifndef CUDA_VERSION
#define CUDA_VERSION 0
#endif

// Stable-ABI runtime-error check used by some libtorch-stable kernels (e.g.
// minimax_reduce_rms_kernel). The ported kernel calls musa* runtime APIs that
// return a musaError_t (0 == success); wrap them in STD_TORCH_CHECK.
// mcc translates STD_CUDA_CHECK -> STD_MUSA_CHECK at the source level, so both
// names are guarded here.
#ifndef STD_CUDA_CHECK
#define STD_CUDA_CHECK(EXPR) \
do { \
auto _musa_err = (EXPR); \
STD_TORCH_CHECK(_musa_err == 0, "MUSA runtime error: ", \
static_cast<int64_t>(_musa_err)); \
} while (0)
#endif
#ifndef STD_MUSA_CHECK
#define STD_MUSA_CHECK(EXPR) STD_CUDA_CHECK(EXPR)
#endif

// Kernel-launch error check used by some libtorch-stable kernels after a <<<>>>
// launch (e.g. selective_scan). Checks the last runtime error via the same
// STD_CUDA_CHECK path.
#ifndef STD_CUDA_KERNEL_LAUNCH_CHECK
#define STD_CUDA_KERNEL_LAUNCH_CHECK() STD_CUDA_CHECK(musaGetLastError())
#endif
#ifndef STD_MUSA_KERNEL_LAUNCH_CHECK
#define STD_MUSA_KERNEL_LAUNCH_CHECK() STD_CUDA_KERNEL_LAUNCH_CHECK()
#endif

// Newer torch_musa exposes the BLAS handle through its stable C shim. Keep a
// CUDA-named forwarding wrapper for downstream sources that bypass source
// porting; normally the mapping rule rewrites the call directly to the MUSA
// name. This avoids depending on torch_musa's private C++ handle-pool ABI.
#if TORCH_VERSION_MAJOR > 2 || \
(TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR >= 11)
#include <torch/csrc/stable/c/shim.h>
static inline AOTITorchError torch_get_current_cuda_blas_handle(void** ret) {
return torch_get_current_musa_blas_handle(ret);
}
#else
// torch_musa 2.9 has no stable C shim for the BLAS handle. Provide the MUSA
// name produced by source porting through the legacy C++ handle-pool API, then
// keep the CUDA name as a forwarding wrapper for unported sources.
struct _mublasHandle_t;
typedef struct _mublasHandle_t* mublasHandle_t;
namespace at {
namespace musa {
mublasHandle_t getCurrentMUSABlasHandle();
}
}
static inline AOTITorchError torch_get_current_musa_blas_handle(void** ret) {
auto handle = at::musa::getCurrentMUSABlasHandle();
*ret = reinterpret_cast<void*>(handle);
return handle ? 0 : 1; // fail fast on a null handle instead of crashing in muBLAS
}
static inline AOTITorchError torch_get_current_cuda_blas_handle(void** ret) {
return torch_get_current_musa_blas_handle(ret);
}
#endif

// torch_musa's AOTI C-shim exposes aoti_torch_get_current_musa_stream, not the
// upstream _cuda_ spelling that libtorch-stable kernels (torch_utils.h) call.
// Forward so those kernels compile against the upstream name.
#ifndef TORCHADA_HAVE_AOTI_CUDA_STREAM
#define TORCHADA_HAVE_AOTI_CUDA_STREAM 1
static inline AOTITorchError aoti_torch_get_current_cuda_stream(int32_t device_index,
void** ret) {
return aoti_torch_get_current_musa_stream(device_index, ret);
}
#endif

// Some libtorch-stable kernels reference TORCH_UTILS_CHECK, which torch_musa's
// stable headers do not define; alias it to the stable check macro.
#ifndef TORCH_UTILS_CHECK
#define TORCH_UTILS_CHECK STD_TORCH_CHECK
#endif

// --- torch < 2.11 backport: boxer, Device, stable free functions ---
// PyTorch 2.11+ already provides the boxer, Device, HeaderOnlyArrayRef and the
// stable free functions below, so compiling the backport there would redefine
// native stable-ABI symbols.
#if TORCH_VERSION_MAJOR < 2 || \
(TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR < 11)
// torchada stable-ABI compat: TORCH_BOX + small helpers.
//
// torch_musa 2.9.0's torch::stable runtime predates the TORCH_BOX boxer family
Expand All @@ -16,7 +116,6 @@
// kernels call. Define the stable Device here -- BEFORE <tensor.h> -- so the
// torchada-patched tensor_struct.h accessors (gated on TORCHADA_STABLE_ACCESSORS)
// can reference it; empty/from_blob are defined after <tensor.h> below.
#include <torch/csrc/inductor/aoti_torch/c/shim.h>
#include <c10/util/ArrayRef.h>
#include <optional>
#include <vector>
Expand Down Expand Up @@ -123,69 +222,6 @@ inline Tensor from_blob(void* data, c10::IntArrayRef sizes,
} // namespace stable
} // namespace torch

// CUDA_VERSION guards in the kernels: define low so the sm100/Blackwell fast
// paths (also gated on cc_major>=10) compile out on MUSA. torchada also passes
// -DCUDA_VERSION=0 via the build, but define here for direct/JIT use.
#ifndef CUDA_VERSION
#define CUDA_VERSION 0
#endif

// Stable-ABI runtime-error check used by some libtorch-stable kernels (e.g.
// minimax_reduce_rms_kernel). The ported kernel calls musa* runtime APIs that
// return a musaError_t (0 == success); wrap them in STD_TORCH_CHECK.
#ifndef STD_CUDA_CHECK
#define STD_CUDA_CHECK(EXPR) \
do { \
auto _musa_err = (EXPR); \
STD_TORCH_CHECK(_musa_err == 0, "MUSA runtime error: ", \
static_cast<int64_t>(_musa_err)); \
} while (0)
#endif

// Kernel-launch error check used by some libtorch-stable kernels after a <<<>>>
// launch (e.g. selective_scan). Checks the last runtime error via the same
// STD_CUDA_CHECK path.
#ifndef STD_CUDA_KERNEL_LAUNCH_CHECK
#define STD_CUDA_KERNEL_LAUNCH_CHECK() STD_CUDA_CHECK(musaGetLastError())
#endif

// torch_get_current_cuda_blas_handle has no AOTI stable-ABI shim on torch_musa,
// but torch_musa exposes the stream-bound current handle through its handle pool
// (at::musa::getCurrentMUSABlasHandle). Forward-declare it (resolved at import
// time from the already-loaded libtorch_musa) and return the muBLAS handle so the
// gptq cuBLAS->muBLAS GEMM path works. mublasHandle_t per
// /usr/local/musa/include/internal/mublas_types.h; the typedef is harmless if a
// later <mublas.h> (via the cublas_v2.h->mublas.h mapping) repeats it.
struct _mublasHandle_t;
typedef struct _mublasHandle_t* mublasHandle_t;
namespace at {
namespace musa {
mublasHandle_t getCurrentMUSABlasHandle();
}
} // namespace at
static inline AOTITorchError torch_get_current_cuda_blas_handle(void** ret) {
auto handle = at::musa::getCurrentMUSABlasHandle();
*ret = reinterpret_cast<void*>(handle);
return handle ? 0 : 1; // fail fast on a null handle instead of crashing in muBLAS
}

// torch_musa's AOTI C-shim exposes aoti_torch_get_current_musa_stream, not the
// upstream _cuda_ spelling that libtorch-stable kernels (torch_utils.h) call.
// Forward so those kernels compile against the upstream name.
#ifndef TORCHADA_HAVE_AOTI_CUDA_STREAM
#define TORCHADA_HAVE_AOTI_CUDA_STREAM 1
static inline AOTITorchError aoti_torch_get_current_cuda_stream(int32_t device_index,
void** ret) {
return aoti_torch_get_current_musa_stream(device_index, ret);
}
#endif

// Some libtorch-stable kernels reference TORCH_UTILS_CHECK, which torch_musa's
// stable headers do not define; alias it to the stable check macro.
#ifndef TORCH_UTILS_CHECK
#define TORCH_UTILS_CHECK STD_TORCH_CHECK
#endif

namespace torchada_stable {

template <class T>
Expand Down Expand Up @@ -249,3 +285,5 @@ inline void boxed(StableIValue* stack, uint64_t /*nargs*/, uint64_t /*nout*/) {
#ifndef TORCH_BOX
#define TORCH_BOX(func) (&::torchada_stable::boxed<func>)
#endif

#endif // torch < 2.11
Loading