{"id":"IL-0428","org":"BigScience","date":"2022-03-04","docs":[],"title":{"en":"Test runs of 100B-200B models on 320 to 384 A100 GPUs hung once inter-node traffic grew, and each hang took nodes down","ko":"GPU 320~384개로 돌린 대형 모델 시험 학습이 멈추고 그때마다 노드가 내려갔다"},"domain":["ai-infra"],"impact":{"scope":"Test runs of 100B to 200B models on 320 to 384 A100 GPUs hung; each hanging run left nodes down until rebooted, with 13 of 52 nodes down at one point","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Python's trace module is very useful for debugging hanging processes because it logs the last call each process made before it stopped responding, but it should be started later, just before train_step, to avoid gigabytes of traces from the dataloader and setup code.","ko":"멈춘 프로세스가 어디서 멈췄는지 알려면 py-spy 로 모든 프로세스의 호출 스택을 뜨거나 파이썬 trace 모듈로 모든 호출을 기록할 수 있다. trace 를 켜면 속도는 느려졌지만 멈춤은 그대로 일어났다. 작성자는 trace 가 멈춘 프로세스를 디버깅하는 데 아주 쓸모 있었다고 봤다. 다만 처음부터 추적하면 데이터 로더와 준비 코드의 쓸모없는 기록까지 쌓이므로 `train_step` 바로 앞에서 추적을 시작하는 편이 나았다. 멈춘 작업을 살피는 두 번째 `srun` 에는 `--gres=gpu:0` 을 줘야 첫 `srun` 이 끝날 때까지 막히지 않는다. 먼저 `salloc` 으로 GPU 를 잡아 두면 SLURM 이 프로세스를 죽여도 그 노드에 들어갈 수 있다."},"related":[],"sources":[{"url":"https://github.com/bigscience-workshop/bigscience/blob/master/train/tr11-176B-ml/chronicles-prequel.md","kind":"github","archived":"https://web.archive.org/web/20260305044359/https://github.com/bigscience-workshop/bigscience/blob/master/train/tr11-176B-ml/chronicles-prequel.md"}],"summary":{"en":"Before starting the tr11 176B training, BigScience ran test runs of 100B to 200B models with Megatron-LM and DeepSpeed on 320 to 384 A100 GPUs of the Jean Zay cluster. Above a certain scale the runs hung: random GPUs stopped responding, the job waited until it timed out, and each attempt left several nodes down. By growing the model first in layers and then in hidden size, the engineer showed that the hang appeared when inter-node traffic passed a certain level, and noted that DeepSpeed ZeRO shards data over all GPUs, so more GPUs means more communication. The hang lived partly in DeepSpeed and partly in Megatron-LM, where some processes stayed in a broadcast inside train_step while the others had moved on, but the cause could be FusedAdam, PyTorch, NCCL or the system itself.\n\nDiagnosis was slow because every run of the hanging setup cost a few nodes, and with the engineer 10 hours behind Jean Zay nobody was there to reboot them. py-spy run through a second srun with --gres=gpu:0 could not reach several of the hung processes, so the engineer turned on Python's trace module in pretrain_gpt.py with a Tee helper that copies each process's output to its own file; this did not hide the hang and logged 14GB of Python calls from 320 processes.\n\nSetting CUDA_LAUNCH_BLOCKING=1 made the hang go away, and in performance checks it had surprisingly little effect on throughput at this scale, although it normally slows training by making CUDA operations synchronous. The engineer paused the investigation to test the final version of the code without risking more nodes, and the team kept CUDA_LAUNCH_BLOCKING=1 as the workaround.","ko":"BigScience 는 176B 모델 학습을 시작하기 전에 Jean Zay 의 A100 80GB 8-GPU 노드에서 100B~200B 모델로 시험 학습을 돌렸다. GPU 320~384개를 한 작업에 쓰자 학습이 멈췄다. 몇몇 GPU 가 무작위로 응답하지 않았고 시스템 전체가 타임아웃이 날 때까지 멈췄다. 멈출 때마다 노드 몇 대가 내려가 재부팅 전까지 돌아오지 않았다. 한때는 52개 노드 가운데 13개가 내려가 있었다.\n\n작성자는 모델을 층 방향과 hidden 방향으로 따로 키우며 경계를 찾았다. hidden 을 `1024*14` 로 두면 40층 100B 에서 멈췄고, 층을 80 으로 두면 `1024*12` 145B 에서 멈췄다. 두 실험 모두 노드 사이 트래픽이 어느 수준을 넘으면 시스템이 실패한다는 것을 보였고, `all_reduce` 나 `broadcast` 패킷 하나의 크기 문제는 아니었다. py-spy 로 보니 노드마다 프로세스 6개는 `train_step` 을 마치고 다음 `all_reduce` 로 넘어갔고 2개는 `broadcast` 에 남아 있었다. 원인 후보로 apex 의 `FusedAdam`, PyTorch, NCCL, 시스템 내부 문제를 들었지만 어느 것도 확정하지 못했다.\n\n`CUDA_LAUNCH_BLOCKING=1` 을 켜면 CUDA 연산이 동기로 돌면서 멈춤이 사라졌다. 이 규모에서는 성능 저하도 거의 없었다. 작성자는 파이썬 trace 모듈로 프로세스 320개의 호출을 14GB 분량으로 기록하며 원인을 더 찾았다. 그러다 최종 코드를 시험하는 일로 넘어가야 했고 노드를 더 잃을 수 없어 조사를 멈췄다. 팀은 당분간 `CUDA_LAUNCH_BLOCKING=1` 로 우회하기로 했다."},"trigger":{"en":"Growing the test model past about 100B parameters over 20 to 40 nodes, which raised inter-node communication past the level the system handled, with CUDA launches left asynchronous.","ko":"100B 이상 모델을 20~40개 노드에 걸쳐 돌려 노드 사이 NCCL 트래픽이 어느 수준을 넘으면 멈춤이 시작됐다."},"severity":"unknown","symptoms":["training-job-failed","nccl-timeout","gpu-unavailable","node-not-ready"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":null,"components":["nccl","pytorch"],"root_cause":"unknown","remediation":[{"text":{"en":"Set CUDA_LAUNCH_BLOCKING=1, which removed the hang with little effect on throughput at this scale","ko":"`CUDA_LAUNCH_BLOCKING=1` 을 설정하자 멈춤이 사라졌다. 성능을 여러 번 확인해 보니 이 규모에서는 속도 저하가 거의 없었고, 팀은 이 우회책을 당분간 쓰기로 했다."}}],"action_items":[],"contributing":["limited-debug-access"],"recurrence_of":null,"symptoms_text":{"en":"On Jean Zay, test runs of large models across 320 to 384 A100 GPUs hung: random GPUs stopped responding and the whole job hung until it timed out. Every run of the hanging setup left a few nodes down until someone rebooted them, and at one point 13 of 52 nodes were down.\n\nThe hang depended on scale. A 200B model worked on 10 nodes and a model under 100B worked on 40 nodes (TP=8, PP=10, DP=4), but 100B over 20 to 40 nodes hung, reliably on 40 nodes and intermittently on 20. Keeping the hidden size at 1024*14 and adding layers, 10 layers (25B) and 20 layers (50B) worked and 40 layers (100B) hung after iteration 1 succeeded. Keeping 80 layers and growing the hidden size, 1024*10 (100B) worked and 1024*12 (145B) hung. The engineer read this as the system failing once inter-node traffic passed a certain level, not as a problem with the size of each all_reduce or broadcast.\n\nOn nodes 0 and 1, each running only tensor parallelism, py-spy showed 6 processes in \"train (megatron/training.py:915)\" and 2 processes in \"broadcast (torch/distributed/distributed_c10d.py:1191)\" called from \"_aggregate_total_loss (deepspeed/runtime/pipe/engine.py:540)\". Six processes had finished train_step while two never did, so the processes had fallen out of sync. When py-spy was run on all processes, several did not respond at all, so it could not show where those were hanging.\n\nWith asynchronous CUDA launches (CUDA_LAUNCH_BLOCKING=0), a 200B run on 160 GPUs with GBS 2048 \"may hang\" and on 320 GPUs \"always hangs\", while with CUDA_LAUNCH_BLOCKING=1 the 320-GPU run worked at 87.78 TFLOPs. Suspects included apex's FusedAdam, which had caused a serious issue a week earlier, PyTorch, NCCL and an internal problem of the system.","ko":"A100 GPU 320~384개로 돌린 대형 모델 시험 학습이 멈췄다. 몇몇 GPU 가 무작위로 응답하지 않았고 시스템 전체가 타임아웃이 날 때까지 멈춰 있었다. 멈출 때마다 노드 몇 대가 내려갔다.\n\n멈춤은 규모에 따라 달랐다. 100B 미만 모델은 40개 노드에서 TP=8/PP=10/DP=4 로 돌았고, 200B 모델도 10개 노드에서는 돌았다. 100B 모델을 20~40개 노드에서 돌리면 멈췄다. hidden 을 고정하고 층을 늘리자 10층 25B 와 20층 50B 는 됐고 40층 100B 는 iteration 1 을 마친 뒤 멈췄다. 층을 80 으로 고정하고 hidden 을 늘리자 `1024*10` 100B 는 됐고 `1024*12` 145B 는 멈췄다. 40개 노드에서는 매번 실패했고 20개 노드에서는 가끔 실패했다.\n\n`CUDA_LAUNCH_BLOCKING=0` 인 비동기 실행으로 200B 모델의 두 번째 iteration 을 재면 GPU 160개에 GBS 2048 은 멈출 때가 있었고 GPU 320개에 GBS 2048 은 늘 멈췄다.\n\npy-spy 로 노드 0 과 1 의 파이썬 호출 스택을 떠 보니 노드마다 프로세스 6개는 `train (megatron/training.py:915)` 에 있었고, 2개는 `_aggregate_total_loss (deepspeed/runtime/pipe/engine.py:540)` 를 거쳐 `broadcast (torch/distributed/distributed_c10d.py:1191)` 에 있었다. 6개는 `train_step` 을 마치고 `done_cuda` 의 `all_reduce` 로 넘어가 있었다. 작성자는 나머지 2개가 `train_step` 을 끝내지 못한 채 이미 떠난 6개에 broadcast 하다 멈췄다고 추정했다. 나중에 모든 프로세스에 py-spy 를 돌렸을 때는 여러 프로세스가 응답하지 않아 어디서 멈췄는지 알 수 없었다.\n\n멈추는 설정을 돌릴 때마다 노드 몇 대를 잃었다. 한때는 52개 노드 가운데 13개가 내려가 진단을 이어 갈 수 없었다. 작성자가 있는 곳과 Jean Zay 사이에는 10시간 시차가 있어 노드를 재부팅해 줄 사람이 현지에 없었다. 대부분의 노드는 다음 날 아침에야 돌아왔다.\n\n작성자는 크래시 뒤 돌아오지 않은 노드에 내부 문제가 있다고 의심했지만, 같은 200B 모델을 10개 노드 묶음으로 시험했을 때는 문제가 없었다. 일주일 전에도 심각한 문제를 일으켰던 apex 의 `FusedAdam`, 그리고 PyTorch, NCCL, 시스템 내부 문제도 후보로 들었다. 패킷 하나의 크기 문제는 아니었다. hidden 을 그대로 두고 층만 4분의 1 로 줄이면 잘 돌았기 때문이다."},"updated_at":"2026-11-14T12:34:07.825740Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0428","org_slug":"bigscience"}