3
3
DCU技术达人
海光 DCU 的环境变量,哪些 source 不来、必须亲手 export?
2026-10-08 22:05:40
20
在 N 卡栈里写 CUDA 的那些年,环境变量属于"高级调优"——不设照样跑,设了能快一点、省一点,锦上添花。换到海光 DCU 上,这个认知要整个翻过来:在这套栈里,环境变量是开机动作,一堆 N 卡上根本不存在、也从来不需要管的变量,在这里是必需品——不设就编译断链、服务起不来、模型下不动。 先交代机器和环境,下面每一条答都出自同一台设备:海光 DCU(K100_AI)8 卡机,DTK 26.04,裸机多卡,vLLM + Triton AMD 后端,Python 3.10。还有一条读法上的原则要先立起来:DCU 的变量分两层,一层是 `source /opt/dtk-26.04/env.sh` 自动替你设好的——要认识它,出事时知道往哪查;另一层是工具链不会管、必须手动 export 的——这才是真正的开机动作。分不清这两层,就会出现"别人笔记里也写了这个变量,我设了怎么没用"的困惑。下面十五问答就按这个顺序展开。 ## 一、env.sh 替你设好的那一层 **问 1:DTK 环境怎么才算加载好了?** 答:`source /opt/dtk-26.04/env.sh`。注意 26.04 起原来挂在 `/etc/profile.d/dtk.sh` 的全局加载没有了,登录 shell 不会自动带工具链——新开终端直接敲 `hipcc --version` 报 command not found,不是装坏了,是没 source。往 `.bashrc` 里加一行 source,一劳永逸。验证用 `hipconfig --version`,输出 6.3.25521 就是加载对了。 **问 2:source 这一下,背后都设了什么?** 答:一整组。`DTKROOT=/opt/dtk-26.04`,DTK 根目录,hipcc、hipify 这些工具靠它定位自己;`ROCM_PATH` 同 DTKROOT,是生态兼容层——大量 ROCm 系工具认这个变量,DTK 靠它"伪装"成 ROCm;`HIP_PATH=$ROCM_PATH/hip`,HIP 编译与运行时的家目录;`LD_LIBRARY_PATH` 前置了 DTK 的 lib 目录,运行时找 .so 就靠它;`MIOPEN_FIND_MODE=3`,MIOpen 的算子查找策略,影响 kernel 选择行为,动它之前先想清楚;`AMDGPU_TARGETS=gfx906;gfx926;gfx928;gfx936;gfx938`,编译目标架构清单,triton 和 hipcc 都依赖它决定给哪代卡生成代码。这组变量的共同特点是设对了无感、设错了致命。 **问 3:这组变量里,缺哪个最要命?** 答:`AMDGPU_TARGETS`。它一缺,编译器不知道给哪代卡生成代码,要么直接报 `unsupported target`,要么 Triton 在构造编译目标时抛架构不识别。麻烦在于这类报错的外壳和链接器问题很像,顺着链接器查会绕很远。现在的习惯是遇到编译类报错,先花十秒 `echo $AMDGPU_TARGETS`,把这层排除掉再往下走。 **问 4:怎么判断一个变量属于哪一层?** 答:最直接的办法是做一次对照:source 之前把 `env` 存一份,source 之后再存一份,diff 一下,多出来的就是 env.sh 的管辖范围。这台机器上 diff 出来的核心就是问 2 那一组——工具链的事 env.sh 都替你办了;不在这份清单里的变量,工具链一律不管,全都要自己 export。分清这一层,后面排障时就不会犯"别人笔记里写了这个变量,我到底要不要设"的低级犹豫。 ## 二、必须亲手 export 的那一层 **问 5:TRITON_HIP_LLD_PATH 是干嘛的?env.sh 为什么不管它?** 答:Triton 的 AMD 后端硬编码回退到 `/opt/rocm/llvm/bin/ld.lld`,而 DCU 的工具链不在那个位置,所以 JIT 编译路径上它是硬依赖,env.sh 一概不负责,只能手动: ```bash export TRITON_HIP_LLD_PATH=/opt/dtk-26.04/llvm/bin/ld.lld ``` 忘了它的症状很统一:凡是触发 JIT 编译的服务启动即崩——新版 vLLM 配 TP≥2 是重灾区——报 `PassManager::run failed` 或 `ROCm linker ... not found`,而报错信息完全不指向变量缺失,顺着报错本身查会越查越偏。 **问 6:这个路径为什么必须以 ld.lld 结尾,写成 lld 不行吗?** 答:不行。lld 是个多路复用驱动,按进程名(basename)决定自己的工作模式——被叫 `ld.lld` 时才进入 ELF 链接模式,被直接叫 `lld` 时会抛 "generic driver" 拒绝干活。这两个文件在 DTK 里互为软链接、指向同一个二进制,但名字决定行为,三个字符决定进程是正常编译还是当场崩。修完用一行验证: ```bash python -c "import triton.backends.amd.compiler as c; print(c.HIPBackend.path_to_rocm_lld())" ``` 输出必须以 `ld.lld` 结尾才算修对。 **问 7:vLLM 的 attention 后端变量,能设哪些值?** 答:`VLLM_ATTENTION_BACKEND` 和 `VLLM_USE_FLASH_ATTN_PA` 管的是"attention 用哪套实现"。关键认知是:rocm 平台的支持面很窄,只认 `FLASH_ATTN_V1` 和 `TRITON_ATTN` 两个值——N 卡栈上那一长串后端名在这里大部分是无效选项。设错或设了不支持的值,症状是启动时后端选择报错,或运行中 attention 路径崩溃。 **问 8:钉卡设哪个变量?CUDA_VISIBLE_DEVICES 还认吗?** 答:认。在 DCU 上 `HIP_VISIBLE_DEVICES` 和 `CUDA_VISIBLE_DEVICES` 都被 torch 识别,而且认的都是 HCU 编号——`CUDA_VISIBLE_DEVICES=5` 依然有效,torch 会把 5 号 HCU 映射成进程内的 0 号设备,所以很多从 N 卡迁过来的启动脚本这行不用改。真正要紧的是必须设:不设就是全卡可见,多任务共存的机器上每个服务都默认抢 0 号卡。见过的经典现场是:一台 8 卡机上 A 服务跑着,新起的 B 服务一加载模型就把 A 的显存顶爆,两边 OOM 日志互相甩锅,看起来像 A 自己出了问题。单任务独占整台机器时可以偷懒不钉,只要一台机器上跑起两个以上服务,钉卡就从好习惯升级成必设项。 **问 9:内网机器,模型和包都下不动,配什么?** 答:`HF_ENDPOINT=https://hf-mirror.com` 把下载指到镜像站,`PIP_INDEX_URL`(或在 `~/.pip/pip.conf` 里配阿里镜像)解决 pip。这两个变量有个共同的时间要求:必须在 Python 进程启动前生效——`huggingface_hub` 是在 import 时读取的——所以写进 `.bashrc` 最稳。顺带一个绕过远路的案例:在同一个终端里先起了一次服务(下载失败),然后才 export,再起第二次照样失败,因为第二次起服务用的是另一个 shell。现在的标准动作是:写完 `.bashrc` 之后新开终端、`env | grep HF_` 确认、再起服务。这类问题报错倒是直白——卡在下载阶段超时重试刷屏 `Connection timed out`——不像编译链的坑那么隐蔽,但每台新机器第一次都会撞上。 **问 10:哪些变量适合写进 .bashrc,哪些只能进启动脚本?** 答:看两件事:要不要在 Python 进程启动前生效,要不要在非交互 shell 里生效。`HF_ENDPOINT`、`PIP_INDEX_URL` 写 `.bashrc` 就够——它们只要求在进程启动前就位;env.sh 的 source 也可以放进 `.bashrc`,让交互终端省一步。但 `TRITON_HIP_LLD_PATH`、钉卡变量、业务路径这类必须进 start.sh 本身——cron 和脚本拉起的场合根本不读 `.bashrc`,写在里面等于没写(机制见问 12)。一条判断口诀:终端里用的进 `.bashrc`,机器上跑的进 start.sh,两头都要的干脆两边都写。 **问 11:自己写的服务,路径配置怎么管?** 答:路径类配置一律环境变量注入,服务代码里不写死路径。模型产物目录用 `CKPT_DIR` 这类变量注入,服务启动第一件事就校验,缺了立刻报错退出: ```python import os, sys ckpt = os.environ.get("CKPT_DIR") if not ckpt or not os.path.isdir(ckpt): sys.exit(f"[fatal] CKPT_DIR 未设置或目录不存在: {ckpt}") ``` 五行成本,换来任何一次"忘了配"都在启动第一秒暴露,而不是在半夜的日志里。校验要放在读配置的最前面、任何依赖路径的初始化之前,晚了就失去 fail fast 的意义。配套还有半条规矩:变量名要收敛。各服务各起各的名(`MODEL_DIR`、`WEIGHTS_PATH`、`CKPT_ROOT`……),同一个值就得在三处脚本里写三遍,改一次目录要记着改三处。统一成一份变量清单、一个公共 env 段,所有 start.sh 只做 source 加注入。 ## 三、三个最常见的翻车点 **问 12:.bashrc 里明明写了,cron 里怎么就是没有?** 答:`.bashrc` 只在交互式 shell 里加载。cron、systemd、被别的脚本拉起,都属于非交互 shell,根本不读它——以为"全局"的变量,其实只活在自己的终端里。修法:启动脚本第一段显式 `source /opt/dtk-26.04/env.sh`,关键 export 写进脚本本身,不依赖任何 shell 配置文件。 **问 13:路径设了,JIT 编译还是崩,报 generic driver?** 答:十有八九是 `TRITON_HIP_LLD_PATH` 的结尾写成了 `lld`。对照问 6 的机制检查一遍,把结尾改成 `ld.lld`,再用那行验证命令确认输出。 **问 14:变量赋值了,子进程里为什么是空的?** 答:赋值没加 export。不带 `export` 的赋值只是 shell 局部变量,不会传给子进程;多进程服务里最容易中招——TP 拉起一堆 worker,父进程自己能用,worker 全瞎。一律写 `export VAR=value`,脚本末尾加一句 `env | grep -E 'TRITON|HIP|DTK'` 打印确认,眼见为实。 ## 四、收拢成模板 **问 15:新服务的 start.sh,开头有没有能直接抄的写法?** 答:有,这段就是标准开头: ```bash #!/bin/bash # ---- DCU env 段:新服务 start.sh 标准开头 ---- source /opt/dtk-26.04/env.sh # 工具链(26.04 起必须显式 source) export TRITON_HIP_LLD_PATH=/opt/dtk-26.04/llvm/bin/ld.lld # 结尾必须是 ld.lld export HIP_VISIBLE_DEVICES=5 # 钉卡,多任务共存必设 export HF_ENDPOINT=https://hf-mirror.com # 模型下载走镜像 export CKPT_DIR=/data/models/your_model # 业务路径注入 env | grep -E 'DTK|TRITON|HIP|HF_|CKPT' # 启动前眼见为实 ``` 照抄之后按服务实际情况改两处:钉卡的 HCU 号和 `CKPT_DIR` 的路径。 这套生态里,环境变量不是配置,是依赖。N 卡栈把大量依赖做成了自动发现,DCU 栈把其中一部分显式交还给人——这既是坑,也是透明的排障入口:服务行为不对时,`env | grep -E 'DTK|TRITON|HIP'` 先扫一遍变量在不在,再谈别的。把变量清单模板化、写进每个 start.sh,这类问题就从玄学变成了一眼扫完。
全部评论(0)
只看楼主
暂无数据
--
楼主
Level.6
0 帖子
楼主热帖
暂无数据