Moore Threads MUSA uses native operator kernels calling libmudnn.so, not CUDA boxing. The MUSA toolkit ships no CUDA runtime, and there is no vendor dispatch key to box into.
- CPU PyTorch 2.10.x:
torch==2.10.0from the upstream CPU index - MUSA toolkit: Moore Threads SDK with
musartruntime,mudnnoperator library, andmurandRNG library under/usr/local/musa - Python: 3.8 or later
- Operating System: Linux
The MUSA toolkit provides:
musart: runtime layer (device/memory/stream)mudnn(libmudnn.so): operator library with category-driven API (Unary/Binary/Reduce/MatMul/Softmax/Convolution/Dropout)murand(libmurand.so): device-side Philox random generation for uniform, normal, and integer draws
mudnn links against musart only and pulls in no torch symbols at all, making this backend torch-version-agnostic (tested against both 2.9.1 and 2.10.0 from the same source tree, though only 2.10.0 is officially supported).
pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cpugit clone https://github.com/flagos-ai/PyTorch-Plugin-FL.git
cd PyTorch-Plugin-FL
FLAGOS_ACCELERATOR=musa pip install --no-build-isolation -v -e .Build flags:
FLAGOS_ACCELERATOR=musa: selects the MUSA build path and enablesFLAGOS_BUILD_VENDOR=ONFLAGOS_BUILD_VENDOR=ON: compiles generatedmudnnoperator kernels (automatic whenFLAGOS_ACCELERATOR=musa)FLAGOS_BUILD_FLAGGEMS=ON: compiles the optional Python dispatcher callers into the same wheel; runtime routing comes frombackends_musa.confFLAGOS_BUILD_BOXING=OFF: forced (the MUSA toolkit exports no CUDA symbols)FLAGOS_BUILD_FLAGGEMS_CPP=OFF: automatically disabled because the FlagGems C++ runtime is not built for MUSA--no-build-isolation: required (without it, pip resolves its own torch into a build overlay, and the extension links against that instead of your installed torch, causingimport torch_flto fail withundefined symbol: c10::ValueError)
The build runs scripts/codegen/codegen_mudnn.py to generate kernels. Coverage is 64 generated ops plus 2 handwritten convolution kernels; native RNG kernels add muRAND-backed rand/randn, rand_like/randn_like, randint, normal_, uniform_, random_, and mudnn dropout paths. Everything outside those sets reaches the cpu_fallback.
Without --no-build-isolation, pip creates a temporary build environment and installs its own copy of torch there. The C++ extension then links against that temporary torch, not the one you installed. When you later import torch_fl in your actual environment, the torch C++ object layouts don't match, causing symbol resolution failures.
This constraint is specific to MUSA because mudnn has no torch dependency at all. Earlier versions of this backend called torch_musa's flat at::musa::* API from libmusa_python.so, which links against torch and embeds its C++ object layout—pinning the plugin to one exact torch build (sizeof(c10::MessageLogger) changed 408 → 400 between 2.9.1 and 2.10, corrupting the vendor .so's stack). mudnn avoids that coupling entirely.
If the torch_musa package is installed alongside torch_fl (not recommended, but possible), you must import torch_fl before torch, or export TORCH_DEVICE_BACKEND_AUTOLOAD=0:
export TORCH_DEVICE_BACKEND_AUTOLOAD=0torch_musa registers a torch.backends entry point, so a bare import torch autoloads it and claims the PrivateUse1 backend name first. torch_fl sets TORCH_DEVICE_BACKEND_AUTOLOAD=0 internally when imported first, which covers the torch_fl-first order. The other order fails with an explicit message.
Recommendation: do not import the top-level torch_musa plugin in the same process. It is optional for normal torch-fl operation; only its distributed submodule may be discovered lazily for the MCCL fallback when it is installed.
import torch_fl # Must come before torch if torch_musa is present
import torch
print(f"flagos available: {torch_fl.flagos.is_available()}")
print(f"flagos devices: {torch_fl.flagos.device_count()}")
x = torch.randn(64, 64, device="flagos:0")
y = torch.abs(x)
print(f"abs matches CPU: {torch.allclose(y.cpu(), x.cpu().abs())}")torch_fl installs a lib/flagos_platform marker so the runtime picks backends_musa.conf automatically. This native-only mode requires no environment variable override.
There is no FLAGOS_USE_FLAGGEMS opt-in and no separate *_flagos_py.conf
narrow hybrid set. backends_musa.conf is generated FlagGems-first: of the 515
ops MUSA registers on PrivateUse1, 468 resolve to flaggems and 47 to musa,
and the remaining ops are written none because MUSA does not register them, so
they reach cpu_fallback. Where a mudnn kernel exists behind an op FlagGems
wins, the entry carries a # musa annotation. Reading the file tells you the
whole routing.
The 47 native routes are the ops FlagGems does not cover at all plus the ops
listed in NATIVE_TRITON_GAPS["musa"], which FlagGems cannot execute correctly
on this stack: the bf16 wrapped-number lowering failure in the pointwise
arithmetic family (including its in-place .Tensor forms, which is where ATen's
wrapped-number boxing sends add_.Scalar, _foreach_add_ and AdamW's foreach
step), the RNG bridge, and sort. Three of those gap ops have no mudnn kernel
either and stay none. FlagGems is not patched for MUSA.
The FlagGems routes require FlagGems and the MThreads FlagTree compiler/runtime.
On the measured host, FlagGems 5.4.0rc2.post1 (master, installed from source)
executed with flagtree 0.6.2a3+mthreads3.6 (Triton 3.6.0, backend mthreads).
A generic PyPI Triton wheel is not sufficient -- it ships no mthreads backend
-- and must not be used for this path.
To pin the table to one backend for A/B measurement, set
FLAGOS_FORCE_BACKEND to flaggems or vendor. Ops the target does not
implement are listed on stderr and stay on their configured backend.
Run the MUSA dispatch suite:
pytest tests/integration/ops/test_musa_dispatch.py -vThis test file checks that ops route to the musa backend, exercises per-op environment overrides, and validates results against CPU references. It replaces the generic per-op tests in tests/integration/ops/, which assert -> cuda routing that MUSA builds cannot produce (no CUDA boxing kernels are compiled).
Run the autocast and GradScaler suite:
TORCH_DEVICE_BACKEND_AUTOLOAD=0 FLAGOS_ACCELERATOR=musa \
LD_LIBRARY_PATH=/usr/local/musa/lib:$LD_LIBRARY_PATH \
pytest tests/integration/test_amp_contract.py -m amp -vRun common operator smoke tests:
pytest tests/integration/ops/test_common_ops.py -v -s --tb=shortNote: MUSA has no CI configuration file (.github/configs/musa.yml does not exist), so all validation is manual.
Category-driven codegen via scripts/codegen/codegen_mudnn.py covers:
- Unary: abs, sqrt, rsqrt, exp, log, log2, log10, log1p, sin, cos, acos, atan, tanh, sigmoid, silu, relu, gelu, erf, floor, ceil, sign
- Binary: add, mul, sub, div, pow, eq, ne, lt, le, gt, ge, maximum, minimum, logical_and, logical_or, logical_xor
- Reductions: sum, mean, max, min, argmax, argmin (with dim support)
- MatMul: mm, addmm, bmm, baddbmm
- Softmax: softmax, log_softmax
- Composed from single mode: neg (MUL by -1), trunc (TRUNCATEDIV by 1), expm1 (EXP then SUB 1)
Convolution (csrc/aten/backends/musa/mudnn_conv.cc):
convolution_overrideablecannot be left unregistered (ATen's default raises rather than being boxable to CPU)mudnn'sConvolutioncovers 2 spatial dims only:- conv1d runs as 2D conv with unit
Hdim (exact against CPU) - conv3d takes the CPU fallback
- conv1d runs as 2D conv with unit
- Bias is a separate broadcast
Binary::ADD;RunFusionaccepts bias only for non-grouped 2D - Algorithm is chosen by trial and cached per shape (since
GetRecommendForwardAlgorithmcan name one thatRunthen rejects)
Copy and cast (csrc/aten/backends/musa/mudnn_copy.cc):
- Strided copies and dtype casts use
mudnn'sUnary::IDENTITY/Unary::CAST - Handles both in a single device pass
- Without this,
copy_/clone/contiguouswould reach the CUDADispatchStuband fail
MUSA uses the shared AutocastPrivateUse1 policies with its native mudnn routes.
Both torch.float16 and torch.bfloat16 are supported autocast targets:
import torch
import torch.nn.functional as F
import torch_fl # noqa: F401
model = torch.nn.Linear(8, 4, device="flagos")
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
scaler = torch.amp.GradScaler("flagos")
inputs = torch.randn(2, 8, device="flagos")
targets = torch.randn(2, 4, device="flagos")
with torch.autocast("flagos", dtype=torch.bfloat16):
output = model(inputs)
loss = F.mse_loss(output, targets)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()The standard policy groups cast matmul, linear, and convolution to the selected lower-precision dtype. Logarithm, layer normalization, MSE loss, and the default softmax policy run in float32; operations in the promote group use the widest input dtype. Nested autocast state and explicit softmax dtypes follow PyTorch's PrivateUse1 behavior.
GradScaler's _amp_foreach_non_finite_check_and_unscale_ currently reaches the
existing CPU fallback because mudnn has no fused AMP-foreach primitive. The
fallback copies tensor-list operands and scalar state to CPU, invokes PyTorch's
reference kernel, and copies the mutated gradients and found_inf flag back to
MUSA. This preserves finite-step growth, overflow backoff, and optimizer-step
skipping, but it is not a native device-side performance path.
Native RNG uses a per-device Philox generator from libmurand.so. Each operation consumes one seed from the selected PyTorch flagos generator under its mutex, then configures a cached muRAND generator on the shared MUSA stream. This preserves torch.manual_seed, torch.flagos.manual_seed, manual_seed_all, get_rng_state/set_rng_state, explicit generator= isolation, and independent per-device sequences without maintaining a second Python-side RNG state. The optional FlagGems bridge reserves operation seeds through the same C++ API and starts each FlagGems Philox invocation at offset zero, so mixed native/FlagGems call order has one authoritative state.
Odd-sized normal outputs are generated with one extra sample because muRAND's normal API requires an even length. muRAND produces uniform samples in (0, 1], so the native wrapper maps the endpoint to zero to provide PyTorch's required [0, 1) interval. S5000's Philox implementation returns MURAND_STATUS_TYPE_ERROR from murandGenerateLongLong; integer RNG therefore combines two supported 32-bit outputs and applies ATen-compatible range transforms, including int64 ranges wider than INT64_MAX.
The current native RNG set covers rand/randn, their generator and like variants, integer factories and in-place random_, normal_, uniform_, and native_dropout forward/backward. randperm, tensor-parameter distributions, and rejection-sampled distributions remain unregistered until a device implementation can provide their exact ATen contract. They therefore use cpu_fallback rather than being routed to an absent kernel.
Other ops with no mudnn mode are deliberately left unregistered, so they reach the cpu_fallback and stay correct. Examples:
sinh,cosh,asin: nomudnnmode exists
Registering an op with no kernel behind it would trip the dispatcher's "backend not registered" check.
mudnn Tensors carry strides on both operands and honor 0-strides. This means:
- Broadcasting is just
expand()(a view, no copy) - Non-contiguous inputs are read in place
- No
.contiguous()materialization needed (contrast with GCU'stopsaten)
int64 works across Unary/Binary/Reduce/MatMul categories. Unlike GCU's topsaten (which has no int64 kernels at all), MUSA only falls back for genuinely unmapped dtypes (complex, quantized).
mudnn enables TF32 by default, whereas PyTorch defaults torch.backends.cuda.matmul.allow_tf32 off. The handle is refreshed from torch's flag on every op to match PyTorch semantics. Without this, a 64×64 float mm drifts ~2e-2 from CPU.
mudnn v3300's Reduce raises SIGFPE (an uncatchable crash, not an error status) when reducing over more than one dim of a tensor that is a broadcast of a single element. Conv bias gradients hit exactly that case, since autograd feeds ones.expand(...) into the reduction.
A fully broadcast input is materialized before a multi-dim reduction to avoid this crash.
flagos keeps its own caching allocator over raw musaMalloc. mudnn allocates nothing on its own beyond op workspaces, which are served from the same allocator via a MemoryMaintainer.
MUSA has no CI runner (no .github/configs/musa.yml config exists), so all tests are manual. The platform status is Experimental (see docs/reference/compatibility.md line 31).
The native RNG and hybrid FlagGems implementation were measured on 2026-08-17 on an eight-device Moore Threads MTT S5000 host. Device 0 reported capability 3.1, 60 multiprocessors, and 85,813,358,592 bytes of memory. The environment used CPU PyTorch 2.10.0, the installed /usr/local/musa toolkit (mudnn v3300), FlagGems 5.0.2, and the vendor flagtree-0.5.0+mthreads3.1 wheel (Triton 3.1.0, backend mthreads). Results:
pytest tests/integration/test_amp.py -v(nowtest_amp_contract.py -m amp): 25 passed in 9.00 seconds. Both FP16 and BF16 passed lower-precision matmul/linear/convolution, float32 and promote policies, nested state, mutable non-finite unscale, finite scale growth, overflow backoff, optimizer-step skipping, and autocast/GradScaler training.pytest tests/integration/ops/test_rng_dispatch.py -m "main_ops" -v: the unified RNG suite passed, including explicit generators, state round trips,torch.manual_seed, full-width int64 ranges, native dropout, shared native/FlagGems reservation ordering, and multi-device sequence isolation. MUSA-only generator and reservation cases are selected by themusamark.pytest tests/integration/ops/test_musa_dispatch.py -v: 89 passed in 36.31 seconds.pytest tests/unit/test_vendor_routing.py tests/unit/test_musa_rng_bridge.py -v: 24 passed in 2.19 seconds.pytest tests/integration/ops/test_musa_flaggems.py -q: 2 passed in 5.33 seconds withFLAGOS_USE_FLAGGEMS=1. The test instruments and observes all seven selected Python callables (all,all.dims,any,any.dims,repeat_interleave.Tensor,index_add, andindex_add_) onflagos:0, verifies CPU-equivalent outputs including duplicate indices, and executes FlagGemsrandnonflagos:0between nativerandcalls. Repeating the sequence aftertorch.flagos.manual_seed(20260817)reproduces all three outputs and confirms two shared C++ generator reservations. That file has since been split: its route-instrumentation case is now the platform-neutraltests/integration/flaggems/suite, and the shared-reservation case istests/integration/ops/test_musa_flaggems_device.py.- Native and hybrid suites ran in separate pytest processes. Backend configuration is cached by the process-static C++
BackendTable(), so changing the conf the process resolved after a native import cannot switch the active routes. - The MThreads driver obtained the same nonzero raw
musaStream_tthat native mudnn/muRAND uses, so native and FlagGems launches share the torch-fl stream. In thetorch.compilepath this handle comes fromtorch_fl.compile.flagtree_shim.get_musa_current_raw_stream(), without consulting thetorch_musaplugin.
The generic triton 3.7.1 installation remains unsuitable because it does not ship the MThreads backend. FlagGems stochastic ATen routing is intentionally still native-first; the end-to-end FlagGems RNG evidence comes from its real flag_gems.ops.randn.randn kernel and the shared reservation bridge, not an expanded RNG dispatcher route.
Status: FlagCX-first routing and MCCL fallback are implemented; this RNG validation did not rerun multi-process collectives.
MUSA distributed communication routes through FlagCX via the identity view path. The _flagos_identity_view binding passes privateuseone tensors directly to FlagCX's MUSA adaptor without storage conversion, since FlagCX extracts data_ptr() and musaStream_t without validating device().type(). If FlagCX initialization is unavailable, the MUSA profile attempts ProcessGroupMCCL from torch.distributed or torch_musa.distributed. The FlagGems compatibility shim preserves access to an installed torch_musa package's submodules without importing its top-level plugin and taking ownership of PrivateUse1.
The routing unit suite covers FlagCX preference, MCCL fallback, the mthreads vendor alias, missing identity bindings, and the no-backend error. End-to-end multi-process validation still requires FlagCX or MCCL built for this host and should use tests/manual/test_comm_device_index.py --world-size 2. See docs/architecture/distributed-flagcx.md for the ProcessGroupFlagOS architecture.
MUSA profiling uses the optional MUPTI activity API from the MUSA toolkit. A profiler-capable
build detects mupti_activity.h under MUSA_HOME and dynamically loads libmupti.so when a
torch.profiler session starts. The extension does not link against MUPTI, so importing
torch_fl remains possible on a host that has the MUSA runtime but no profiler library.
The tracer enables concurrent and serialized kernels, runtime and driver API records, memcpy, memset, and external-correlation records. MUPTI timestamps are converted into the realtime clock domain used by Kineto. Runtime/device vendor correlation IDs remain separate from torch external correlation IDs: the former draws flow arrows and the latter attributes device time to CPU ops.
Run the focused hardware test on an MTT S5000 host:
TORCH_DEVICE_BACKEND_AUTOLOAD=0 FLAGOS_ACCELERATOR=musa \
LD_LIBRARY_PATH=/usr/local/musa/lib:$LD_LIBRARY_PATH \
pytest tests/integration/test_profiler_musa.py -qMeasured with CPU PyTorch 2.10.0 and the installed MUSA 5.1.0 toolkit, the test captured real MUPTI kernel, runtime, and memcpy events with positive duration, valid names, device/stream metadata, and a valid Chrome trace JSON document. The same run exposed torch external IDs on the captured device events. CPU-only Kineto builds may not invoke the PrivateUse1 resolver, so this is an MUPTI device-timeline validation rather than a claim of full torch-cuda profiler parity.
Useful diagnostics are FLAGOS_TRACE=1 for activity setup and session lifecycle logging and
FLAGOS_TRACER_LIBRARY=/path/to/libmupti.so to select a specific MUPTI library. MUPTI subscriber
ownership remains process-global; an external MUSA profiling tool may therefore reject a concurrent
torch.profiler session. torch.compile with the vendor FlagTree runtime is
validated separately below; a stock Triton wheel remains insufficient for MUSA.
MUSA torch.compile(backend="flagos") uses TorchInductor without rewriting the
graph to CUDA. The graph and autograd device stay flagos, while the MThreads
FlagTree runtime receives a native musa target and launches through the shared
musaStream_t. The tested compiler is flagtree-0.5.0+mthreads3.1 (Triton 3.1,
backend mthreads); generic Triton 3.7.1 is not MUSA compiler evidence.
The torch_musa plugin is not required, and importing it in this process
breaks torch_fl. FlagTree reaches the MUSA device through torch_fl alone:
the vendor MThreads driver normally reads device availability, current device,
capability, and the raw stream from torch_musa, and
torch_fl.compile.flagtree_shim rebinds those lookups onto its own runtime
before the first Triton driver is created. The plugin may remain installed on
disk — torch_fl never imports its __init__, and torch_fl publishes a small
compatibility surface under that module name for FlagGems backend discovery,
which is torch_fl's own code rather than the vendor plugin. See
torch-compile-integration.md
for why the plugin cannot coexist with torch_fl.
mode="max-autotune" compiles and runs, but its runtime coordinate-descent
tuning is disabled on MUSA: it times candidate configurations through Inductor's
CUDA benchmarker (torch.cuda.synchronize plus torch.cuda.Event), which the
CPU PyTorch wheel cannot provide. Kernels are compiled and executed, just not
runtime-tuned.
Use a process with the vendor runtime before running the focused compile tests:
PYTHONPATH=/path/to/flagtree-mthreads-runtime:$PWD \\
LD_LIBRARY_PATH=/path/to/flagtree-mthreads-runtime/triton/_C:/usr/local/musa/lib:$LD_LIBRARY_PATH \\
TORCH_DEVICE_BACKEND_AUTOLOAD=0 FLAGOS_ACCELERATOR=musa FLAGOS_USE_FLAGTREE=1 \\
pytest tests/integration/test_compile.py -vOn the MTT S5000 this suite passed in full (22 tests), covering eager
equivalence, forward/backward compilation, FP32/FP16 paths, max-autotune,
recompilation, FakeTensor tracing, output/gradient placement, and the assertion
that torch_musa is absent from sys.modules throughout. MThreads FlagTree queries
the MUSA runtime during compiler setup, so torch_fl serializes compilation to
one Inductor worker by default. Set TORCHINDUCTOR_COMPILE_THREADS or the
compile_threads option only when the installed vendor driver is known to be
fork-safe. FLAGOS_COMPILE_FALLBACK_EAGER=1 is useful for diagnosing an
unsupported graph, but a fallback pass does not count as compiler validation.
The result is specific to the measured MTT S5000, MUSA 5.1.0, CPU PyTorch 2.10, and the vendor FlagTree wheel above; it does not imply support for other MUSA SDK, PyTorch, or FlagTree combinations.
A generic Triton wheel does not imply MUSA kernel support. Use a FlagTree wheel
that ships the mthreads backend and a FlagGems revision that matches it; the
measured combination for the routing above is flagtree 0.6.2a3+mthreads3.6
(Triton 3.6.0) with FlagGems 5.4.0rc2.post1 installed from source. Install
FlagGems with --no-deps so its triton dependency does not replace FlagTree's
wheel:
python3 -m pip install "flagtree===0.6.2a3+mthreads3.6" \
--index-url=https://resource.flagos.net/repository/flagos-pypi-hosted/simple
pip install --no-deps -e /path/to/FlagGemsThe full procedure, including the environment variables the MUSA CI job sets, is
in flaggems-setup.md. Because the MUSA wheel registers the
whole FlagGems Python operator set on PrivateUse1, no dispatcher subset has to be
selected at build time and there is no FLAGOS_USE_FLAGGEMS opt-in to set: the
generated backends_musa.conf already decides the routing, and native
mudnn/muRAND plus CPU fallback remain usable for the ops it sends to musa or
none.
To build the runtime layer only (device/memory/stream support) with no native operator kernels:
FLAGOS_ACCELERATOR=musa FLAGOS_BUILD_VENDOR=OFF pip install --no-build-isolation -v -e .All compute ops will fall back to CPU. This mode is useful for testing the runtime layer in isolation.
- Codegen source: category-driven kernel generation for
mudnn - Compatibility matrix: platform status and limitations
- Environment variables: runtime environment variables and backend selection