dsh-scnet 0.3.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.
- package/LICENSE +1 -1
- package/README.md +132 -14
- package/README_CN.md +107 -0
- package/cordis.patch.yml +8 -0
- package/docs/installation.md +60 -0
- package/docs/installation.zh-CN.md +73 -0
- package/docs/testing.md +63 -0
- package/docs/testing.zh-CN.md +62 -0
- package/index.mjs +15 -7
- package/package.json +15 -9
- package/skills/scnet-hpc/SKILL.md +87 -247
- package/skills/scnet-hpc/clusters/_template.conf +1 -0
- package/skills/scnet-hpc/clusters/zzeshell.conf +1 -1
- package/skills/scnet-hpc/references/adding-cluster.md +13 -16
- package/skills/scnet-hpc/references/environment.md +15 -15
- package/skills/scnet-hpc/references/quickstart-en.md +127 -0
- package/skills/scnet-hpc/references/setup.md +9 -11
- package/skills/scnet-hpc/references/software-compatibility.md +33 -4
- package/skills/scnet-hpc/references/troubleshooting.md +15 -16
- package/skills/scnet-hpc/scripts/_common.sh +9 -1
- package/skills/scnet-hpc/scripts/new-job.sh +47 -11
- package/skills/scnet-hpc/scripts/refresh-cluster.sh +1 -1
- package/skills/scnet-hpc/scripts/run-compute-probe.sh +17 -5
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# SCNet HPC English Quick Start
|
|
2
|
+
|
|
3
|
+
This guide covers the common workflow for SCNet clusters. Current repository profiles focus
|
|
4
|
+
mainly on Hygon DCU/DTK systems. Always read the target profile before using a partition,
|
|
5
|
+
memory value, accelerator type, module, or home-directory path.
|
|
6
|
+
|
|
7
|
+
The repository scripts support Linux and macOS natively. On Windows, use WSL2; native Windows
|
|
8
|
+
execution and Git Bash are not fully validated. This is separate from the official SCNet desktop
|
|
9
|
+
client, which supports Windows 10+ and macOS 12 Monterey+.
|
|
10
|
+
|
|
11
|
+
## 1. Inspect the available profiles
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ls clusters/*.conf
|
|
15
|
+
sed -n '1,220p' clusters/<cluster>.conf
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Check at least `PARTITION`, `PARTITION_CPU`, `GRES_TYPE`, `MIN_GRES`,
|
|
19
|
+
`DEF_MEM_PER_CPU`, `MODULE_LOADS`, `COMPUTE_NODE_OFFLINE`, and
|
|
20
|
+
`KNOWN_LIMITATIONS`.
|
|
21
|
+
|
|
22
|
+
## 2. Install the skill
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/lql341/scnet-hpc.git
|
|
26
|
+
cd scnet-hpc
|
|
27
|
+
./scripts/install.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The repository is designed to be shared by Codex, Claude Code, and OpenCode. Installation
|
|
31
|
+
paths depend on the local agent layout; `install.sh --link` is useful when developing the
|
|
32
|
+
skill from a shared source directory.
|
|
33
|
+
|
|
34
|
+
## 3. Configure SSH
|
|
35
|
+
|
|
36
|
+
Download the private key from the SCNet console, then run:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
./scripts/setup-ssh.sh --cluster <cluster> <private-key-file> <username>
|
|
40
|
+
ssh <cluster>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The script installs the key under `~/.ssh`, adds an SSH config entry, and tests the
|
|
44
|
+
connection. Do not commit private keys, usernames, internal node names, or personal paths.
|
|
45
|
+
|
|
46
|
+
## 4. Generate a Slurm job
|
|
47
|
+
|
|
48
|
+
Accelerator job:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
./scripts/new-job.sh --cluster <cluster> myjob 1 8 00:20:00
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
CPU-only job, when the profile defines `PARTITION_CPU`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
./scripts/new-job.sh --cluster <cluster> --cpu-only build 0 32 01:00:00
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Explicit partition override:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
./scripts/new-job.sh --cluster <cluster> --partition <partition> probe 1 8 00:10:00
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The generator calculates a safe memory request from the profile, adds GRES only when
|
|
67
|
+
needed, configures a shared temporary directory, enables offline mode when appropriate,
|
|
68
|
+
and propagates the program exit code.
|
|
69
|
+
|
|
70
|
+
Create the remote log directory before submission:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ssh <cluster> 'mkdir -p ~/scripts/logs'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Upload the generated script and validate the request before queueing it:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
scp myjob.slurm <cluster>:~/scripts/
|
|
80
|
+
ssh <cluster> 'sbatch --test-only ~/scripts/myjob.slurm'
|
|
81
|
+
ssh <cluster> 'sbatch ~/scripts/myjob.slurm'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 5. Monitor and debug
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
squeue -u "$USER"
|
|
88
|
+
squeue -j <job-id> --start
|
|
89
|
+
sacct -j <job-id> --format=JobID,State%14,ExitCode,Elapsed,MaxRSS -P
|
|
90
|
+
scancel <job-id>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Do not trust `COMPLETED` alone. Read both stdout and stderr, and make sure the job script
|
|
94
|
+
ends with the real program exit code.
|
|
95
|
+
|
|
96
|
+
For short experiments, request an interactive allocation with `srun`. Use the partition,
|
|
97
|
+
GRES type, CPU count, and memory limit from the target profile.
|
|
98
|
+
|
|
99
|
+
## 6. SCNet environment rules
|
|
100
|
+
|
|
101
|
+
- Login nodes are for source management, dependency preparation, file operations, and
|
|
102
|
+
scheduler commands. Whether package indexes and model sites are reachable is cluster-specific.
|
|
103
|
+
- Compute nodes are often offline. Download dependencies, models, and kernels before the job.
|
|
104
|
+
- A DCU partition may require at least one accelerator even for a CPU-oriented command.
|
|
105
|
+
- Memory limits may be tied to `cpus-per-task × DefMemPerCPU`.
|
|
106
|
+
- Do not use system `/tmp` for files that must be shared across login and compute nodes.
|
|
107
|
+
- Loading a module on a login node does not prove that the runtime works on a compute node.
|
|
108
|
+
- Hygon DCU software capabilities depend on the exact DTK, driver, framework, and `gfx` target.
|
|
109
|
+
|
|
110
|
+
## 7. Refresh and probe a cluster
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
./scripts/refresh-cluster.sh --cluster <cluster> --dry-run
|
|
114
|
+
./scripts/refresh-cluster.sh --cluster <cluster>
|
|
115
|
+
./scripts/refresh-cluster.sh --cluster <cluster> --compute
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The default refresh performs read-only login-node checks. `--compute` submits a small Slurm
|
|
119
|
+
job to test the accelerator runtime and therefore consumes cluster resources.
|
|
120
|
+
|
|
121
|
+
For detailed diagnostics, see the Chinese references:
|
|
122
|
+
|
|
123
|
+
- `references/setup.md`
|
|
124
|
+
- `references/environment.md`
|
|
125
|
+
- `references/troubleshooting.md`
|
|
126
|
+
- `references/software-compatibility.md`
|
|
127
|
+
- `references/hygon-dcu-development.md`
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
集群的主机名、端口等参数来自 `clusters/<集群短名>.conf`。
|
|
4
4
|
本文用 `<集群>`、`<主机名>`、`<端口>` 表示从 profile 读出的值。
|
|
5
5
|
|
|
6
|
-
##
|
|
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
|
|
48
|
+
变成失效 socket,可能留下需要清理的失效 socket。10 分钟覆盖一次交互操作的节奏,又能自然回收。
|
|
49
49
|
实测复用后单条命令从约 2 秒降到 0.57 秒。
|
|
50
50
|
|
|
51
51
|
**`ServerAliveInterval 60`**:应用层心跳,防止空闲 SSH 会话被中间网关静默切断。
|
|
52
|
-
|
|
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
|
-
|
|
|
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 中的连接参数。
|
|
@@ -8,9 +8,38 @@
|
|
|
8
8
|
4. **依赖路径**:区分 pip/conda 解析失败、运行时动态库失败、框架 kernel 不支持和模型/数据下载失败。
|
|
9
9
|
5. **端到端结果**:记录成功条件、性能、显存/内存、失败日志和未验证范围。
|
|
10
10
|
|
|
11
|
+
### 编译型软件的分层验证
|
|
12
|
+
|
|
13
|
+
- **把编译放到计算节点**:C++/HIP 大型构建的峰值内存可能远高于登录节点限额。
|
|
14
|
+
编译器进程被 OOM kill 时,先换到有明确内存配额的计算作业,先排除资源限制,再判断源码问题。
|
|
15
|
+
- **只生成目标架构**:显式设置目标 `gfx` 架构。默认同时生成多个架构会成倍增加
|
|
16
|
+
编译时间、产物体积和峰值内存。
|
|
17
|
+
- **升级工具链后重跑最小构建**:DTK/编译器升级可能改变 wrapper 头、host/device
|
|
18
|
+
编译模式或默认链接路径。保存 verbose compile command,与上一版本逐项比较。
|
|
19
|
+
- **区分节点环境**:登录/CPU 节点可能加载得到 module,却缺少只在加速器节点完整
|
|
20
|
+
可见的 HSA/HIP 库或符号链接。以目标计算节点解析到的真实库文件为准,必要时通过
|
|
21
|
+
CMake cache 变量显式传入,不创建全局假链接。
|
|
22
|
+
- **先串行能力、后并行能力**:先完成无 MPI 的单卡最小构建和功能验证,再开启 MPI,
|
|
23
|
+
最后测试 GPU-aware 通信与多卡扩展,以隔离编译器、运行库和通信栈问题。
|
|
24
|
+
|
|
25
|
+
### GPU-aware MPI 的验证边界
|
|
26
|
+
|
|
27
|
+
系统 MPI 能启动多进程,不代表它带加速器感知能力。先记录 MPI 构建参数,并做
|
|
28
|
+
GPU-aware on/off 对照。单节点验证可先固定共享内存与 self 传输,减少 UCX/IB
|
|
29
|
+
站点配置带来的变量;这只能证明单节点路径,不能外推到跨节点通信。
|
|
30
|
+
|
|
31
|
+
多卡扩展通常同时依赖足够大的问题规模、较高的计算/通信比以及可用的 GPU-aware
|
|
32
|
+
路径。小问题或低计算密度任务扩展不佳,不足以单独证明硬件或 MPI 配置错误。
|
|
33
|
+
|
|
34
|
+
### 数值与性能验收
|
|
35
|
+
|
|
36
|
+
加速器移植至少应同时报告:CPU/参考实现的关键数值偏差、守恒量或长期稳定性、
|
|
37
|
+
单卡问题规模扫描、固定规模的 1/2/单节点全卡强扩展、GPU-aware on/off 对照、
|
|
38
|
+
峰值内存/显存,以及每项测试的退出码和完整日志。性能通过不能替代正确性验证。
|
|
39
|
+
|
|
11
40
|
### 已验证的典型边界
|
|
12
41
|
|
|
13
|
-
- **gfx936 / BW1000**:Triton、硬件 FP8 `torch._scaled_mm`、部分 bitsandbytes INT8 路径可能不可用;纯 PyTorch
|
|
42
|
+
- **gfx936 / BW1000**:Triton、硬件 FP8 `torch._scaled_mm`、部分 bitsandbytes INT8 路径可能不可用;纯 PyTorch 软件反量化可作为兼容路径,但需要单独做性能和精度验证。
|
|
14
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 需要随源码适配。
|
|
15
44
|
- **GROMACS HIP**:先验证 CMake 最低版本、DTK 的 `lib`/`lib64` CMake 路径、目标架构、FFTW 预置和 SIMD;CUDA 兼容层与原生 HIP 的性能不可直接互相推断。
|
|
16
45
|
|
|
@@ -26,18 +55,18 @@ echo "test_exit_code=$rc"
|
|
|
26
55
|
exit "$rc"
|
|
27
56
|
```
|
|
28
57
|
|
|
29
|
-
|
|
58
|
+
不能只依据 `sacct` 的 `COMPLETED` 判定成功。脚本必须显式传递最后一个测试命令的退出码,并同时读取 `.out/.err`。
|
|
30
59
|
|
|
31
60
|
### 公开报告模板
|
|
32
61
|
|
|
33
|
-
标题采用“项目 + 加速器/平台 +
|
|
62
|
+
标题采用“项目 + 加速器/平台 + 编译与性能/兼容性测试报告”。正文可按以下顺序:
|
|
34
63
|
|
|
35
64
|
1. 环境信息
|
|
36
65
|
2. 编译过程与主要难题
|
|
37
66
|
3. 最终方案与验证结果
|
|
38
67
|
4. 测试数据与资源占用
|
|
39
68
|
5. 已知限制与注意事项
|
|
40
|
-
6.
|
|
69
|
+
6. 适用范围与可复用结论
|
|
41
70
|
7. 附录:快速复现命令
|
|
42
71
|
|
|
43
72
|
发布前扫描:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 排查作业失败
|
|
2
2
|
|
|
3
|
-
##
|
|
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
|
-
|
|
13
|
+
该记录不能证明 Python 工作负载成功。Python 可能已在第 3 分钟抛出 `ValueError`,而日志末尾仍打印脚本中
|
|
14
14
|
写的 `===== COMPLETE =====`。
|
|
15
15
|
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
132
|
+
该现象可能返回退出码 0,因此还需检查模块环境变量和探针输出。该行为已在昆山集群观测。
|
|
133
133
|
|
|
134
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 步骤共享已有作业的资源分配,避免为诊断步骤重新申请一份资源。
|
|
@@ -98,9 +98,17 @@ parse_cluster_arg() {
|
|
|
98
98
|
REST=()
|
|
99
99
|
while [ $# -gt 0 ]; do
|
|
100
100
|
case "$1" in
|
|
101
|
-
--cluster)
|
|
101
|
+
--cluster)
|
|
102
|
+
[ $# -ge 2 ] || die "--cluster 缺少参数"
|
|
103
|
+
CLUSTER="$2"
|
|
104
|
+
shift 2
|
|
105
|
+
;;
|
|
102
106
|
--cluster=*) CLUSTER="${1#*=}"; shift ;;
|
|
103
107
|
*) REST+=("$1"); shift ;;
|
|
104
108
|
esac
|
|
105
109
|
done
|
|
110
|
+
if [ -n "$CLUSTER" ]; then
|
|
111
|
+
[[ "$CLUSTER" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] \
|
|
112
|
+
|| die "集群短名包含不安全字符"
|
|
113
|
+
fi
|
|
106
114
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# 生成一个符合目标集群所有约束的作业脚本骨架。
|
|
3
3
|
#
|
|
4
|
-
# ./new-job.sh [--cluster <集群短名>]
|
|
4
|
+
# ./new-job.sh [--cluster <集群短名>] [--cpu-only] [--partition <分区>] \
|
|
5
|
+
# <作业名> [加速器数] [cpu数] [时长]
|
|
5
6
|
#
|
|
6
7
|
# 内存按 cpus × DEF_MEM_PER_CPU 自动取安全值,避免手算出错。
|
|
7
8
|
|
|
@@ -16,11 +17,16 @@ set -- "${REST[@]+${REST[@]}}"
|
|
|
16
17
|
REMOTE_USER=""
|
|
17
18
|
REFRESH=no
|
|
18
19
|
USE_AUTO=yes
|
|
20
|
+
CPU_ONLY=no
|
|
21
|
+
PARTITION_OVERRIDE=""
|
|
19
22
|
ARGS=()
|
|
20
23
|
while [ $# -gt 0 ]; do
|
|
21
24
|
case "$1" in
|
|
22
|
-
--user) REMOTE_USER="$
|
|
25
|
+
--user) [ $# -ge 2 ] || die "--user 缺少参数"; REMOTE_USER="$2"; shift 2 ;;
|
|
23
26
|
--user=*) REMOTE_USER="${1#*=}"; shift ;;
|
|
27
|
+
--partition) [ $# -ge 2 ] || die "--partition 缺少参数"; PARTITION_OVERRIDE="$2"; shift 2 ;;
|
|
28
|
+
--partition=*) PARTITION_OVERRIDE="${1#*=}"; shift ;;
|
|
29
|
+
--cpu-only) CPU_ONLY=yes; shift ;;
|
|
24
30
|
--refresh) REFRESH=yes; shift ;;
|
|
25
31
|
--no-auto) USE_AUTO=no; shift ;;
|
|
26
32
|
*) ARGS+=("$1"); shift ;;
|
|
@@ -35,17 +41,32 @@ TIME="${4:-00:20:00}"
|
|
|
35
41
|
|
|
36
42
|
if [ -z "$NAME" ]; then
|
|
37
43
|
cat >&2 <<EOF
|
|
38
|
-
用法: $0 [--cluster <集群短名>] [--user <远端用户名>] [--
|
|
44
|
+
用法: $0 [--cluster <集群短名>] [--user <远端用户名>] [--cpu-only]
|
|
45
|
+
[--partition <分区>] [--refresh|--no-auto] <作业名> [加速器数] [cpu数] [时长]
|
|
39
46
|
|
|
40
47
|
例子:
|
|
41
48
|
$0 probe # 1 卡, 8 核, 20 分钟(探针)
|
|
42
49
|
$0 infer 8 32 01:30:00 # 8 卡, 32 核, 1.5 小时(大模型)
|
|
50
|
+
$0 --cpu-only build 0 32 01:00:00 # 使用 profile 的 CPU 分区,不申请加速器
|
|
43
51
|
|
|
44
52
|
可用集群: $(list_clusters | tr '\n' ' ')
|
|
45
53
|
EOF
|
|
46
54
|
exit 1
|
|
47
55
|
fi
|
|
48
56
|
|
|
57
|
+
[[ "$NAME" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ ]] \
|
|
58
|
+
|| die "作业名只允许 1-64 个字母、数字、点、下划线或连字符,且必须以字母或数字开头"
|
|
59
|
+
[[ "$ACCEL" =~ ^[0-9]+$ ]] || die "加速器数必须是非负整数"
|
|
60
|
+
[[ "$CPUS" =~ ^[1-9][0-9]*$ ]] || die "CPU 数必须是正整数"
|
|
61
|
+
[[ "$TIME" =~ ^([0-9]+-)?[0-9]{1,2}:[0-9]{2}:[0-9]{2}$ ]] \
|
|
62
|
+
|| die "时长格式应为 HH:MM:SS 或 D-HH:MM:SS"
|
|
63
|
+
if [ -n "$REMOTE_USER" ]; then
|
|
64
|
+
[[ "$REMOTE_USER" =~ ^[A-Za-z0-9._-]+$ ]] || die "远端用户名包含不安全字符"
|
|
65
|
+
fi
|
|
66
|
+
if [ -n "$PARTITION_OVERRIDE" ]; then
|
|
67
|
+
[[ "$PARTITION_OVERRIDE" =~ ^[A-Za-z0-9._-]+$ ]] || die "分区名包含不安全字符"
|
|
68
|
+
fi
|
|
69
|
+
|
|
49
70
|
if [ "$REFRESH" = yes ]; then
|
|
50
71
|
"$REPO_ROOT/scripts/refresh-cluster.sh" --cluster "${CLUSTER:-}"
|
|
51
72
|
fi
|
|
@@ -56,6 +77,17 @@ load_cluster "$CLUSTER"
|
|
|
56
77
|
[ "${SCHEDULER:-slurm}" = "slurm" ] \
|
|
57
78
|
|| die "暂只支持 slurm,${CLUSTER_ID} 用的是 ${SCHEDULER}"
|
|
58
79
|
|
|
80
|
+
if [ "$CPU_ONLY" = yes ]; then
|
|
81
|
+
[ -n "${PARTITION_CPU:-}" ] \
|
|
82
|
+
|| die "${CLUSTER_ID} profile 未定义 PARTITION_CPU,不能使用 --cpu-only"
|
|
83
|
+
EFFECTIVE_PARTITION="${PARTITION_OVERRIDE:-$PARTITION_CPU}"
|
|
84
|
+
ACCEL=0
|
|
85
|
+
[ -n "${DEF_MEM_PER_CPU_CPU:-}" ] && DEF_MEM_PER_CPU="$DEF_MEM_PER_CPU_CPU"
|
|
86
|
+
else
|
|
87
|
+
EFFECTIVE_PARTITION="${PARTITION_OVERRIDE:-${PARTITION:-}}"
|
|
88
|
+
fi
|
|
89
|
+
[ -n "$EFFECTIVE_PARTITION" ] || die "目标分区为空,请补 profile 或使用 --partition"
|
|
90
|
+
|
|
59
91
|
# 内存上限 = cpus × DEF_MEM_PER_CPU,留 1GB 余量避免边界抖动
|
|
60
92
|
if [ -n "${DEF_MEM_PER_CPU:-}" ]; then
|
|
61
93
|
MEM_MB=$(( CPUS * DEF_MEM_PER_CPU ))
|
|
@@ -70,15 +102,19 @@ fi
|
|
|
70
102
|
|
|
71
103
|
# QOS 强制申请加速器时必须写 --gres
|
|
72
104
|
GRES_LINE=""
|
|
73
|
-
if [ -n "${GRES_TYPE:-}" ]; then
|
|
105
|
+
if [ "$CPU_ONLY" != yes ] && [ -n "${GRES_TYPE:-}" ] && [ "$ACCEL" -gt 0 ]; then
|
|
74
106
|
GRES_LINE="#SBATCH --gres=${GRES_TYPE}:${ACCEL}"
|
|
75
107
|
[ -n "${MIN_GRES:-}" ] && GRES_LINE="$GRES_LINE # 必须:QOS 要求最少 ${MIN_GRES}"
|
|
76
108
|
fi
|
|
109
|
+
if [ "$CPU_ONLY" != yes ] && [ -n "${MIN_GRES:-}" ] && [ "$ACCEL" -eq 0 ]; then
|
|
110
|
+
die "默认/指定分区要求至少 ${MIN_GRES};请申请加速器或使用 --cpu-only"
|
|
111
|
+
fi
|
|
77
112
|
|
|
78
113
|
# 远端用户名。#SBATCH 是注释行,Slurm 不做变量展开 —— 日志路径里写 $USER
|
|
79
114
|
# 会被当成字面量目录名,作业以 exit 53 失败且不产生日志。所以这里必须展开成
|
|
80
115
|
# 真实用户名。默认取本地用户名,不同时用 --user 覆盖。
|
|
81
116
|
REMOTE_USER="${REMOTE_USER:-${REMOTE_USER_DETECTED:-$(whoami)}}"
|
|
117
|
+
[[ "$REMOTE_USER" =~ ^[A-Za-z0-9._-]+$ ]] || die "探测到的远端用户名包含不安全字符,请用 --user 显式指定"
|
|
82
118
|
HOME_DIR="${HOME_BASE}/${REMOTE_USER}"
|
|
83
119
|
|
|
84
120
|
# 脚本体(非 #SBATCH 行)里可以正常用 $USER
|
|
@@ -101,11 +137,11 @@ cat > "$OUT" <<EOF
|
|
|
101
137
|
#!/bin/bash -l
|
|
102
138
|
# 目标集群: ${CLUSTER_ID} (${CLUSTER_DESC:-$SSH_HOST})
|
|
103
139
|
#
|
|
104
|
-
#
|
|
105
|
-
# shell
|
|
106
|
-
# 返回 0,但 ROCM_PATH
|
|
140
|
+
# 使用 "bash -l",因为部分集群仅在 login
|
|
141
|
+
# shell 中定义 module 函数。普通 "#!/bin/bash" 可能使 module load 静默失败,作业仍
|
|
142
|
+
# 返回 0,但 ROCM_PATH 未设置且能力工具无输出。该行为已在昆山集群观测。
|
|
107
143
|
#SBATCH --job-name=${NAME}
|
|
108
|
-
#SBATCH --partition=${
|
|
144
|
+
#SBATCH --partition=${EFFECTIVE_PARTITION}
|
|
109
145
|
${GRES_LINE}
|
|
110
146
|
#SBATCH --nodes=1
|
|
111
147
|
#SBATCH --ntasks-per-node=1
|
|
@@ -142,7 +178,7 @@ PYEOF
|
|
|
142
178
|
rc=\$?
|
|
143
179
|
echo "### python exit=\$rc"
|
|
144
180
|
date +"%Y-%m-%d %H:%M:%S"
|
|
145
|
-
#
|
|
181
|
+
# 传播工作负载退出码,避免调度器状态掩盖 Python 失败
|
|
146
182
|
exit \$rc
|
|
147
183
|
EOF
|
|
148
184
|
|
|
@@ -153,11 +189,11 @@ sed -i.bak '/^$/N;/^\n$/D' "$OUT" 2>/dev/null && rm -f "$OUT.bak"
|
|
|
153
189
|
|
|
154
190
|
echo "已生成 $OUT"
|
|
155
191
|
echo " 集群=${CLUSTER_ID} ${GRES_TYPE:-加速器}=${ACCEL} CPU=${CPUS} 内存=${MEM_NOTE} 时长=${TIME}"
|
|
156
|
-
echo " 分区=${
|
|
192
|
+
echo " 分区=${EFFECTIVE_PARTITION} 模式=$([ "$CPU_ONLY" = yes ] && echo CPU || echo accelerator) 节点数=${NODE_COUNT:-未探测}(来源:${NODE_COUNT_SOURCE:-profile/cache})"
|
|
157
193
|
echo " 日志目录=${HOME_DIR}/scripts/logs(用户名 ${REMOTE_USER},不对请加 --user)"
|
|
158
194
|
echo
|
|
159
195
|
echo "上传并提交:"
|
|
160
196
|
echo " scp $OUT ${CLUSTER_ID}:${HOME_DIR}/scripts/"
|
|
161
197
|
echo " ssh ${CLUSTER_ID} 'mkdir -p ${HOME_DIR}/scripts/logs && sbatch --test-only ${HOME_DIR}/scripts/$OUT'"
|
|
162
198
|
echo
|
|
163
|
-
echo "
|
|
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=';'
|
|
@@ -19,21 +19,32 @@ PYTHON_BIN=""
|
|
|
19
19
|
|
|
20
20
|
while [ $# -gt 0 ]; do
|
|
21
21
|
case "$1" in
|
|
22
|
-
--cpus) CPUS="$
|
|
22
|
+
--cpus) [ $# -ge 2 ] || die "--cpus 缺少参数"; CPUS="$2"; shift 2 ;;
|
|
23
23
|
--cpus=*) CPUS="${1#*=}"; shift ;;
|
|
24
|
-
--time) TIME="$
|
|
24
|
+
--time) [ $# -ge 2 ] || die "--time 缺少参数"; TIME="$2"; shift 2 ;;
|
|
25
25
|
--time=*) TIME="${1#*=}"; shift ;;
|
|
26
|
-
--accelerators) ACCEL="$
|
|
26
|
+
--accelerators) [ $# -ge 2 ] || die "--accelerators 缺少参数"; ACCEL="$2"; shift 2 ;;
|
|
27
27
|
--accelerators=*) ACCEL="${1#*=}"; shift ;;
|
|
28
|
-
--user) REMOTE_USER="$
|
|
28
|
+
--user) [ $# -ge 2 ] || die "--user 缺少参数"; REMOTE_USER="$2"; shift 2 ;;
|
|
29
29
|
--user=*) REMOTE_USER="${1#*=}"; shift ;;
|
|
30
|
-
--python) PYTHON_BIN="$
|
|
30
|
+
--python) [ $# -ge 2 ] || die "--python 缺少参数"; PYTHON_BIN="$2"; shift 2 ;;
|
|
31
31
|
--python=*) PYTHON_BIN="${1#*=}"; shift ;;
|
|
32
32
|
-h|--help) sed -n '2,10p' "$0" | sed 's/^# \?//'; exit 0 ;;
|
|
33
33
|
*) die "未知参数: $1" ;;
|
|
34
34
|
esac
|
|
35
35
|
done
|
|
36
36
|
|
|
37
|
+
[[ "$CPUS" =~ ^[1-9][0-9]*$ ]] || die "CPU 数必须是正整数"
|
|
38
|
+
[[ "$ACCEL" =~ ^[1-9][0-9]*$ ]] || die "加速器数必须是正整数"
|
|
39
|
+
[[ "$TIME" =~ ^([0-9]+-)?[0-9]{1,2}:[0-9]{2}:[0-9]{2}$ ]] \
|
|
40
|
+
|| die "时长格式应为 HH:MM:SS 或 D-HH:MM:SS"
|
|
41
|
+
if [ -n "$REMOTE_USER" ]; then
|
|
42
|
+
[[ "$REMOTE_USER" =~ ^[A-Za-z0-9._-]+$ ]] || die "远端用户名包含不安全字符"
|
|
43
|
+
fi
|
|
44
|
+
if [ -n "$PYTHON_BIN" ]; then
|
|
45
|
+
[[ "$PYTHON_BIN" =~ ^[A-Za-z0-9_./-]+$ ]] || die "Python 命令包含不安全字符"
|
|
46
|
+
fi
|
|
47
|
+
|
|
37
48
|
[ -n "${CLUSTER:-}" ] || die "请用 --cluster <集群短名> 指定集群。"
|
|
38
49
|
load_cluster "$CLUSTER"
|
|
39
50
|
|
|
@@ -41,6 +52,7 @@ load_cluster "$CLUSTER"
|
|
|
41
52
|
[ -n "${PARTITION:-}" ] || die "${CLUSTER_ID} 的 PARTITION 为空,无法提交计算节点探针。"
|
|
42
53
|
|
|
43
54
|
REMOTE_USER="${REMOTE_USER:-${REMOTE_USER_DETECTED:-$(whoami)}}"
|
|
55
|
+
[[ "$REMOTE_USER" =~ ^[A-Za-z0-9._-]+$ ]] || die "探测到的远端用户名包含不安全字符,请用 --user 显式指定"
|
|
44
56
|
HOME_DIR="${HOME_BASE}/${REMOTE_USER}"
|
|
45
57
|
PROBE_DIR="${HOME_DIR}/.scnet-hpc/probes"
|
|
46
58
|
PROBE_BASE="${PROBE_DIR}/compute-probe"
|