海光 BW1000 DCU 初探:从硬件特性、软件栈到开发实践的初学者指南

初学者首次接触海光BW1000:需要了解哪些内容以及如何使用这块国产DCU

记录时间:2026-07-16
2026先导杯(基于国产DCU上Qwen大模型推理加速)后记

这篇东西其实算是比赛结束后补的一次作业。

我在参加比赛的时候成绩并不是很好,在那段时间大部分时间都在研究模型、推理框架以及各种参数,当时基本是遇到一个问题就先解决一个问题,服务能跑起来以后,再继续处理下一个环节。等到事情结束回过头来看发现了一个问题:代码在BW1000上运行很多次,但是对这张卡却了解不多。

公开参数并不难找,但真正开始开发以后,遇到的问题往往不在参数表里。为什么在 PyTorch 中还要使用.cuda()?环境中的 torch 可以更新吗?数据从 CPU 移动到 GPU 多快?一张 64GB 显卡为什么放进去一个模型还是会显存不足?

所以我后来把环境重跑一遍,再补几组比较简单的测试。例如做矩阵乘法、CPU 和 DCU 之间拷贝,以及简单显存读写操作等。

首先是一个简单的环境描述:我的这个环境状态良好并且效果良好,在大规模矩阵中,FP16、FP32、FP64 的 GEMM 比较接近公开资料展示的速度大约为 91.5%、93.1% 和 87.6%,而简单的读写操作根据其传输的数据量来估计也在开放显存带宽的八成左右,至少在这些基本任务上,这张卡以及相关软件栈都是正常工作的。

DCU是什么

DCU可以看作是针对通用并行计算进行加速的设备。CPU负责系统的管理和一些复杂的分支操作等,而DCU更擅长处理大量的相同计算任务,例如矩阵乘法、张量运算、深度学习训练及推断、数值模拟、科学计算等。

刚开始我看这个软件栈也是比较混乱,后来简单画出来如下图所示,就方便多了。

应用代码 ↓ PyTorch / vLLM / TensorFlow / 科学计算程序 ↓ 适配版框架、BLAS、DNN、通信库 ↓ HIP、编译器、运行时、性能工具 ↓ DTK 与驱动 ↓ BW1000 DCU

根据海光公开资料, DCU 是基于 GPGPU 架构、兼容类 CUDA 环境的通用协处理器,同时提到了双精度计算、高带宽内存和并行处理能力。1

“类CUDA”这3个字很容易让读者产生一种误解:既然接口相似,那么原来的代码可以直接搬过来使用吗?并非如此,普通的PyTorch模型如果是使用常用的算子,则可以较顺畅;但是如果涉及到自定义CUDA扩展、Triton kernel、flash-attn或者经过大量修改的推理引擎等,则不能有这种想法。接口相似只是一方面的问题,在底层实现以及版本是否匹配才是更重要的问题。

BW1000 的公开参数,主要看下边几项

模力方舟官网公布的BW1000参数有:64GB HBM2e、1.6TB/s显存带宽、约300W典型功耗,以及支持FP16、FP32和FP64等多种精度。而参考计算能力为:FP16 480TFLOPS、FP32 60TFLOPS、FP64 30TFLOPS,并且说明不支持FP8。2

项目公开资料数据实际开发中应该关心什么
存储64 GB HBM2e是否能放下所有模型权重、KV cache以及临时空间
显存带宽1.6TB/s访存型算子是否会由于等待数据而被阻塞
FP16480 TFLOPS训练、推理以及混合精度计算
FP3260 TFLOPS一般运算以及对精度有一定要求的应用场景
FP6430 TFLOPS科学计算,仿真,双精度线性代数等。
FP8不支持需要选择量化方案或者使用FP8 KV cache 在此之前需要进行检查。
典型功耗约 300 W根据设备所承受负载情况进行参考使用,不能作为业务测试依据

64GB显存看似很大,但是显存并非是被模型权重所占用。权重只是一部分,在进行推理过程中还会存在KV cache、workspace、框架缓存以及编译生成的buffer等,而在跑图捕获时还会有新的内容。再加上分配器预留以及内存碎片等问题的存在,实际上可用的空间远远小于看上去那么大。

我在做长上下文推理任务中明显感觉到,显存参数不能设置到最大值。短请求可以正常启动,但经常有长请求、warmup以及并发oom的情况发生。留有一定的冗余虽然看起来很保守,但是实际上却更节省时间。

理论算力也差不多。GEMM 能跑高说明这条路线可行,但是实际模型中还有 attention、归一化、采样、CPU 调度、网络服务以及各种小算子,最终得到 tokens/s 并不能简单地用 TFLOPS 来换算。

问题一:升级 torch

我已经拿到环境有 DTK、HIP、PyTorch 和 vLLM,PyTorch 接口仍然是熟悉的写法,torch.cuda.is_available()返回也同样是True。当时看到这个情况也是放松了警惕,以为与普通的 CUDA 环境区别不大。

但随着我敲下这行代码出现了个问题:

pipinstall--upgradetorch

我所在环境中的torch带有"dtk2604"标记,vLLM为"0.18.1+das.dtk2604"。这表示这个包已经与当前DTK进行了适配,在使用来自公网PyPI的标准PyTorch覆盖之后,虽然版本号可能变化,但是设备无法被检测到;更严重的是可能会出现ABI、算子编译以及运行时的问题。

类似的也会出现在 Triton、flash-attn 自定义扩展等地方。很多时候出现问题并不是因为代码本身有误,而是以往的传统开发能否真正适用于新环境?也就是说像这样每个包都可以正常安装但是彼此之间却不能兼容。解决这些问题相当耗费时间,错误提示处不一定就是问题发生的地点。

OpenCloudOS 的一个 BW1000 部署示例使用了驱动 6.3.16 和 DTK 25.04.2并且用hy-smirocm-smi查看设备。3而这一组版本在我自己的机器上并不是这样,这也提示我们在网上查找资料时要留意版本号是否相同。

我这台机器(比赛环境)的情况

后面的所有测试都是在这个环境中进行。表格较长,但是版本号还是要保留,过几个月再看能够知道自己当时跑的是哪个版本。

项目当前环境
操作系统Ubuntu 22.04.5 LTS
内核5.10.134-17.1.3.sga8.x86_64
CPUHygon C86处理器,2路,lscpu显示128个逻辑处理器
系统内存约 503 GiB
DCU单卡,设备名为BW
显存hy-smi显示 65520 MiB,PyTorch 显示约 63.98 GiB
Compute Unit80
ISAgfx936
驱动6.3.31-V1.5.0a
hy-smi1.24.0,编译日期 2026-03-23
DTK/opt/dtk-26.04-DCC2602-0317
HIP6.2.0-0
Python3.10.12
PyTorch2.10.0,pip包带有"dtk2604"标记
vLLM0.18.1+das.dtk2604

还有一些比较底层的信息:设备挂载在0000:55:00.0,内核驱动为hycu,NUMA node 是 2,PCIe 状态是 32.0 GT/s、x16。rocminfo显示有 80 个 CU、wavefront size 64、最大主频 1500 MHz。空闲状态下温度约为 50-55 摄氏度,功率约为 71-78 瓦。

日常检查主要用下面这些命令久够用:

uname-acat/etc/os-release lscpufree-hhy-smi hy-smi-ahy-smi--showmeminfovram hy-smi--showtopohy-smi--showdriverversionrocminfo hipcc--versionpython3-mpip list|grep-E\"dtk|torch|vllm|deepspeed|hip|rocm|triton"

PyTorch 侧再跑个最小检查:

importtorchprint("PyTorch:",torch.__version__)print("Available:",torch.cuda.is_available())print("Device count:",torch.cuda.device_count())iftorch.cuda.is_available():props=torch.cuda.get_device_properties(0)print("Device:",props.name)print("Memory GiB:",props.total_memory/1024**3)print("Compute units:",props.multi_processor_count)

在我这台机器上,这里返回的是True,设备名为BW``,尽管接口仍然使用torch.cuda`,但在内部实现上是基于 DCU 的适配层。

矩阵乘法测试,看看三种精度

比赛后我做的第一个测试是矩阵乘法。矩阵乘法是一个非常经典的并行计算的例子,代码少,跑得快,同时可以比较 FP16, FP32 和 FP64。

测试用方阵,大小由 2048 增加至 12288。每组预热 10 次,测量 30 次,在开始以及结束时调用torch.cuda.synchronize()函数。张量创建尽可能不在计时范围内。吞吐量取值为2 × N³

这里使用的是框架层测试而非专门针对某一家厂商的测试工具,特别是像2048这种亚毫秒级的结果,由于主机计时以及同步的开销较大,在此更多是观察趋势。

精度矩阵规模平均时间(ms)中位时间(ms)中位吞吐(TFLOPS)峰值显存(MiB)
FP1620480.100.09183.5164
FP1640960.480.48288.27160
FP1681923.643.64301.91544
FP16122888.458.45439.181184
FP3220480.410.4141.6496
FP3240962.592.5853.20288
FP32819219.9519.9355.161056
FP321228866.4966.4755.832336
FP6420480.770.7622.51160
FP6440965.565.5524.75544
FP64819245.8245.9023.952080
FP6412288141.19141.2126.284640

FP16 从 8192 到 12288 提升显著。

按表里的最好结果算:

  • FP16 是 439.18 TFLOPS,约为公开参考值 480 TFLOPS 的 91.5%;
  • FP32 是 55.83 TFLOPS,约为 60 TFLOPS 的 93.1%;
  • FP64 是 26.28 TFLOPS,约为 30 TFLOPS 的 87.6%。

这些对于我来说已经足够有说服力的结果。虽然不能保证所有的工作负载都能达到90%,但是至少可以说明目前使用PyTorch与DTK结合可以充分利用矩阵计算的能力。而FP64的表现也给我留下了深刻的印象,在支持半精度AI的同时,双精度的科学计算也是有意义的。

数据搬运

然后是pageable host memory以及pinned host memory上H2D(Host to Device)、D2H(Device to Host),目标张量预先申请,在复制完毕之后进行同步。如表所示:

方向Host 内存数据量(MiB)中位时间(ms)估算带宽(GB/s)
H2Dpageable645.2412.81
D2Hpageable642.0133.34
H2Dpinned641.4446.68
D2Hpinned641.4446.52
H2Dpageable25620.2613.25
D2Hpageable2567.2936.84
H2Dpinned2565.5548.34
D2Hpinned2565.6747.37
H2Dpageable102485.6712.53
D2Hpageable102427.5838.93
H2Dpinned102422.1048.58
D2Hpinned102422.5747.58

pinned H2D 基本能稳定在 47~49 GB/s,pageable H2D 只有 12~13 GB/s。
这也是为何在训练或者推理循环中反复搬运小张量得不偿失。即使DCU计算速度非常快,但是每一遍都需要等待CPU传递数据,最终还是白白浪费时间。怎样合理使用CPU以及DCU计算能力也是在工程上需要考虑的问题。(在资源调度上是否能解决这个问题?这方面的知识我了解尚浅如果有了解的朋友可以在评论区讨论
另外,.item().cpu()等函数也要注意,它们也有可能造成同步,在计时脚本中如果不考虑这个问题,则测得的时间实际上是任务提交的时间,我是之前在查看结果时常常忽略这一点,后来我统一了所有的地方进行同步。

显存读写

然后是D2D copy以及一个最简单的FP32 vector add。

在此之前需要知道 D2D copy 如果用“复制的数据量 ÷ 时间”,得到的是有效复制吞吐;但是从 HBM 角度看,它发生了读取源张量一次,写入目标张量一次,因此总的流量应乘以 2。vector add 是 C=A+B,即两次读取一次写入,因此用三个张量的数据量来衡量。

测试单个张量或有效数据规模估算 HBM 总流量中位时间(ms)有效复制吞吐(GB/s)估算 HBM 流量带宽(GB/s)
D2D copy256 MiB512 MiB0.44614.861229.72
D2D copy1024 MiB2048 MiB1.62661.251322.50
D2D copy4096 MiB8192 MiB6.37674.441348.88
FP32 vector add256 MiB768 MiB0.661224.89
FP32 vector add1024 MiB3072 MiB2.531273.38
FP32 vector add4096 MiB12288 MiB10.011287.68
根据HBM读写流量计算,D2D约为1.23~1.35TB/s,vector add为1.22~1.29TB/s,约等于公开1.6TB/s参考值的80%左右。

Qwen3.5-27B 推理任务

微基准跑起来很快,真实推理不是。

我在一个 Qwen3.5-27B 长上下文任务中使用了 vLLM, Triton/HIP kernel, KV cache 以及torch.compile。有一回的日志显示中,模型加载耗时约 374s,torch.compile耗时约 209s, profiling 和 warmup 大约也是 208s, engine init 记录了一个较长的时间即 436s(可能是我改毁了一些东西)。

这些阶段是有包含关系,不是简单的相加。但是感觉很直观的一点是:一个启动需要等待很久的时间。如果稍微改动一些内容就会导致重新编译,那么半天都未必能够跑完一轮,大部分时间都是花费在加载以及warm-up上。

这也是我后来更加重视编译缓存的原因。第一次启动时间和稳定状态下的请求时间要区别对待,第一个请求不能算作正常的吞吐量,在进行 A/B测试的时候,一方面命中缓存另一方面又重新编译,结果无法进行对比。

显存规划也是一样,在长上下文中,模型权重并不是唯一的部分,还有KV cache、workspace、图捕获以及临时缓冲区都需要空间,如果设置gpu_memory_utilization过大,对于短期请求可能是可以接受的,但是对于较长的请求或者是warmup就会出现问题,在实际开发中应该先留有余地,把服务稳定下来之后再去逐步提高这个值。

写在最后

BW1000 给我的总体感受是:硬件基本功扎实,在 FP16、FP32、FP64 大矩阵运算上均达到公开参考结果水平,在框架层面的显存带宽也得到了良好体现。64GB 显存对于大模型以及科学研究非常有利。

开发上真正需要适应的是软件栈。DTK、HIP、适配版 PyTorch 及上层框架是整体,版本对上可以很流畅,版本混用会非常麻烦排查问题。这并非 BW1000 所特有,在国产异构环境下,目前更多需要开发者自己做记录与核对。

我这次做的都是很基础的测试,离完整评价一张计算卡还差得很远。多卡通信、真实训练吞吐、不同模型的推理表现、自定义 kernel 优化等都没有涉及。但是对初学者第一次使用 BW1000 而言,先了解机器的状态如何、公开的数据是什么样的、程序容易出现的问题是什么,相信这份测试报告应该能起到一定的作用!
最后,感谢阅读!

参考资料


  1. 海光信息技术股份有限公司,《首次公开发行股票并在科创板上市招股说明书(申报稿)》,“海光 DCU”相关章节,上海证券交易所:https://static.sse.com.cn/stock/disclosure/announcement/c/202111/001043_20211108_ALLG.pdf ↩︎

  2. 模力方舟,《海光 GPU》,包含 BW1000 公开规格、HIP、DTK 和适配版 PyTorch 环境说明:https://ai.gitee.com/docs/compute/clusters_gpu/hygon_gpu ↩︎

  3. OpenCloudOS,《基于 OpenCloudOS 的海光 DCU 部署实践》,包含 BW1000、驱动、DTK 和环境检查示例:https://docs.opencloudos.org/OC9/ai-deployment/GPU-optimization-practice/hygon-deployment/ ↩︎