2
4
DCU技术达人
新人贴
快速上手国产计算卡海光DCU
2026-07-06 10:26:43
62
# 国产计算卡海光DCU保姆级教程 > 本博客基于曙光智算的超算互联网平台 https://www.scnet.cn/ 进行的实践与教学,其平台界面相较于北京超算云等平台更加现代,操作十分方便,几乎不需要使用vscode等ssh工具就可以获得相当便捷的运行环境。如果想要进行本地开发,也有一定的参考价值。目前我自己也在这一平台进行海洋相关科学计算和vllm推理加速的任务。 ## 一、DCU简介 ### 1.1 基本定义 DCU 全称**Deep Computing Unit(深度计算单元)**,是海光信息自研的**国产通用 GPGPU 并行加速芯片**,对标英伟达 A/H 系列 GPU,主打 AI 大模型训练、推理、高性能科学计算,是国内成熟商用通用算力卡之一。 ### 1.2 产品线迭代 1. **深算一号(DCU 8000/Z100)** 7nm 工艺,32/64GB HBM2 显存,支持 FP64 双精度,2021 年量产;兼顾超算仿真与中小模型训练,国产化算力起步主力。 2. **深算二号(DCU 8200/K100)** 迭代升级,96GB HBM3,FP32 峰值 256TFLOPS,大模型训练性能大幅提升,2025 年规模商用,适配千亿参数大模型训推一体。 3. **深算三号(8300)** 5nm 工艺,128GB 超大 HBM3E 显存,算力翻倍,对标 H100,研发推进中。 ### 1.3 硬件核心特性 - 全精度算力:FP64/FP32/FP16/INT8/FP8 全覆盖,兼顾科学计算与 AI 混合精度训练; - HBM 高带宽显存,单卡 TB/s 级带宽,适配大模型海量参数; - PCIe4.0 + xGMI 多卡高速互联,支持单机多卡、分布式算力集群扩展; - 服务器标准加速卡形态,风冷 / 液冷可选,适配国产 x86 服务器(海光 CPU 配套最优)。 ### 1.4 软件生态 DTK(核心优势) 自研**DTK 开发工具栈**,兼容 ROCm 生态,提供类 CUDA 迁移接口: 1. 少量修改即可迁移原有 CUDA 代码,迁移成本低; 2. 原生适配 PyTorch、TensorFlow、飞桨等全部主流深度学习框架; 3. 完整编译器、算子库、调试 / 性能分析工具; 4. 全面适配 ChatGLM、Qwen、Llama、文心等国产 / 开源大模型。 ### 1.5 应用场景 1. AI 领域:大语言模型训练微调、AIGC、计算机视觉、语音识别; 2. HPC 超算:气象、流体仿真、能源勘探、生物医药分子计算; 3. 行业信创:金融、政务、运营商国产化智算中心算力底座。 ## 二、基础入门:从0构建第一个DCU程序 > 本节在曙光超算互联网的 **DCU 队列** 下完成,所有命令均可在交互式 `srun` 或 `sbatch` 提交方式下使用。如果你用的是别的平台(如北京超算云、阿里云弹性加速实例),逻辑一致,只是 DTK 路径和 SLURM 队列名不同。 ### 2.1 第一步:写一个 SLURM 任务提交脚本 在超算上跑 DCU 程序,**第一步永远不是写代码,而是先把资源申请好**。海光集群几乎都使用 SLURM 作为调度器,我们用 `sbatch` 把任务扔到队列里执行。 **最小可用模板** `hello_dcu.sh` ```bash #!/bin/bash #SBATCH -p dcu # 提交到 DCU 队列(不同集群名字可能不同:kshdmcc202x、dcuh100 等) #SBATCH -N 1 # 申请 1 个计算节点 #SBATCH -n 8 # 8 个 CPU 核心(DCU 程序通常需要 CPU 线程做 I/O 与任务调度) #SBATCH --gres=dcu:1 # 关键:每节点申请 1 张 DCU #SBATCH -J hello_dcu # 作业名,方便 squeue 查询 #SBATCH --exclusive # 独占节点(避免别人和你抢 DCU 显存/带宽) # 在这里放你的 DCU 程序 ./hello_dcu ``` **常用参数速查** | 参数 | 含义 | 备注 | |---|---|---| | `-p 队列名` | 提交到哪个分区 | DCU 队列一般叫 `dcu` / `dcuh100` / `kshdmcc2026` | | `-N` | 节点数 | 多机分布式才用 `>1` | | `-n` | CPU 任务总数 | 不等于核数,是 SLURM 任务槽数 | | `--gres=dcu:N` | **每节点 DCU 数量** | 整机申请要写成 `--gres=dcu:4` | | `--cpus-per-task` | 每个任务占几个 CPU 核 | 配合 `-n` 一起算总核数 | | `--mem=0` | 申请节点全部内存 | 大数据预加载时建议加上 | **提交与查看** ```bash # 提交 sbatch hello_dcu.sh # 查看自己的作业 squeue -u $USER # 取消(作业 ID 从 squeue 输出第一列获取) scancel <作业ID> ``` 提交后用 `squeue` 能看到状态是 `PD`(排队)或 `R`(运行)。等状态变成 `R` 后,程序就会在分配到的节点上开始执行,结果写入 `hello_dcu.log`。 --- ### 2.2 第二步:寻找依赖(DTK、hipcc、运行时库) DCU 的开发工具叫 **DTK(DCU Toolkit)**,它本质上是 AMD ROCm 的国产化发行版。所以我们写代码用的 API 是 **HIP(Heterogeneous-Compute Interface for Portability)**——和 CUDA 几乎一一对应。 #### 编译器在哪? `hipcc` 一定藏在 DTK 安装目录里。不同集群的 DTK 版本不一定一样,先在交互节点上探测一下: ```bash ls /public/software/compiler/rocm/ # 典型输出:dtk-25.04.4 dtk-24.04.1 dtk-22.10.1 ``` 找到版本后,编译器路径就是: ```bash HIPCC=/public/software/compiler/rocm/dtk-25.04.4/hip/bin/hipcc ``` #### 运行时库 DCU 程序运行时需要加载 ROCm 的动态库,否则会报 `libamdhip64.so` 找不到。统一加到 `LD_LIBRARY_PATH` 即可: ```bash DTK=/public/software/compiler/rocm/dtk-25.04.4 export LD_LIBRARY_PATH=$DTK/lib:$DTK/lib64:$DTK/hip/lib:$LD_LIBRARY_PATH ``` #### 一键探测脚本(推荐加到 `~/.bashrc`) 把下面这一段加到作业脚本开头,**自动找最新可用的 DTK**,避免写死路径: ```bash DTK_VER="" for try_ver in "dtk-25.04.4" "dtk-24.04.1" "dtk-22.10.1"; do candidate="/public/software/compiler/rocm/${try_ver}/hip/bin/hipcc" if [ -f "$candidate" ]; then DTK_VER="$try_ver" break fi done [ -z "$DTK_VER" ] && { echo "找不到 DTK,请联系超算管理员"; exit 1; } DTK=/public/software/compiler/rocm/$DTK_VER export HIPCC=$DTK/hip/bin/hipcc export LD_LIBRARY_PATH=$DTK/lib:$DTK/lib64:$DTK/hip/lib:$LD_LIBRARY_PATH echo "使用 DTK: $DTK_VER" ``` --- ### 2.3 第三步:编译与链接 #### 最小编译命令 假设你只有一个源文件 `hello_dcu.cpp`,里面包含 HIP kernel: ```bash $HIPCC -std=c++14 -O2 \ --offload-arch=gfx906 \ -o hello_dcu hello_dcu.cpp ``` > **新手最常踩的坑**:忘了加 `--offload-arch=gfx906`,编译能过,但运行时 `hipGetDeviceCount` 返回 0,程序直接退出而无明显报错。 > `gfx906` 对应海光深算一号(Z100)和 AMD MI50/MI60。如果你是深算二号 K100,需要换成 `gfx940` 或 `gfx942`(具体看集群文档)。 #### 关键参数 | 参数 | 作用 | |---|---| | `-std=c++14` | HIP 头文件要求至少 C++14 | | `-O2 / -O3` | 优化等级,DCU 计算代码建议 `-O3` | | `--offload-arch=gfx906` | 目标 DCU 架构,**必加** | | `-I/path` | 第三方头文件目录(如 netcdf、hdf5) | | `-L/path -lxxx` | 链接第三方库 | | `-Wl,-rpath,/path` | 把库路径烧进可执行文件,避免运行时找不到 | #### 完整实战例子(链接 NetCDF + HDF5) 这是真实项目里常见的"既要科学库又要 GPU"的编译命令: ```bash NC_LIB=/public/home/achwjznh4b/install/bin/glnxa64 NC_INC=/public/sourcecode/amber18/AmberTools/src/netcdf-4.3.0/include $HIPCC -std=c++14 -O3 \ --offload-arch=gfx906 \ -I"$NC_INC" \ -o myapp myapp.cpp \ -L"$NC_LIB" -l:libnetcdf.so.7 -l:libhdf5.so.8 \ -Wl,-rpath,"$NC_LIB" ``` 注意:`-l:libnetcdf.so.7` 这种写法是直接链接具体的 .so 文件名,比 `-lnetcdf` 更稳(避免版本冲突),上面的"科学计算库"就是读取netCDF的库。 --- ### 2.4 实例 1:查看当前节点的 DCU 设备信息 在写第一个 kernel 之前,**先确认你申请到的节点上确实有 DCU,并且版本对**。有两种方式: #### 方式 A:Shell 一行命令(最快) ```bash rocm-smi ``` 输出类似: ![1783304586496.png](/api-forum/file/RedirectImage?path=20260706/1783304729320_1783304586496.png) 如果想看更详细的信息(频率、显存、温度): ```bash rocm-smi --showmeminfo vram --showuse --showtemp ``` #### 方式 B:写一个 C++ 程序通过 HIP API 查询 文件 `query_dcu.cpp`: ```cpp #include #include int main() { int n = 0; hipError_t err = hipGetDeviceCount(&n); if (err != hipSuccess) { printf("HIP 错误: %s\n", hipGetErrorString(err)); return 1; } printf("检测到 %d 张 DCU/GPU\n", n); for (int i = 0; i < n; i++) { hipDeviceProp_t prop; hipGetDeviceProperties(&prop, i); printf("\n=== DCU %d ===\n", i); printf("名称 : %s\n", prop.name); printf("架构 : %d.%d\n", prop.major, prop.minor); printf("全局显存 : %.1f GB\n", prop.totalGlobalMem / 1e9); printf("每个 block 的 shared mem: %zu KB\n", prop.sharedMemPerBlock / 1024); printf("每个 block 的最大线程数: %d\n", prop.maxThreadsPerBlock); printf("多处理器数量: %d\n", prop.multiProcessorCount); } return 0; } ``` 编译运行(记得按照第三步操作!): ```bash $HIPCC -std=c++14 -O2 --offload-arch=gfx906 -o query_dcu query_dcu.cpp ./query_dcu ``` 预期输出(节选): ![1783304593967.png](/api-forum/file/RedirectImage?path=20260706/1783304760157_1783304593967.png ) > 看到这些数字基本就能判断这张卡的算力档位。`gfx906 + 60 CU` 就是海光深算一号/AMD MI50 这一档。 --- ### 2.5 实例 2:第一个真正的 DCU 程序——向量加法 这是 GPU 编程的"Hello World":计算 `C = A + B`,A、B、C 各 1024 万个 float。 文件 `vec_add.cpp`: ```cpp #include #include #include // HIP_CHECK: 任何 HIP API 失败立刻报错退出 #define HIP_CHECK(cmd) do { \ hipError_t e = cmd; \ if (e != hipSuccess) { \ printf("HIP 错误 %s:%d: %s\n", \ __FILE__, __LINE__, hipGetErrorString(e)); \ exit(1); \ } \ } while(0) // __global__ 标记的函数会被编译成 DCU 上的 kernel __global__ void vec_add(const float* A, const float* B, float* C, int n) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n) { C[i] = A[i] + B[i]; } } int main() { const int N = 1 << 24; // 1677 万个元素 const size_t bytes = N * sizeof(float); // 1) 分配主机端内存并初始化 float *hA = (float*)malloc(bytes); float *hB = (float*)malloc(bytes); float *hC = (float*)malloc(bytes); for (int i = 0; i < N; i++) { hA[i] = 1.0f; hB[i] = 2.0f; } // 2) 分配 DCU 显存 float *dA, *dB, *dC; HIP_CHECK(hipMalloc(&dA, bytes)); HIP_CHECK(hipMalloc(&dB, bytes)); HIP_CHECK(hipMalloc(&dC, bytes)); // 3) 把数据从内存拷到 DCU(H2D) HIP_CHECK(hipMemcpy(dA, hA, bytes, hipMemcpyHostToDevice)); HIP_CHECK(hipMemcpy(dB, hB, bytes, hipMemcpyHostToDevice)); // 4) 启动 kernel int block = 256; int grid = (N + block - 1) / block; vec_add<<>>(dA, dB, dC, N); HIP_CHECK(hipGetLastError()); // 检查 kernel 启动是否成功 HIP_CHECK(hipDeviceSynchronize()); // 等待 DCU 算完 // 5) 把结果拷回内存(D2H) HIP_CHECK(hipMemcpy(hC, dC, bytes, hipMemcpyDeviceToHost)); // 6) 验证结果 printf("C[0] = %f(应为 3)\n", hC[0]); printf("C[N-1] = %f(应为 3)\n", hC[N - 1]); // 7) 释放资源 HIP_CHECK(hipFree(dA)); HIP_CHECK(hipFree(dB)); HIP_CHECK(hipFree(dC)); free(hA); free(hB); free(hC); return 0; } ``` #### 在 SLURM 作业里运行 把上面命令拼成 `vec_add.sh` 提交: ```bash #!/bin/bash #SBATCH -p kshdmcc2026 #SBATCH -N 2 #SBATCH -n 64 #SBATCH --exclusive #SBATCH --gres=dcu:4 #SBATCH -J MCC_RUN DTK_VER="" for try_ver in "dtk-25.04.4" "dtk-24.04.1" "dtk-22.10.1"; do candidate="/public/software/compiler/rocm/${try_ver}/hip/bin/hipcc" if [ -f "$candidate" ]; then DTK_VER="$try_ver" break fi done [ -z "$DTK_VER" ] && { echo "找不到 DTK,请联系超算管理员"; exit 1; } DTK=/public/software/compiler/rocm/$DTK_VER export HIPCC=$DTK/hip/bin/hipcc export LD_LIBRARY_PATH=$DTK/lib:$DTK/lib64:$DTK/hip/lib:$LD_LIBRARY_PATH echo "使用 DTK: $DTK_VER" $HIPCC -std=c++14 -O2 --offload-arch=gfx906 -o vec_add vec_add.cpp ./vec_add ``` 提交运行结果: ![1783304601008.png](/api-forum/file/RedirectImage?path=20260706/1783304700258_1783304601008.png ) --- ### 小结 到这里,你已经掌握了 DCU 编程的**完整最小链路**: ``` 写 SLURM 脚本申请资源 → 探测/配置 DTK → hipcc 编译 → 提交作业运行 (2.1 节) (2.2 节) (2.3 节) (2.5 节) ``` 下一节我们会从"向量加法"升级到真实的科学计算场景:利用 DCU 的多卡并行 + HIP 流并发,做一个**滑动窗口气候态统计**程序。
全部评论(0)
只看楼主
暂无数据
--
楼主
Level.6
0 帖子
楼主热帖
暂无数据