dsh-scnet 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  集群的主机名、端口等参数来自 `clusters/<集群短名>.conf`。
4
4
  本文用 `<集群>`、`<主机名>`、`<端口>` 表示从 profile 读出的值。
5
5
 
6
- ## 手工配置(不用 setup-ssh.sh 时)
6
+ ## 手工配置
7
7
 
8
8
  ```bash
9
9
  # 1. 装私钥
@@ -42,14 +42,14 @@ Host <集群> <主机名>
42
42
  UpdateHostKeys no
43
43
  ```
44
44
 
45
- ## 各选项的理由
45
+ ## SSH 选项说明
46
46
 
47
47
  **`ControlPersist 10m` 而非 `yes`**:永久驻留的 master 在笔记本休眠或换网络后会
48
- 变成失效 socket,反而要手工清理。10 分钟覆盖一次交互操作的节奏,又能自然回收。
48
+ 变成失效 socket,可能留下需要清理的失效 socket。10 分钟覆盖一次交互操作的节奏,又能自然回收。
49
49
  实测复用后单条命令从约 2 秒降到 0.57 秒。
50
50
 
51
51
  **`ServerAliveInterval 60`**:应用层心跳,防止空闲 SSH 会话被中间网关静默切断。
52
- 跑长任务时关键。`TCPKeepAlive` 是 TCP 层的,两者互补。
52
+ 用于保持长时间空闲会话。`TCPKeepAlive` 是 TCP 层的,两者互补。
53
53
 
54
54
  **`UpdateHostKeys no`**:部分平台的服务端对主机密钥轮换扩展返回错误签名:
55
55
 
@@ -57,9 +57,7 @@ Host <集群> <主机名>
57
57
  client_global_hostkeys_prove_confirm: server gave bad signature for RSA key 0
58
58
  ```
59
59
 
60
- 这是平台侧实现问题,不影响安全性——首次记录的主机密钥仍在正常校验。关掉只为消除
61
- 告警噪音。**只在遇到这个告警的集群上加**(profile 里标
62
- `NEEDS_UPDATE_HOSTKEYS_NO=yes`)。
60
+ 该设置仅禁用服务端主机密钥轮换扩展;首次主机密钥仍按正常流程校验。仅在出现该告警且 profile 标记 `NEEDS_UPDATE_HOSTKEYS_NO=yes` 的集群上使用。
63
61
 
64
62
  **`IdentitiesOnly yes`**:只用指定的私钥。ssh-agent 里密钥多时,避免因尝试次数
65
63
  过多被服务端拒绝。
@@ -91,7 +89,7 @@ profile 里的 `KEY_NAME_MARKER` 就是用来从这种文件名里提取用户
91
89
  `scnet-hpc` profile 使用 `_<CLUSTER_HOST>_` 占位符,所以安装时通常需要显式传
92
90
  用户名,或在本地私有 profile 中补齐真实标记。
93
91
 
94
- 查看当前密钥指纹:
92
+ 查看密钥指纹:
95
93
 
96
94
  ```bash
97
95
  ssh-keygen -lf ~/.ssh/id_rsa_<集群>
@@ -113,7 +111,7 @@ ssh-keygen -p -f ~/.ssh/id_rsa_<集群>
113
111
  | `Connection timed out` | 端口被本地网络阻断(超算常用非 22 端口)|
114
112
  | `Bad owner or permissions on config` | `chmod 600 ~/.ssh/config` |
115
113
  | `WARNING: UNPROTECTED PRIVATE KEY` | `chmod 600 ~/.ssh/id_rsa_<集群>` |
116
- | 首次连接卡住不动 | 在等确认主机指纹,加 `-o StrictHostKeyChecking=accept-new` |
114
+ | 首次连接等待主机指纹确认 | 在等确认主机指纹,加 `-o StrictHostKeyChecking=accept-new` |
117
115
 
118
116
  多数超算平台有 **IP 白名单**,换网络(家里/公司/热点)后可能连不上,
119
117
  需要去控制台加当前 IP。
@@ -125,7 +123,7 @@ ssh -o BatchMode=yes <集群> '<命令>'
125
123
  ```
126
124
 
127
125
  `BatchMode=yes` 让认证失败立刻返回,而不是卡在密码提示上等输入。写自动化脚本时
128
- 必加,否则可能挂住。
126
+ 应启用,以避免自动化流程等待交互输入。
129
127
 
130
128
  ## 文件传输
131
129
 
@@ -135,4 +133,4 @@ scp <集群>:/public/home/$USER/scripts/logs/job_123.log .
135
133
  rsync -avz --progress ./dir/ <集群>:/public/home/$USER/dir/ # 大量文件
136
134
  ```
137
135
 
138
- 走同一个长连接,不需额外配置端口。
136
+ 上述命令复用 SSH profile 中的连接参数。
@@ -11,7 +11,7 @@
11
11
  ### 编译型软件的分层验证
12
12
 
13
13
  - **把编译放到计算节点**:C++/HIP 大型构建的峰值内存可能远高于登录节点限额。
14
- 编译器进程被 OOM kill 时,先换到有明确内存配额的计算作业,不要立即归因于源码。
14
+ 编译器进程被 OOM kill 时,先换到有明确内存配额的计算作业,先排除资源限制,再判断源码问题。
15
15
  - **只生成目标架构**:显式设置目标 `gfx` 架构。默认同时生成多个架构会成倍增加
16
16
  编译时间、产物体积和峰值内存。
17
17
  - **升级工具链后重跑最小构建**:DTK/编译器升级可能改变 wrapper 头、host/device
@@ -20,7 +20,7 @@
20
20
  可见的 HSA/HIP 库或符号链接。以目标计算节点解析到的真实库文件为准,必要时通过
21
21
  CMake cache 变量显式传入,不创建全局假链接。
22
22
  - **先串行能力、后并行能力**:先完成无 MPI 的单卡最小构建和功能验证,再开启 MPI,
23
- 最后测试 GPU-aware 通信与多卡扩展,避免把编译器、运行库和通信栈问题混在一起。
23
+ 最后测试 GPU-aware 通信与多卡扩展,以隔离编译器、运行库和通信栈问题。
24
24
 
25
25
  ### GPU-aware MPI 的验证边界
26
26
 
@@ -39,7 +39,7 @@ GPU-aware on/off 对照。单节点验证可先固定共享内存与 self 传输
39
39
 
40
40
  ### 已验证的典型边界
41
41
 
42
- - **gfx936 / BW1000**:Triton、硬件 FP8 `torch._scaled_mm`、部分 bitsandbytes INT8 路径可能不可用;纯 PyTorch 软件反量化可作为推理兜底,但需要单独做性能和精度验证。
42
+ - **gfx936 / BW1000**:Triton、硬件 FP8 `torch._scaled_mm`、部分 bitsandbytes INT8 路径可能不可用;纯 PyTorch 软件反量化可作为兼容路径,但需要单独做性能和精度验证。
43
43
  - **gfx906 / Z100**:CentOS 7.6 的 glibc 2.17 会限制 manylinux wheel 版本;安装 Python 软件时优先选 manylinux2014 / manylinux_2_17 兼容包。MinerU 场景中,Python 3.10 + onnxruntime 1.16.3 是已验证方向,magika 版本/API 需要随源码适配。
44
44
  - **GROMACS HIP**:先验证 CMake 最低版本、DTK 的 `lib`/`lib64` CMake 路径、目标架构、FFTW 预置和 SIMD;CUDA 兼容层与原生 HIP 的性能不可直接互相推断。
45
45
 
@@ -55,18 +55,18 @@ echo "test_exit_code=$rc"
55
55
  exit "$rc"
56
56
  ```
57
57
 
58
- 不要只看 `sacct` 的 `COMPLETED`。脚本必须显式传递最后一个测试命令的退出码,并同时读取 `.out/.err`。
58
+ 不能只依据 `sacct` 的 `COMPLETED` 判定成功。脚本必须显式传递最后一个测试命令的退出码,并同时读取 `.out/.err`。
59
59
 
60
60
  ### 公开报告模板
61
61
 
62
- 标题采用“项目 + 加速器/平台 + 编译与性能/兼容性测试报告”。正文建议按以下顺序:
62
+ 标题采用“项目 + 加速器/平台 + 编译与性能/兼容性测试报告”。正文可按以下顺序:
63
63
 
64
64
  1. 环境信息
65
65
  2. 编译过程与主要难题
66
66
  3. 最终方案与验证结果
67
67
  4. 测试数据与资源占用
68
68
  5. 已知限制与注意事项
69
- 6. 经验总结与通用建议
69
+ 6. 适用范围与可复用结论
70
70
  7. 附录:快速复现命令
71
71
 
72
72
  发布前扫描:
@@ -1,6 +1,6 @@
1
1
  # 排查作业失败
2
2
 
3
- ## 第一原则:不要相信 `sacct` 的 State
3
+ ## 作业状态与实际退出码
4
4
 
5
5
  bash 脚本里 Python 崩了之后,bash 继续执行后面的行,作业以**最后一条命令**的退出码
6
6
  结束。真实案例:
@@ -10,10 +10,10 @@ $ sacct -j <JOB_ID> --format=JobID,JobName,State,ExitCode,Elapsed
10
10
  <JOB_ID> | example-job | COMPLETED | 0:0 | 00:34:32
11
11
  ```
12
12
 
13
- 看着完美,实际上 Python 在第 3 分钟就抛了 `ValueError`,日志末尾还打印了脚本里
13
+ 该记录不能证明 Python 工作负载成功。Python 可能已在第 3 分钟抛出 `ValueError`,而日志末尾仍打印脚本中
14
14
  写的 `===== COMPLETE =====`。
15
15
 
16
- **排查顺序永远是:读日志 → 看 State,不是反过来。**
16
+ 排查时先读取日志和工作负载退出码,再结合调度器 State 判断。
17
17
 
18
18
  预防:脚本末尾写
19
19
 
@@ -43,7 +43,7 @@ sbatch: error: min tres(gres/dcu) request 0 exceeds per-job max tres limit 1
43
43
  sbatch: error: QOSMinGRES
44
44
  ```
45
45
 
46
- 忘了 `--gres=dcu:N`。这个分区**强制**每个作业至少 1 张 DCU,纯 CPU 作业也要写。
46
+ 该分区要求每个作业至少申请 1 张 DCU。补充 `--gres=dcu:N`;纯 CPU 负载也受该分区策略约束。
47
47
 
48
48
  ### `too much memory was requested relative to the number of CPUs`
49
49
 
@@ -82,7 +82,7 @@ httpcore.ConnectError: [Errno -2] Name or service not known
82
82
  ### `cannot get address for 'hipDrvLaunchKernelEx' from libamdhip64.so`
83
83
 
84
84
  Triton。DTK 26.04 的 HIP 运行时缺上游 ROCm 7 的 API,Triton 的 AMD backend 加载
85
- 即失败。**放弃这条路**,包括所有依赖 Triton kernel 的框架(SGLang FP8、vLLM ROCm
85
+ 即失败。该软件栈不能使用此 Triton 路径,依赖对应 Triton kernel 的框架也不适用(SGLang FP8、vLLM ROCm
86
86
  MoE、transformers finegrained-fp8)。
87
87
 
88
88
  郑州集群最近还会先报另一种缺库:
@@ -91,7 +91,7 @@ MoE、transformers finegrained-fp8)。
91
91
  ImportError: libgcvm.so.17git: cannot open shared object file
92
92
  ```
93
93
 
94
- 本质相同,都是 Triton 在当前 DTK/DCU 软件栈上不可用,不要继续调 Triton kernel。
94
+ 本质相同,都是 Triton 在当前 DTK/DCU 软件栈上不可用,继续调整 Triton kernel 参数不能解决该运行时缺失。
95
95
 
96
96
  ### `torch._scaled_mm is only supported on CUDA devices with compute capability >= 9.0 or 8.9, or ROCm MI300+`
97
97
 
@@ -114,7 +114,7 @@ cat: No such file or directory ← 连日志都没有,因为写不进
114
114
  1. `--output` / `--error` 路径里有未展开的变量(`$USER`、`$HOME`)
115
115
  2. **日志目录不存在** —— Slurm 不会自动创建
116
116
 
117
- 修法:`#SBATCH` 里写完整字面量路径,提交前 `mkdir -p <日志目录>`。
117
+ 处理方法:`#SBATCH` 里写完整字面量路径,提交前 `mkdir -p <日志目录>`。
118
118
  `scripts/new-job.sh` 会展开好用户名并提示建目录。
119
119
 
120
120
  ### `module load` 静默失败:作业返回 0 但 `ROCM_PATH` 没设置
@@ -129,9 +129,9 @@ ROCM_PATH=未设置
129
129
  ### python exit=0 ← 作业「成功」了
130
130
  ```
131
131
 
132
- 这比直接报错更坑,因为退出码是 0。实测于昆山集群。
132
+ 该现象可能返回退出码 0,因此还需检查模块环境变量和探针输出。该行为已在昆山集群观测。
133
133
 
134
- 修法:shebang 用 `#!/bin/bash -l`,或在 heredoc 内包一层 `bash -l`。
134
+ 处理方法:shebang 用 `#!/bin/bash -l`,或在 heredoc 内包一层 `bash -l`。
135
135
  `scripts/new-job.sh` 生成的脚本已经用 `bash -l`。
136
136
 
137
137
  自检:作业里打印 `echo "ROCM_PATH=${ROCM_PATH:-未设置}"`,未设置就说明没生效。
@@ -145,7 +145,7 @@ ROCM_PATH=未设置
145
145
  SyntaxError: Non-ASCII character '\xe5' ... no encoding declared
146
146
  ```
147
147
 
148
- 修法:作业脚本里显式加载 Python 3 module:
148
+ 处理方法:作业脚本里显式加载 Python 3 module:
149
149
 
150
150
  ```bash
151
151
  module load python/3.8.10
@@ -186,7 +186,7 @@ for i in range(torch.cuda.device_count()):
186
186
 
187
187
  ### 作业一直 `PD (Priority)` 不动
188
188
 
189
- 排队等资源,正常现象。看预计启动时间:
189
+ 该状态表示等待调度资源。查询预计启动时间:
190
190
 
191
191
  ```bash
192
192
  squeue -j <ID> --start
@@ -197,15 +197,14 @@ sinfo -p <分区> -o "%n %t" # 有几台 idle
197
197
 
198
198
  ## 调试策略
199
199
 
200
- **验证要便宜。** 大模型加载动辄半小时,用大作业试错代价太高。分层验证:
200
+ 按成本递增的顺序执行验证,避免使用完整模型诊断基础环境问题:
201
201
 
202
202
  1. **纯逻辑**(不需要 GPU/torch)→ 本地 Python 直接跑
203
203
  2. **需要 torch/DCU 但数据量小** → `srun` 交互式,约 5 秒拿到节点
204
204
  3. **小规模真实数据** → 2 分钟的 `sbatch` 探针作业
205
205
  4. **完整模型** → 最后才做
206
206
 
207
- 真实教训:DeepSeek V4 的反量化实现,先写 16 项单元测试(2 分钟作业)验证数值正确,
208
- 再跑完整模型。如果跳过第 3 步直接跑,每轮试错 30 分钟。
207
+ 例如,反量化实现应先通过小规模数值测试,再运行完整模型。
209
208
 
210
209
  **探针作业模板**:只读 metadata 不加载权重,几秒就出结果:
211
210
 
@@ -222,11 +221,11 @@ with safe_open(path, framework="pt", device="cpu") as f:
222
221
  # 作业跑在哪个节点
223
222
  squeue -j <ID> -o "%N"
224
223
 
225
- # 登到那个节点看进程(作业运行期间可以)
224
+ # 在作业运行期间检查目标节点进程
226
225
  ssh <节点名> 'top -b -n1 -u $USER | head -20'
227
226
 
228
227
  # GPU 占用
229
228
  srun --jobid=<ID> --overlap rocm-smi
230
229
  ```
231
230
 
232
- `--overlap` 让新的 srun 步骤共享已有作业的资源分配,不用重新排队。
231
+ `--overlap` 让新的 srun 步骤共享已有作业的资源分配,避免为诊断步骤重新申请一份资源。
@@ -137,9 +137,9 @@ cat > "$OUT" <<EOF
137
137
  #!/bin/bash -l
138
138
  # 目标集群: ${CLUSTER_ID} (${CLUSTER_DESC:-$SSH_HOST})
139
139
  #
140
- # 注意 shebang 是 "bash -l"(login shell)。有些集群的 module 函数只在 login
141
- # shell 里定义,用普通 "#!/bin/bash" 会让 module load 静默失败 —— 作业照样
142
- # 返回 0,但 ROCM_PATH 不设置、rocminfo/rocm-smi 无输出。实测于昆山集群。
140
+ # 使用 "bash -l",因为部分集群仅在 login
141
+ # shell 中定义 module 函数。普通 "#!/bin/bash" 可能使 module load 静默失败,作业仍
142
+ # 返回 0,但 ROCM_PATH 未设置且能力工具无输出。该行为已在昆山集群观测。
143
143
  #SBATCH --job-name=${NAME}
144
144
  #SBATCH --partition=${EFFECTIVE_PARTITION}
145
145
  ${GRES_LINE}
@@ -178,7 +178,7 @@ PYEOF
178
178
  rc=\$?
179
179
  echo "### python exit=\$rc"
180
180
  date +"%Y-%m-%d %H:%M:%S"
181
- # 必须传播退出码,否则 python 崩了 sacct 仍显示 COMPLETED(假成功)
181
+ # 传播工作负载退出码,避免调度器状态掩盖 Python 失败
182
182
  exit \$rc
183
183
  EOF
184
184
 
@@ -196,4 +196,4 @@ echo "上传并提交:"
196
196
  echo " scp $OUT ${CLUSTER_ID}:${HOME_DIR}/scripts/"
197
197
  echo " ssh ${CLUSTER_ID} 'mkdir -p ${HOME_DIR}/scripts/logs && sbatch --test-only ${HOME_DIR}/scripts/$OUT'"
198
198
  echo
199
- echo "注意:logs 目录必须先存在,否则作业会以 exit 53 失败且不产生任何日志。"
199
+ echo "要求:logs 目录必须先存在;否则作业会以 exit 53 失败且不产生日志。"
@@ -208,7 +208,7 @@ if [ "$COMPUTE" = yes ] && [ -n "$COMPUTE_OUT" ]; then
208
208
  IMPORT_ERR:*) KNOWN_LIMITS_NEW="${KNOWN_LIMITS_NEW:+${KNOWN_LIMITS_NEW};}bitsandbytes 导入失败(${BNB})" ;;
209
209
  esac
210
210
 
211
- # 保留 profile 里已有的人工经验,动态结果放前面。
211
+ # 保留 profile 中已有的人工验证结论,并将动态结果置于前面。
212
212
  if [ -n "${KNOWN_LIMITATIONS:-}" ]; then
213
213
  OLD_IFS="$IFS"
214
214
  IFS=';'