Skip to content

Integrate NPU SpMM Demo into DGL - #7912

Open
zhuqiming1025 wants to merge 319 commits into
dmlc:masterfrom
zhuqiming1025:master
Open

zhuqiming1025 wants to merge 319 commits into
dmlc:masterfrom
zhuqiming1025:master

Conversation

@zhuqiming1025

Copy link
Copy Markdown

Description

Checklist

Please feel free to remove inapplicable items for your PR.

  • The PR title starts with [$CATEGORY] (such as [NN], [Model], [Doc], [Feature]])
  • I've leverage the tools to beautify the python and c++ code.
  • The PR is complete and small, read the Google eng practice (CL equals to PR) to understand more about small PR. In DGL, we consider PRs with less than 200 lines of core code change are small (example, test and documentation could be exempted).
  • All changes have test coverage
  • Code is well-documented
  • To the best of my knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change
  • Related issue is referred in this PR
  • If the PR is for a new model/paper, I've updated the example index here.

Changes

lizengyong and others added 28 commits August 14, 2026 14:07
…rged

fix(npu): sync PyTorch NPU stream for graph ops via C++ layer
feat(sddmm): add SDDMM operator with NPU-native kernels for Ascend
feat(spmm): add SPMM FP32 NPU-native kernel for Ascend
… Ascend

Add Ascend NPU adaptation for edge_softmax operator, enabling GAT/PAGTN
graph attention network training on Ascend 910B NPU.

New operators:
- edge_softmax forward/backward: Ascend C kernel with FullLoad/RowSplit
  dual-mode, FP32/FP16 support, AR/ARA (num_heads=1/>1) branches
- CSRTranspose: Ascend implementation via COOToSR(COOTranspose(CSRToCOO))
  chain, reusing existing Ascend kernels

Framework integration:
- kernel.cc: dispatch edge_softmax by data tensor device (not graph context)
  to handle NPU tensors with CPU-resident graph topology; add CPU fallback
  for BackwardSegmentCmp and ScatterAdd (needed by GAT WeightedSumAndMax)
- array.cc: add Ascend dispatch branch for CSRTranspose

Host code (edge_softmax.cc):
- ACL host with forward/backward template specializations (FP32/FP16 x
  int32/int64)
- CSC edge ID remapping via CPU gather/scatter (NPU torch index ops
  unreliable on DGL blob tensors)
- Backward interface adapted to DGL convention (sds = out * grad_out)

End-to-end validation:
- pytest test_gat.py: 2/3 passed, 1 regression needs 800 epochs (CPU also
  needs more epochs)
- pytest test_pagtn.py: no operator crashes (precision is test-epoch limit)
- test_edge_softmax_npu.py: 78 tests, 100% pass (FP32/FP16 x fwd/bwd x
  6 graph types x 3 num_heads + edge cases + perf)

Co-Authored-By: CANNBot <cannbot@ascend>
…emapping

- IndexSelectND: sddmm_copy_lhs_kernel (NPU gather, no CPU roundtrip)
- ScatterBackND: aclrtMemcpyAsync D2D (stays on NPU)
- int64 need_remap: actual sequential check
- 78 edge_softmax + 66 SDDMM tests pass
- Remove NDArrayToTorch (never called)
- Remove torch/extension.h and NPUStream.h includes
- 78 tests pass
…transpose

feat(edge_softmax): add edge_softmax and CSRTranspose NPU support for Ascend
…sampling-ascend

[Feature] Implement native AscendC CSRRowWiseSampling for NPU
fix(npu): sync PyTorch NPU stream for graph-structure queries

Created-by: xuejikan11
Commit-by: xuejikan
Merged-by: knightgd
Description: ## Summary
Sync PyTorch NPU stream for graph-structure queries to fix data races.

## Files (7)
- python/dgl/_ffi/streams.py
- python/dgl/core.py
- python/dgl/heterograph.py
- src/array/array.cc
- src/array/ascend/segment_reduce.cc
- src/array/kernel.cc
- src/graph/unit_graph.cc

关联的Issue: BUPT-GAMMA#6

See merge request: AI4Science/dgl-ascend!9
feat(sddmm): add SDDMM operator with NPU-native kernels

Created-by: xuejikan11
Commit-by: xuejikan
Merged-by: knightgd
Description: ## Summary
Add SDDMM with 3 NPU-native kernels + host dispatch.

## Files (8)
- python/dgl/_sparse_ops.py
- src/array/ascend/sddmm.cc (new)
- src/array/ascend/sddmm_dot_kernel.cpp (new)
- src/array/ascend/sddmm_copy_lhs_kernel.cpp (new)
- src/array/ascend/sddmm_binary_kernel.cpp (new)
- src/array/ascend/sddmm_copy_lhs_tiling.h (new)
- src/array/ascend/sddmm_binary_tiling.h (new)
- tests/python/ascend/test_sddmm.py (new)

关联的Issue: BUPT-GAMMA#7

See merge request: AI4Science/dgl-ascend!10
feat(spmm): add unified SPMM kernel with FP32/FP16 template

Created-by: xuejikan11
Commit-by: xuejikan
Merged-by: knightgd
Description: ## Summary
Add unified SPMM kernel with template-based FP32/FP16 support.

## Files (6)
- src/array/ascend/spmm.cc (modified)
- src/array/ascend/spmm_unified_aiv_kernel.cpp (new)
- src/array/ascend/spmm_unified_maxmin_kernel.cpp (new)
- src/array/ascend/spmm_unified_sum_kernel.cpp (new)
- src/array/ascend/spmm_unified_tiling.h (new)
- tests/python/ascend/test_spmm.py (new)

关联的Issue: BUPT-GAMMA#8

See merge request: AI4Science/dgl-ascend!11
feat(edge_softmax): add edge_softmax and CSRTranspose NPU support

Created-by: xuejikan11
Commit-by: xuejikan
Merged-by: knightgd
Description: ## Summary
Add edge_softmax kernel + CSRTranspose.

## Files (5)
- src/array/ascend/edge_softmax.cc (new)
- src/array/ascend/edge_softmax_kernel.cpp (new)
- src/array/ascend/edge_softmax_tiling.h (new)
- src/array/ascend/csr_transpose.cc (new)
- tests/ascend/test_edge_softmax_npu.py (new)

关联的Issue: BUPT-GAMMA#9

See merge request: AI4Science/dgl-ascend!12
…ITCH_CUDA_ASCEND

PR BUPT-GAMMA#16 added Ascend SDDMM kernel implementations (SDDMMCsr<kDGLAscend> /
SDDMMCoo<kDGLAscend> template specializations) and changed the macro in
kernel.cc::SDDMM() from ATEN_XPU_SWITCH_CUDA to ATEN_XPU_SWITCH_CUDA_ASCEND.

However, array.cc::CSRSDDMM() and array.cc::COOSDDMM() — the lower-level
dispatch entry points called by dgl_sparse (matmul.cc::SDDMMNoAutoGrad and
BroadcastOpNoAutoGrad) — were not updated. They still use
ATEN_XPU_SWITCH_CUDA, which treats kDGLAscend as unsupported and falls
back to LOG(FATAL) at runtime.

This fix changes both CSRSDDMM and COOSDDMM in array.cc to use
ATEN_XPU_SWITCH_CUDA_ASCEND, consistent with kernel.cc.

Without this fix, dgl.sparse.SDDMM() and related operations
(BroadcastAdd/Sub/Mul/Div, SpMM backward) silently fail on NPU.
Add tests verifying that dgl.sparse.sddmm() correctly routes to Ascend
SDDMM kernels through the array.cc::CSRSDDMM/COOSDDMM dispatch path.

Before the macro fix, these calls would LOG(FATAL) with
does not support ascend device. After the fix, they route to
SDDMMCsr<kDGLAscend>/SDDMMCoo<kDGLAscend> without crash.

Tests cover:
- COO format SDDMM (no crash, shape correct)
- CSR format SDDMM (no crash, shape correct)
- Various edge counts
- Empty graph
- FP16 dtype
- Consistency: both gsddmm (kernel.cc) and dgl.sparse (array.cc) paths work
Move dgl.sparse dispatch path tests from standalone test_sddmm_sparse.py
into test_sddmm.py as TestSparseSDDMM class. Use int32 indices to avoid
NPU DLPack int64 overflow issue (unrelated to the macro fix).
…ITCH_CUDA_ASCEND

PR BUPT-GAMMA#16 (GitHub) added Ascend SDDMM kernel implementations
(SDDMMCsr<kDGLAscend> / SDDMMCoo<kDGLAscend> template specializations)
and changed the macro in kernel.cc::SDDMM() from ATEN_XPU_SWITCH_CUDA
to ATEN_XPU_SWITCH_CUDA_ASCEND.

However, array.cc::CSRSDDMM() and array.cc::COOSDDMM() -- the lower-level
dispatch entry points called by dgl_sparse (matmul.cc::SDDMMNoAutoGrad
and BroadcastOpNoAutoGrad) -- were not updated. They still use
ATEN_XPU_SWITCH_CUDA, which treats kDGLAscend as unsupported and crashes
with LOG(FATAL).

This fix changes both CSRSDDMM and COOSDDMM in array.cc to use
ATEN_XPU_SWITCH_CUDA_ASCEND, consistent with kernel.cc.

Also adds TestSparseSDDMM class to test_sddmm.py verifying dgl.sparse.sddmm
does not crash on NPU.
…end-macro

fix(sddmm): route CSRSDDMM/COOSDDMM to Ascend kernels via ATEN_XPU_SWITCH_CUDA_ASCEND
fix(sddmm): route CSRSDDMM/COOSDDMM to Ascend kernels via ATEN_XPU_SWITCH_CUDA_ASCEND

Created-by: xuejikan11
Commit-by: xuejikan11
Merged-by: knightgd
Description: ## Summary

Fix missing `ATEN_XPU_SWITCH_CUDA_ASCEND` macro in `array.cc::CSRSDDMM()` and `array.cc::COOSDDMM()`.

## Problem

PR !10 (feat/sddmm-ascend) added Ascend SDDMM kernel implementations (`SDDMMCsr<kDGLAscend>` / `SDDMMCoo<kDGLAscend>` template specializations) and changed the macro in `kernel.cc::SDDMM()` from `ATEN_XPU_SWITCH_CUDA` to `ATEN_XPU_SWITCH_CUDA_ASCEND`.

However, `array.cc::CSRSDDMM()` and `array.cc::COOSDDMM()` -- the lower-level dispatch entry points called by `dgl_sparse` (`matmul.cc::SDDMMNoAutoGrad` and `BroadcastOpNoAutoGrad`) -- were not updated. They still use `ATEN_XPU_SWITCH_CUDA`, which treats `kDGLAscend` as unsupported and crashes with `LOG(FATAL)`.

## Two dispatch paths

| Path | Entry point | Macro status | Affected APIs |
|------|-------------|-------------|---------------|
| `dgl.ops.gsddmm` | `kernel.cc::SDDMM()` | Fixed in PR !10 | gsddmm |
| `dgl.sparse.sddmm` | `array.cc::CSRSDDMM/COOSDDMM()` | **Fixed in this PR** | dgl.sparse.SDDMM, BroadcastAdd/Sub/Mul/Div, SpMM backward |

## Changes

- `src/array/array.cc`: 2 lines changed
  - `CSRSDDMM`: `ATEN_XPU_SWITCH_CUDA` -> `ATEN_XPU_SWITCH_CUDA_ASCEND`
  - `COOSDDMM`: `ATEN_XPU_SWITCH_CUDA` -> `ATEN_XPU_SWITCH_CUDA_ASCEND`
- `tests/python/ascend/test_sddmm.py`: added TestSparseSDDMM class (112 lines)
  - Verifies `dgl.sparse.sddmm()` does not crash on NPU (COO + CSR)
  - Tests shape correctness, empty graph, FP16
  - Consistency test: both `gsddmm` and `dgl.sparse` paths work

## Verification

- Build: success on Ascend 910B3 (CANN 9.0.0, torch_npu 2.7.1.post4)
- Tests: 46/46 passed (40 existing + 6 new, no regression)

```
tests/python/ascend/test_sddmm.py    46 passed
```

## 类型标签
- [x] Bug修复

See merge request: AI4Science/dgl-ascend!13
14 cases covering structural validity (sampled edges are true neighbors,
per-row count == min(fanout, degree)), deterministic exact comparison
against CPU for select-all and fanout >= degree, semantic checks (no
duplicates without replacement, edge-id mapping), unsorted COO input,
default in-edge direction (transposed COO path), statistical uniformity,
and an NPU path coverage guard. Mirrors the structure of
test_csr_row_wise_sampling_npu.py.
Route NPU COO row-wise uniform sampling to an assembly of existing
Ascend operators instead of falling through to LOG(FATAL): full-graph
COOToCSR followed by the native CSR uniform-sampling kernel. The row
ids pass straight through to the CSR kernel because the full-graph
indptr is indexed by real node ids, so the sampled output rows are
already real node ids (no Range + IndexSelect remapping).

Degenerate inputs (empty rows, empty graph, zero fanout) return an
empty COO matrix without launching kernels. The weighted path (prob or
mask given) is rejected explicitly as unsupported.
COO-format graphs do not support order='srcdst' (only CSR does), so the
CPU-side verification helpers must pick the edge order based on the
graph's created formats.
knightgd and others added 30 commits September 18, 2026 20:49
fix(ascend): NPU core conv suite 1050/1050 + ToBlock Ascend C + torch_npu host queue sync

Created-by: xuejikan11
Commit-by: xuejikan11;gxlgyr
Merged-by: knightgd
Description: ## 修复目标

让 DGL Ascend 的 pytorch NN 核心卷积套件(GraphConv/GIN/GAT/GATv2/SAGE/RGCN/HGT)在昇腾 910B3 上 **1050/1050 全部通过**,无需任何 warmup hack。

## 根因

torch_npu 算子(matmul/bmm 等)不直接提交到 NPU 设备,而是进入 c10_npu 的 **host 侧任务队列**异步 flush;DGL AscendC kernel 用 ACL 直接 launch。两套提交体系互不感知:
- `aclrtSynchronizeDevice/Stream` 只等已提交任务,不 flush host 队列
- `c10_npu::device_synchronize()` 同样不 flush
- DGL kernel 可能在生产者写完输入前执行,读到全零/过期数据

## 修复内容(4 个 commit)

### 1. `2aac5d08` fix: torch_npu host 队列同步修复首调全零
- 新增 `torch_stream_sync.h`:`SyncTorchNpuStream()`(dlsym `npuSynchronizeDevice`)+ `SetDeviceIfChanged()`
- 接入 spmm / edge_softmax / sddmm / csr_get_row_nnz 的 launch 前同步
- 修复 GraphConv/GIN/SAGE 首调全零、GAT/GATv2 偶发 DGLError、in_degrees 偶发全零误报

### 2. `beda31e9` feat: ToBlock 全 device 端 Ascend C 实现
- 替换 CPU 副本 workaround 为 device 端 hash 去重 + 边映射 kernel
- 单入口 + dtype_bytes tiling(规避 K_TYPE_AIV 多函数 meta 编号 bug)
- array.cc: CSRRowWiseSampling Ascend dispatch 分支

### 3. `3d53024b` fix: NPU 兼容性修复合集
- F.min/max int32 转 int64、reorder_graph 重建图、sampling_uniform 单入口
- segment_reduce coreNum fallback、setup.py torch 依赖放宽、测试基建 npu 支持

### 4. `72c2d5e8` fix: GatherByIndex 同步修复 bdd RGCN 首调错误
- `GatherByIndex` 在 `SpMMCsrUnified` 之前执行(copy_rhs pre-gather),
  用 ACL D2H 读 torch 侧未 flush 的 efeat → 读到过期数据
- 在 GatherByIndex 入口加 `SyncTorchNpuStream()`
- 修复 test_rgcn[8-idtype0] bdd sorted/unsorted 差异

## 验证结果

5 轮冷进程稳定 **1050/1050 全部通过**(无 warmup)。

## 文件清单

- `src/array/ascend/torch_stream_sync.h`(新增)
- `src/array/ascend/spmm.cc`(SyncTorchNpuStream + GatherByIndex 同步 + SetDeviceIfChanged)
- `src/array/ascend/edge_softmax.cc`(同步 + SetDeviceIfChanged)
- `src/array/ascend/sddmm.cc`(SetDeviceIfChanged)
- `src/array/ascend/csr_get_row_nnz.cc`(同步 + SetDeviceIfChanged)
- `src/array/ascend/to_block_kernel.cpp`(新增)
- `src/array/ascend/to_block_tiling.h`(新增)
- `src/graph/transform/ascend/to_block_ascend.{h,cc}`(新增)
- `src/graph/transform/to_block.cc`(ToBlock<kDGLAscend> 特化)
- `src/array/array.cc`(CSRRowWiseSampling Ascend dispatch)
- `src/array/ascend/csr_row_wise_sampling_uniform_{kernel.cpp,.cc,_tiling.h}`(单入口 + dtype_bytes)
- `python/dgl/backend/pytorch/tensor.py`(F.min/max int32)
- `python/dgl/transforms/functional.py`(reorder_graph NPU 重建)
- `python/dgl/subgraph.py`(edge_subgraph sync)
- `python/setup.py`(torch 依赖放宽)
- `src/array/ascend/segment_reduce.cc`(coreNum fallback)
- `tests/backend/__init__.py`(npu context)
- `tests/python/pytorch/nn/test_nn.py`(_AXWb sparse to_dense)

See merge request: AI4Science/dgl-ascend!31
Signed-off-by: lhp_lhp <lhp_lhp@noreply.gitcode.com>
Signed-off-by: lhp_lhp <lhp_lhp@noreply.gitcode.com>
Co-authored-by: knightgd<knightgd@126.com>
修改issue模板

Created-by: knightgd
Commit-by: knightgd
Merged-by: xuejikan11
Description: 修改issue模板

See merge request: AI4Science/dgl-ascend!34
Signed-off-by: lhp_lhp <lhp_lhp@noreply.gitcode.com>
release: dgl-ascend 0.0.2 (torch 2.7.1 pin, packaging docs, csr slice correctness)

Created-by: lhp_lhp
Commit-by: lhp_lhp
Merged-by: knightgd
Description: 0.0.2 release prep: version bump, torch 2.7.1 pin, Development.Module, packaging docs, csr slice CPU fallback. See commit message for full validation details.

See merge request: AI4Science/dgl-ascend!30
…nary_elewise for A3

Co-authored-by: jingxupan<79962048+jingxupan@users.noreply.github.com>
Co-authored-by: panxiaomu<panxiaomu@noreply.gitcode.com>
fix(ascend): order DGL kernels against torch_npu stream and rework binary_elewise for A3

Created-by: panxiaomu
Commit-by: jingxupan;panxiaomu
Merged-by: knightgd
Description: ### 背景与根因

Atlas A3 上 dgl-ascend master 存在三处相互独立但叠加生效的问题:

1. **stream 顺序缺失(精度根因)**:torch_npu 异步提交在自己的非默认 ACL stream;DGL
   Ascend kernel 跑在默认 stream 且尾部同步阻塞。两条 stream 无顺序保证 → torch_npu 的
   写入(特征上卡等)可能仍在飞行中就被 DGL kernel 读取 → gspmm/GraphConv 结果非确定性
   错误(隔离偏差 O(1),端到端 MAE 2e-2)。
   直接把 torch 的 stream 通过 DGLSetStream 交给 DGL 不可行:torch_npu 从内部 task-queue
   线程提交、DGL 从调用者线程提交,同一条 stream 上并发提交会破坏 driver 状态。
2. **binary_elewise kernel 使用黑名单 API**:12 个(数组 vs 标量)kernel 直接对 GlobalTensor
   做标量 GetValue/SetValue,本 SoC 上有 per-core DCache 写回一致性风险。
3. **构建阻塞**:gfortran/gomp 以 `REQUIRED` 查找,无 Fortran runtime 的构建机 configure
   直接失败(两者仅被非 Ascend 路径链接)。

### 改动内容(4 个文件)

| 文件 | 改动 |
|---|---|
| `python/dgl/_ffi/base.py` | **FFI stream 桥接**:`_SyncedCDLL` 包装 libdgl,所有 C API 调用前先在 host 上同步 torch_npu 当前 stream(最简单且正确的屏障;stream 空闲时开销极小)。含 DataLoader worker 的 fork 保护(子进程跳过,不重初始化 NPU)与 `DGL_ASCEND_STREAM_BRIDGE=0` 调试开关 |
| `src/runtime/ascend/ascend_device_api.cc` | `getCurrentAscendStream()` 为空时回退 device-wide stream(尊重 `DGLSetStream` 的显式设置),不再静默返回 nullptr |
| `src/array/ascend/binary_elewise_kernel.cpp` | 12 个 kernel 的 GM 流量全部改经 UB + DMA(DataCopyPad),逐元素比较在 UB 驻留数据上进行,移除黑名单的 GM 标量访问 |
| `CMakeLists.txt` | gfortran/gomp 改为可选查找(缺失时跳过链接,不影响 Ascend 构建) |

### 验证

**隔离测试(同权重同输入,NPU vs CPU)**:

| 用例 | 修复前 | 修复后 |
|---|---|---|
| GraphConv 单 etype | 2.2 | **4.77e-7** |
| HeteroGraphConv(3 etype, sum) | 6.18 | **4.77e-7** |
| `dgl.ops.gather_mm` | 6.5(数值错误) | **2.38e-7** |
| `dgl.ops.segment_mm` | 设备异常 | **4.77e-7**(seglen 需在 CPU,接口约定) |

**端到端(OmniG 全图推理,4 die,166,153 基因 / 8 物种,thresh_hold 0.8)**:

| 指标(level_4_ALL vs GPU 基线) | 修复前 | 修复后 | 验收线 |
|---|---|---|---|
| MAE | 1.965e-2 | **4.271e-8** | — |
| Pearson r | 0.793 | **1.000000** | — |
| \|diff\|>0.5% 占比 | 40.8% | **0.0000%** | — |

与 GPU 基线恢复 bit 级对齐(与官方验收口径 §7.5 的 4.2e-8 一致)。

**性能**:4-die 端到端 36.3 min → 34.8 min(运行波动范围内,无回退)。原因:DGL Ascend
数组 kernel 本身就是尾部同步语义,桥接只是把 torch_npu 侧补齐到同样的顺序保证;同步调用点
少而粗(GNN 阶段 6 次 gspmm,其余阶段不进 DGL FFI),stream 空闲时屏障近乎零开销。

**兼容性**:不改变任何 Python/C++ API;新增 `DGL_ASCEND_STREAM_BRIDGE=0` 环境变量仅供
调试关闭桥接;DataLoader worker(fork 子进程)自动跳过桥接,不触发 NPU 重初始化。

See merge request: AI4Science/dgl-ascend!35
…scend NPU

Co-authored-by: knightgd<knightgd@126.com>
feat(unary_elewise): add NPU-native UnaryElewise (Neg) operator for Ascend NPU

Created-by: huanghaihong
Commit-by: knightgd
Merged-by: knightgd
Description: ## 变更摘要

feat(unary_elewise): add NPU-native UnaryElewise (Neg) operator for Ascend NPU(10 文件,+1499/-9)

**新增 Ascend 实现(src/array/ascend/)**
- `unary_elewise.cc`:host 直调(aclrtlaunch + tiling 下发 + 多核 CalcBlockDim,每核 ≥1024 元素门控,核数查询失败回退 8;n ≤ UINT32_MAX 显式校验,n=0 空返回)
- `unary_elewise_kernel.cpp`:i32 向量化路径——GM→UB(DataCopy 主块/DataCopyPad 尾块)→ Muls(-1) → UB→GM,TQue 双缓冲(128KB UB)
- `unary_elewise_i64_kernel.cpp`:i64 位级路径——2×int32 lane 视角 + borrow 链补码取负(静态 [0,-1] 奇偶模式,两次 1024-lane And 分块构建规避 dav_c220 int16-lane 计数陷阱),lo==0 等 Rare-tile 片整体 GM 标量回退
- `unary_elewise_tiling.h`:tiling 仅 {uint32 n},blockFormer 512 元素对齐核内推导,正确性与发射核数解耦

**分发**:`src/array/array_arith.cc` 的 UNARY_ELEMENT_OP 宏新增 kDGLAscend 分支;CPU/CUDA 既有路径不变

**测试(tests/cpp/)**:59 条 gtest 用例(黑盒 20 + FatalMsg 3 + 白盒 12 + Cross 24):`test_unary_elewise.cc` / `test_unary_elewise_whitebox.cc` / `unary_elewise_test_util.h`

**文档**:`docs/ascend/operators/unary_elewise.md`(接口、参数、约束、bit-exact 数值语义、精度、性能、测试、调用示例)+ `docs/ascend/operators/unary_elewise_dev_notes.md`(开发纪要:可复用范式、定位手段、后续建议)

## 功能与精度结论

- 一元逐元素取负 y = -x,1-D IdArray,dtype int32/int64,ctx = kDGLAscend;CPU/CUDA 路径行为不变。
- **bit-exact(整型精确运算,ops-precision-standard 整型类别标准)**:与 CPU golden 逐位一致——i32 Muls(-1) 模 2^32 乘法与取负全域等价(含 INT32_MIN wrap);i64 位级 lane 路径 + lo==0 Rare-tile GM 标量回退覆盖 INT64_MIN。
- **gtest 59/59 PASSED**(bit-exact mismatch=0),含非对齐尾块、多核余数/空闲核、全零回退路径、极值 wrap 等边界。

## 性能结论(CP4 口径,大 n 以设备侧 msprof kernel 时长为权威)

- i32 n=2^22:设备侧 34µs,e2e 324.26GB/s(较基线 +48%,路径未动)
- i64 n=2^20:设备侧 ~19.6µs(vs 标量基线 **>100×**),e2e **16.5×**(9.01→148.44GB/s);i64 n=2^22 设备侧 ~89-102µs(~82×)
- 大 n 瓶颈实测锁定 MTE 搬运主导(计算 13.7%);小 n 处 ~100µs host 启动地板(平台固定开销,与基线同量级)

## 测试说明

```bash
bash script/build_dgl_ascend.sh                        # USE_ASCEND=ON 全量构建(kernel 变更后仅支持全量重建)
./build/runUnitTests --gtest_filter='*UnaryElewise*'   # 59/59 PASS
```

## 遗留说明(非本 MR 范围的已知事项)

- CANN 8.5 多入口 kernel blob 注册问题(.ascend.meta 编号错位,rtRegisterAllKernel EE1004/107000,spmm/range 等仓内既有先例):本 MR 按单入口翻译单元(i32/i64 分文件)规避。
- host 分配悬崖(输出 >~16MB 时 aclrtMalloc/Free 分配/释放成本悬崖,运行时 AllocDataSpace 无缓存直通):影响所有大输出算子 e2e 口径,属平台运行时层事项,已移交专项。

以上遗留事项已由用户书面确认接受。

> 说明:本 MR 由 fork 仓 huanghaihong/dgl-ascend 跨仓发起(head=`huanghaihong:feat/unary-elewise`);原私仓 MR !1 将关闭,请在本 MR 审阅。


See merge request: AI4Science/dgl-ascend!38
Co-authored-by: Bowen Ma<iambowen.m@qq.com>
feat(ascend): support  BFS Nodes/Edges Frontiers capabilities in dgl

Created-by: TokenDance
Commit-by: Bowen Ma
Merged-by: knightgd
Description: ## 描述

将 BFSNodesFrontiers / BFSEdgesFrontiers 两个直调算子从独立子工程接入主仓 aten 派发体系,替代并作废原独立工程 PR !36:

- **算子宿主层**:新增 `src/array/ascend/bfs_nodes_frontiers.cc` / `bfs_edges_frontiers.cc`,注册到主仓 `src/array/ascend/`,通过 aten 派发在 NPU 上自动路由到新 kernel。
- **Kernel 层**:新增 `bfs_nodes_frontiers_kernel.cpp` / `bfs_edges_frontiers_kernel.cpp`,复用平移的 `bfs_core.h`(BFS 工作区布局 `bfs_ws_layout.h`);kernel 单入口 + `dtype_bytes` 分支,规避 CANN 9.0.0 `K_TYPE_AIV` meta 注册 bug。
- **CANN 兼容**:新增 `acl_attr_compat.h`,兼容 CANN 8.3 / 8.5 头文件差异。
- **Python 侧**:沿用既有 `dgl.bfs_nodes_generator` / `dgl.bfs_edges_generator` 接口,NPU 图自动走新 kernel,无需改用户调用。
- **可靠性保留**:errflag 双保险 / SoftSyncAll / 保底开关(回退 CPU 路径)全部保留。
- **派发修正**:`src/array/array.cc` 两处 `ATEN_XPU_SWITCH` 改为 `ATEN_XPU_SWITCH_CUDA_ASCEND`,使 BFS 系列在 NPU 上可达。
- **次要改动**:`python/dgl/traversal.py` 增加 NPU 分支;多个 ascend 源文件(coo2csr / csr_row_wise_sampling_* / csr_row_wise_topk / spmm)补 include。

## 关联的Issue

- 关联 Issue:BUPT-GAMMA#31(原已关联独立工程 PR !36,本 PR 取代该独立工程 PR 完成同一需求的上库)。
- 独立工程 PR !36 作废。

## 测试

- 新增 NPU 测试:`tests/ascend/test_bfs_nodes_frontiers_npu.py` + `tests/ascend/test_bfs_edges_frontiers_npu.py`,111 个用例在 NPU 全量通过(CP3 功能验收)。
- CPU traversal 回归:`dgl.bfs_nodes_generator` / `dgl.bfs_edges_generator` 6/6 通过。
- 独立工程对照验证通过(独立工程目录 `BFSNodesFrontiers/` 不并入本 PR)。
- 性能:CP4 验收确认不劣化。

## 文档更新

- 无需额外文档更新(Python 接口未变)。

## 类型标签

- [ ] Bug修复
- [x] 新特性
- [ ] 性能优化
- [ ] 文档更新
- [ ] 其他

See merge request: AI4Science/dgl-ascend!37
- dynamic block_dim via aclrtGetDeviceInfo instead of hardcoded 1
- keep 64-bit fill value bit-exact via FullTilingData{uint64_t n, val}
- replace per-element GM SetValue with UB stamp + DataCopyPad(Ext)
- drop fake DOUBLE_BUFFER; add MTE2->MTE3 barrier for 64-bit doubling
- extend npu tests with tile/multi-core boundary sizes
feat(array): add AscendC Full operator with vectorized fill path
fix(array): add AscendC Full operator with vectorized fill path

Created-by: gxl_gyr
Commit-by: gxlgyr
Merged-by: knightgd
Description: ## Description
<!-- Brief description. Refer to the related issues if existed.
It'll be great if relevant reviewers can be assigned as well.-->

## Checklist
Please feel free to remove inapplicable items for your PR.
- [ ] The PR title starts with [$CATEGORY] (such as [NN], [Model], [Doc], [Feature]])
- [ ] I've leverage the [tools](https://docs.google.com/document/d/1iHyj7zlmygKSk5gBPsqIqL5ASPzJSPREaNT_QdsiYA4/edit) to beautify the python and c++ code.
- [ ] The PR is complete and small, read the [Google eng practice (CL equals to PR)](https://google.github.io/eng-practices/review/developer/small-cls.html) to understand more about small PR. In DGL, we consider PRs with less than 200 lines of core code change are small (example, test and documentation could be exempted).
- [ ] All changes have test coverage
- [ ] Code is well-documented
- [ ] To the best of my knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change
- [ ] Related issue is referred in this PR
- [ ] If the PR is for a new model/paper, I've updated the example index [here](../examples/README.md).

## Changes
<!-- You could use following template
- [ ] Feature1, tests, (and when applicable, API doc)
- [ ] Feature2, tests, (and when applicable, API doc)
-->


See merge request: AI4Science/dgl-ascend!41
Co-authored-by: shaozengwei<zengwei19861029@163.com>
[feature] 实现单次启动的Ascend concat算子

Created-by: shaozengwei
Commit-by: shaozengwei
Merged-by: knightgd
Description: ## Description
<!-- Brief description. Refer to the related issues if existed.
It'll be great if relevant reviewers can be assigned as well.-->

## Checklist
Please feel free to remove inapplicable items for your PR.
- [ ] The PR title starts with [$CATEGORY] (such as [NN], [Model], [Doc], [Feature]])
- [ ] I've leverage the [tools](https://docs.google.com/document/d/1iHyj7zlmygKSk5gBPsqIqL5ASPzJSPREaNT_QdsiYA4/edit) to beautify the python and c++ code.
- [ ] The PR is complete and small, read the [Google eng practice (CL equals to PR)](https://google.github.io/eng-practices/review/developer/small-cls.html) to understand more about small PR. In DGL, we consider PRs with less than 200 lines of core code change are small (example, test and documentation could be exempted).
- [ ] All changes have test coverage
- [ ] Code is well-documented
- [ ] To the best of my knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change
- [ ] Related issue is referred in this PR
- [ ] If the PR is for a new model/paper, I've updated the example index [here](../examples/README.md).

## Changes
<!-- You could use following template
- [ ] Feature1, tests, (and when applicable, API doc)
- [ ] Feature2, tests, (and when applicable, API doc)
-->


See merge request: AI4Science/dgl-ascend!43
…llback) + review fixes

Co-authored-by: xuejikan11<xuejikan11@noreply.gitcode.com>
fix(ascend): native kernels for Range int32 and CSRToCOO (drop CPU fallback) + review fixes

Created-by: xuejikan11
Commit-by: xuejikan11
Merged-by: knightgd
Description: ### 关联 Issue
- **BUPT-GAMMA#38** https://gitcode.com/AI4Science/dgl-ascend/issues/38 (中文说明:Range int32 / CSRToCOO 原生算子修复 + 同步性能优化)

### Summary

Native AscendC fixes replacing CPU fallbacks, plus review-driven cleanups and redundant-sync removal. 2969/2969 test_nn.py passing on 910B3 (CANN 9.0.0).

Commits:
- f4fb44fe merge upstream master + local NPU fixes (2969/2969)
- 0af850f4 address review findings P1-P3 + comment corrections
- 3b9ada45 native kernels for Range int32 and CSRToCOO (drop CPU fallback)
- 4c01d1a7 restore int32 min/max NPU workaround comments
- 50d9eb9c drop redundant aclrtSynchronizeDevice in favor of stream-scoped sync

### Verified
- test_csr_to_coo_npu.py: 8/8
- Range int32/int64 (multi-block) matches CPU
- test_nn.py: 2969 passed

See merge request: AI4Science/dgl-ascend!44
Co-authored-by: panxiaomu<panxiaomu@noreply.gitcode.com>
[Feature] feat(ascend): add Ascend 950PR (A5) SoC build support

Created-by: panxiaomu
Commit-by: panxiaomu
Merged-by: knightgd
Description: ## Description

本 MR 为 DGL-Ascend 增加 **Ascend 950PR(A5,DAV_3510)芯片的构建支持**。

上游 `master` 目前仅支持 A2 / A3 系列(DAV_2201 架构):
- A2/A3 共享同一指令集与 buffer 尺寸(UB 192KB),SOC_VERSION 只影响编译出的 kernel 微码,可互换运行;
- A5(Ascend 950PR)是 **独立的 DAV_3510 架构**:kernel 源码兼容,但 **UB 更大(248KB vs 192KB)**、核心数为运行时查询(`aclrtGetDeviceInfo`),且 **必须使用各自的 SOC_VERSION** 编译。

本 MR 解决在 A5 设备上编译、安装与运行 DGL 的全部构建链路问题,改动集中在构建脚本与 CMake 配置,**不涉及任何 kernel 源码改动**(A5 kernel 源码与 A2/A3 兼容)。

### 背景与问题

在 Ascend950PR_9579(CANN 9.1.0)上按官方文档安装 DGL-Ascend,存在以下问题:

| # | 问题 | 现象 |
|---|---|---|
| 1 | 构建脚本无法识别 A5 | `detect_soc_version()` 只读 `npu-smi` 的 `NPU Name`(如 `9579`),无对应 case 映射;A5 被回退为 `ascend910b4`,编译出的 kernel 微码与 A5 不匹配 |
| 2 | A5 板卡 `npu-smi -c 0` 不可用 | 部分板卡(如 A310-50)不支持 `-c 0` 参数,导致 SoC 探测直接失败 |
| 3 | `SOC_VERSION` 校验拒绝 A5 | `is_valid_soc()` 仅白名单 A2/A3,`Ascend950PR_9579` 会被判为非法 SoC 而退出 |
| 4 | 探测时机过晚 | 原脚本在参数解析后才 setup Ascend 环境,但 SoC 探测若改用 `aclrtGetSocName` 需要 `libascendcl.so` 在库路径上 |
| 5 | `libpython` 查找硬编码 python3.11 | 官方文档使用 `python=3.10` 创建 conda 环境,`find_library(PYTHON_LIB python3.11 ...)` 找不到库,clean 构建 configure 阶段报 `PYTHON_LIB NOTFOUND` |

### 解决方式

**1. SoC 自动探测升级(build_dgl_ascend.sh)**

- 新增 **Strategy 1**:通过 `aclrtGetSocName` 获取驱动返回的精确 SoC 字符串(如 `Ascend950PR_9579`),该字符串可被 AscendC 编译器原样接受,覆盖全部系列(A2/A3/A5);
- 新增 **Strategy 2 回退**:`npu-smi -c 0` 不可用时自动重试不带 `-c 0` 的版本;
- 新增 `A5_SOC_LIST="ascend950pr_9579"`,按 A2/A3 的白名单风格管理,后续 A5 新型号经验证后追加;
- 新增 `is_a5_soc()` 判断,并在 `-h` 帮助文本中补充 A5 说明;
- 调整主流程顺序:**先 `detect_ascend_toolkit` + `setup_ascend_env`,再解析 SoC**(保证 `libascendcl.so` 可加载);
- `is_valid_soc` 白名单加入 A5,`is_a5_soc` 分支打印 `(Atlas A5 series, DAV_3510)`。

**2. CMake 配置(CMakeLists.txt)**

- 注释说明 A5(DAV_3510)需独立 SOC_VERSION,示例 `Ascend950PR_9579`;
- **修复 `libpython` 探测**:`find_library(PYTHON_LIB python3.11 python3.10 ...)`,兼容官方文档的 `python=3.10` 环境(该问题为仓库既有 bug,非 A5 特有,但阻塞 A5 上的 clean 构建)。

### 环境兼容说明(文档外,运行层)

> 本 MR 不含此改动,仅提示使用方:

官方文档 `AscendInstallation.md` 指定的 `torch_npu==2.8.0.post2` **不支持 A5**(运行时报 `Unsupported soc version: Ascend950PR 9579`)。验证发现需使用 `torch_npu==2.8.0.post5`(同为 torch 2.8 ABI,无需重编 DGL)。建议同步更新 `python/setup.py` 与 `AscendInstallation.md` 中的版本约束(可在后续 MR 中处理)。

---

## Changes

- [x] `script/build_dgl_ascend.sh`:新增 A5 SOC 自动探测(`aclrtGetSocName` 优先 + `npu-smi` 回退)、`A5_SOC_LIST`、`is_a5_soc`、`9579 → Ascend950PR_9579` 映射、帮助文本、探测时序调整
- [x] `CMakeLists.txt`:A5 SOC_VERSION 说明注释;`PYTHON_LIB` 探测兼容 python3.10
- [ ] 文档:`AscendInstallation.md` torch_npu 版本约束更新(建议后续处理)

## Test Plan / 验证

在 **Ascend950PR_9579(A5,CANN 9.1.0)** 上完成以下验证:

### 1. SoC 自动探测

```
$ bash script/build_dgl_ascend.sh -c -j 32
[INFO] Detected SoC via aclrtGetSocName: Ascend950PR_9579
[INFO] SoC: Ascend950PR_9579 (Atlas A5 series, DAV_3510)
[INFO] SoC version: Ascend950PR_9579
[INFO] Build completed successfully!
```

- 环境:conda `dgl-ascend`(python=3.10)、`torch==2.8.0+cpu`、`torch_npu==2.8.0.post5`
- 编译 256 并行时 OOM(cgroup 32GB 限制),以 `-j 32` 成功

### 2. NPU 算子正确性

| 算子 | 结果 | 对比 |
|---|---|---|
| `copy_u_sum` | ✅ | 与 CPU 结果 `allclose(atol=1e-5)` |
| `edge_softmax` | ✅ | 与 CPU 结果 `allclose(atol=1e-5)` |
| GCN 消息传递(update_all + copy_u/sum) | ✅ | 与 CPU 逐位一致(bit-exact) |

```python
import torch, torch_npu, dgl
import dgl.function as fn
g = dgl.graph((torch.tensor([0,1,2,3,1,0]), torch.tensor([1,2,3,0,3,2]))).to('npu')
g.ndata['h'] = torch.randn(4, 8).npu()
g.update_all(fn.copy_u('h', 'm'), fn.sum('m', 'h'))
```

### 3. 测试套件

```
tests/ascend: 152 passed, 54 failed, 4 xfailed
```

- 失败的 54 个集中在 `coo_ops_npu.py`(`COOGetRowDataAndIndices` / `COOSliceRows` / `COOSliceMatrix` 的 `edge-set mismatch`)与 `coo2csr_npu.py` 两个边界用例
- 该类失败为主仓已有算子问题(COO 排序 / eid 语义边界场景),**与 A5 适配无关**,核心图算子与消息传递全部正常

## Checklist

- [x] The PR title starts with `[Feature]`(建议)
- [x] 代码变更小(核心改动 < 200 行,仅 63 行新增)
- [x] 代码有文档注释(SoC 列表、探测策略、UB 差异说明均有注释)
- [ ] 测试覆盖:新增测试建议后续补充(当前验证为手工 + 既有测试套件)
- [x] 相关环境问题记录在 MR 描述中


See merge request: AI4Science/dgl-ascend!45
…se kernels & order DGL kernels against torch_npu submissionsFeat/ascend950pr adaptation (BUPT-GAMMA#43)

* fix(ascend): drop blacklisted GlobalTensor scalar access in binary_elewise kernels

Scalar GetValue/SetValue on GlobalTensor is a production-blacklist API on
Ascend950PR (per-core DCache write-back coherence risk, ADR-0007); the 12
binary_elewise (array-vs-scalar compare) kernels relied on it exclusively,
so on this SoC the result buffer was never written and e.g. HasVertices
(aten::LT) silently returned all-zero, breaking has_nodes/out_degrees and
the degree-normalization path of GraphConv.

Rewrite the kernels to:
- read the tiling block through a typed __gm__ pointer (same 3-word
  layout, host code unchanged);
- stream input/output through UB with DMA (DataCopyPad) instead of scalar
  GM access, comparing on UB-resident values.

Kernel symbols (binary_l_{lt,gt,le,ge,eq,ne}_{i32,i64}) are unchanged.
Verified against CPU on Ascend950PR_9579 (CANN 9.1.0): degrees and
GraphConv now match CPU (max diff ~3.6e-7, fp32).

* feat(ascend): order DGL kernels against torch_npu submissions

torch_npu submits kernels asynchronously on its own (non-default) ACL
stream, while the DGL Ascend array kernels launch on the ACL default
stream and block on it only until their own work completes.  The two
submitters are unordered, which made results nondeterministic and could
raise device-side faults whenever a DGL kernel read a tensor that
torch_npu had just written (feature tensors, generated index arrays).

Handing torch's stream to DGL via DGLSetStream is not a fix: torch_npu
submits to that stream from its internal task-queue thread while DGL
would submit from the caller thread, and concurrent submissions on one
stream corrupt the driver state (observed as host segfaults).

Add a barrier on the python FFI boundary instead:
- wrap the ctypes CDLL so every libdgl C API call first drains
  torch_npu's current stream on the host (cheap when idle);
- DGL ops already host-synchronize at the end, so the reverse direction
  was already ordered;
- the Ascend stream bridge latches lazily (also covers torch_npu being
  imported after dgl), stays silent when NPU is absent, skips
  interpreter shutdown, and can be disabled with
  DGL_ASCEND_STREAM_BRIDGE=0;
- getCurrentAscendStream() falls back to the DeviceAPI stream so the
  kernels always follow whatever stream the host side selects.

Overhead measured on Ascend950PR_9579: ~0.7 ms per GraphConv layer at
5k nodes / 20k edges / 128 hidden.

---------

Co-authored-by: jingxupan <jingxupan@users.noreply.github.com>
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.

8 participants