LabHub

HPC 와 Slurm · 작업 제출과 자원 요청 · 이론

sbatch 스크립트 쓰는 법

LabHub 에서 이어서 보기

한 줄 요약

sbatch 스크립트의 #SBATCH 줄은 주석처럼 보이지만 자원 계약서다. 그리고 첫 실행 명령 앞에 있어야만 읽힌다.

왜 이게 필요했나

가장 흔한 초보 실수가 이것이다.

#!/bin/bashecho "starting"#SBATCH --gres=gpu:2      # <- 무시된다!python train.py

#SBATCH 는 첫 번째 실행 가능한 명령이 나오기 전까지만 파싱된다. 그 뒤의 것은 평범한 주석이다. 에러도 경고도 나지 않는다. 작업은 GPU 없이 제출되고, 사용자는 왜 CUDA 가 안 보이는지 한참 헤맨다.

어떻게 동작하나

기본 골격

#!/bin/bash#SBATCH --job-name=resnet-train#SBATCH --output=/home/me/logs/%x-%j.out#SBATCH --error=/home/me/logs/%x-%j.err#SBATCH --partition=gpu#SBATCH --nodes=1#SBATCH --ntasks=1#SBATCH --cpus-per-task=8#SBATCH --mem=64G#SBATCH --gres=gpu:a100:2#SBATCH --time=04:00:00set -euo pipefailecho "job $SLURM_JOB_ID on $SLURMD_NODENAME"srun python train.py --epochs 50

출력 파일 패턴의 치환자를 알아 두면 좋다.

| 패턴 | 값 |
| --- | --- |
| %j | 작업 ID |
| %x | 작업 이름 |
| %A | 배열 작업의 부모 ID |
| %a | 배열 인덱스 |
| %N | 첫 노드 이름 |

출력 경로의 디렉터리가 미리 존재해야 한다. 없으면 작업이 시작하자마자 실패하고, 그 실패 이유를 담을 파일도 못 만들어 원인을 알기 어렵다.

유용한 환경변수

작업 안에서 Slurm 이 넣어 주는 값들.

SLURM_JOB_ID          작업 IDSLURM_JOB_NAME        작업 이름SLURM_JOB_NODELIST    할당된 노드 목록SLURMD_NODENAME       현재 실행 중인 노드SLURM_CPUS_PER_TASK   태스크당 CPU  <- DataLoader num_workers 에 쓰면 좋다SLURM_ARRAY_TASK_ID   배열 인덱스SLURM_NTASKS          태스크 총 개수

num_workers=int(os.environ.get("SLURM_CPUS_PER_TASK", 4)) 처럼 쓰면 자원 요청과 코드가 자동으로 맞는다.

srun 의 역할

sbatch 스크립트 안에서 srun 을 쓰면 작업 스텝이 만들어진다. 여러 노드/태스크로 병렬 실행할 때 필요하고, 단일 프로세스라면 없어도 되지만 있으면 자원 회계가 정확해진다.

srun --ntasks=4 python ddp_train.py     # 4개 프로세스로

배열 작업

같은 스크립트를 파라미터만 바꿔 여러 번 돌릴 때 쓴다.

#SBATCH --array=1-100%10

1-100 은 인덱스 범위, %10동시에 실행할 최대 개수다. 이 제한이 없으면 100개가 한꺼번에 큐에 들어가 다른 사용자를 막는다.

python sweep.py --config "configs/exp${SLURM_ARRAY_TASK_ID}.yaml"

의존성

JOB1=$(sbatch --parsable prep.sh)sbatch --dependency=afterok:$JOB1 train.sh

| 조건 | 의미 |
| --- | --- |
| afterok:ID | 그 작업이 성공으로 끝난 뒤 |
| afterany:ID | 성공/실패 무관하게 끝난 뒤 |
| afternotok:ID | 실패로 끝난 뒤 (정리 작업용) |
| singleton | 같은 이름의 내 작업이 없을 때 |

--parsable 은 작업 ID 만 출력해 변수에 담기 좋게 한다.

상태 확인

squeue -u $USERsqueue -j 12345 -o '%.10i %.20j %.8T %.10M %.6D %R'scontrol show job 12345sacct -j 12345 --format=JobID,JobName,State,Elapsed,MaxRSS,ReqTRESscancel 12345

squeue 의 마지막 열(%R)이 대기 이유다. Resources(자원 대기), Priority(우선순위 대기), Dependency(의존 대기), QOSMaxJobsPerUserLimit(제한 걸림) 등이 나온다. 작업이 안 도는 이유의 절반이 이 한 열에 적혀 있다.

현장에서 만나는 모습

--mem 을 안 적어 기본값으로 도는 경우. 클러스터 기본값이 작으면 OOM 으로 죽고, 크면 다른 작업이 못 들어온다. 명시하는 습관이 좋다.

--time 을 최대로 적는 문화. 모두가 그러면 백필이 무력해지고 전체 처리량이 떨어진다. 실제에 가깝게 적고 여유를 20% 정도 두는 것이 서로에게 이득이다.

다음 실습에서 할 것

sbatch 스크립트를 요구사항대로 작성하고, 배열 작업과 의존성 체인까지 구성한다. 마지막에는 #SBATCH 위치 오류를 잡아내는 검증 스크립트를 직접 만든다.