NVIDIA 의 CUPTI / NVTX / Nsight 가 채워주는 자리 위에, eBPF 기반의 third-party observability 가 어떻게 끼어들 수 있는가. Yusheng Zheng 의 bpftime · gpu_ext 라인을 따라 — kernel launch 부터 UVM page fault 까지 GPU 위에서 일어나는 일을 production-grade 로 들여다보는 새로운 stack 의 위치를 정리한 학습 노트. 강의 자체의 자막은 실패했고, 여기서는 발표자의 공개 repo · 블로그 · 관련 paper 를 근거로 같은 토픽을 시각적으로 재구성한다.
개발자의 desktop 에서 Nsight Compute 한 번 띄우면 보이는 정보 — kernel duration, occupancy, memory throughput — 를 production cluster 에서 실시간으로 streaming 으로, workload 를 멈추지 않고, 그리고 다른 사용자의 코드에 대해서도 보고 싶다. 이 욕구가 GPU observability 의 출발점이다.
강의가 던지는 두 개의 질문은 이렇다.
Yusheng 의 입장은 실용주의다. CUDA driver 의 internals 를 다 이해하지 않아도, 올바른 hook point 를 잡으면 production 에서 의미 있는 신호를 뽑을 수 있다. 그 hook point 가 어디인지, 그리고 어떤 hook 이 어떤 질문에 답하는지를 정리하는 것이 이 강의의 본론이다.
이 강의의 모든 도구는 같은 질문에 답한다 — “이 production GPU job 에서 방금 무슨 일이 벌어졌는가, 그리고 그게 왜 느렸거나 왜 OOM 됐는가?” Nsight 는 개발자 desktop 의 답이고, eBPF 기반 stack 은 같은 질문을 production 에서 streaming 으로 답하는 길이다.
그래서 이 강의의 끝에서 손에 잡혀 있어야 하는 건 4개 layer 의 observability stack(driver hook, CUPTI activity, NVTX range, application metric)과, 각 layer 가 어떤 질문에 답하는지의 매핑이다.
대부분의 production GPU 모니터링은 세 단계로 끝난다 — nvidia-smi, DCGM, 그리고 가끔 Nsight Systems. 이 셋이 각자 어디까지 보여주고 어디서부터 보이지 않는지를 정리하면 빈 자리가 자연스럽게 드러난다.
nvtx.annotate("attention") 한 줄. 가장 의미론적으로 풍부하지만, 손이 닿는 코드에서만 가능.
In-app
bpftime 의 핵심 영역.
eBPF
gpu_ext 가 NVIDIA Open GPU Kernel Modules 에 eBPF struct_ops hook 을 박아서 노출.
Kernel
nvidia-smi 와 DCGM 이 보여주는 것은 본질적으로 aggregate metric 이다 — GPU 전체의 SM utilization, memory utilization, power. 한 process 가 점유한 만큼 다른 process 가 비어 있는지, 어떤 kernel 이 SM 을 점유했는지는 알 수 없다. “GPU 가 80% 바쁘다” 는 사실로부터 “내 코드의 어디가 80% 를 만드는가” 까지의 거리가 production 에서 가장 흔한 빈 자리다.
“OOM 이 났는데 nvidia-smi 의 memory 그래프는 한가하다” — UVM oversubscription 이 일으키는 page eviction 때문. 이 케이스는 L3 (kernel UVM hook) 만이 직접 답할 수 있다. CUPTI/NVTX 만으로는 증상은 보이지만 원인까지 안 잡힌다.
또 하나의 한계 — multi-tenant 환경. cluster 안에서 다른 팀의 binary 가 도는 경우, 그 binary 에 NVTX 도 없고 CUPTI callback library 도 안 attach 돼 있다. 외부에서 그 process 를 들여다봐야 하는데, 이건 본질적으로 OS-level instrumentation 의 영역이다 — eBPF 가 CPU 쪽에서 풀던 문제와 같다.
eBPF 는 Linux 커널 안에서 안전하게 검증된 작은 프로그램을 hook point 마다 실행하게 해주는 frame. 그 추상을 GPU 로 옮기는 두 갈래가 있다 — 사용자공간 VM (bpftime) 과 driver 내부 struct_ops hook (gpu_ext).
kernel eBPF 와 달리 사용자공간 process 안에 VM 을 띄우고 uprobe / syscall / USDT 같은 hook 점에서 eBPF bytecode 를 실행한다. CUDA app 의 libcuda.so 의 함수 심볼에 attach 가 가능하다는 점이 핵심.
그리고 강의의 가장 흥미로운 contribution — eBPF → PTX 변환. eBPF bytecode 를 PTX 로 컴파일해서 GPU kernel 안에 inject 하면, 사용자가 짠 device function 안에서 정해진 hook point 에 도달했을 때 추가 로깅을 수행할 수 있다. CPU 쪽 uprobe 의 GPU 판.
“이미 도는 다른 process 의 GPU kernel 에 — 코드 수정 없이 — instrumentation 을 박는다.” 이게 production 에서 가장 큰 unlock. CUPTI 는 process 시작 전에 attach 해야 하고, NVTX 는 코드에 손이 닿아야 한다. eBPF 는 이미 떠 있는 binary 에 attach.
NVIDIA 의 Open GPU Kernel Modules 를 fork 해서 eBPF struct_ops hook 을 박는다. 무엇을 hook 하는가 — UVM 의 page fault handler, eviction policy, scheduler timeslice 결정. 이 자리들은 사용자공간에서 절대 보이지 않는 driver internal 결정점이다.
학습 차원에서 더 중요한 건 그 hook 점들을 tracing 으로 켜둘 수 있다는 사실이다 — repo 안의 chunk_trace, prefetch_trace, gpu_sched_trace 가 그 예시.
eBPF 가 강력하다고 해서 NVTX/CUPTI 를 대체하지 않는다. 강의의 메시지는 합치는 쪽이다 — 가장 풍부한 의미론은 application 이 알고, 가장 넓은 커버리지는 eBPF 가 준다. 둘을 같은 timeline 위에 정렬해야 production 의 “왜” 가 풀린다.
# 학습 step 마다 의미 있는 region 을 찍는 표준 패턴
import nvtx
import torch
@nvtx.annotate("train.step")
def step(batch):
with nvtx.annotate("forward"):
loss = model(batch)
with nvtx.annotate("backward"):
loss.backward()
with nvtx.annotate("optim"):
opt.step(); opt.zero_grad()
return loss
이 NVTX range 가 trace 에 박히면 — Nsight Systems 의 GUI 든, 직접 만든 dashboard 든 — 같은 timeline 위에서 “attention 이 차지한 % vs mlp 가 차지한 %” 같은 분해가 즉시 가능해진다. 의미론은 코드만 알 수 있다.
CUDA driver 에 callback library (libcupti.so) 를 attach 하면 — kernel launch, memcpy, memset, stream sync 등이 event 로 흘러나온다. 각 event 에 실제 GPU 시간이 박혀 있어 launch 와 실제 실행 사이의 gap (host-side latency) 도 측정 가능.
핵심 limitation 두 가지.
LD_PRELOAD 또는 init 시점에 hook. 이미 도는 process 에는 못 붙는다.NVTX/CUPTI 가 잡지 못하는 “이미 도는 production process” 에 대해서는 eBPF 가 cuLaunchKernel uprobe 로 같은 신호를 잡는다. 의미론(NVTX) 은 빈약하지만 attach 가 자유롭다.
대규모 학습은 거의 항상 multi-GPU + multi-node. 한 노드의 GPU profile 만 봐서는 — 어느 NCCL allreduce 가 다른 rank 의 stragger 때문에 길어졌는지 결정이 안 난다. 분산 환경의 observability 는 cross-rank correlation 이 추가되는 새 차원.
강의에서 정리되는 패턴은 두 단계.
L064 — Optimizing Communication for ML 와 L058 — Tracing for distributed 같은 강의들이 같은 문제를 다른 각도에서 본다. L098 의 contribution 은 collection layer 자체를 eBPF 로 통일하자는 제안.
구체적인 실현은 보통 — 각 노드에서 bpftime agent 가 돌면서 launch / NCCL ioctl / NVTX 를 수집, OpenTelemetry 또는 Prometheus 로 export, 중앙 dashboard 에서 rank 별 lane 으로 시각화. 이 stack 의 어느 부분이든 NVIDIA 가 직접 제공하지 않는다는 점이 강의의 큰 메시지 — third-party tooling 의 자리가 진짜로 비어 있다.
Yusheng 이 maintain 하는 eunomia-bpf org 안의 repo 들은 무작위가 아니라 한 stack 의 다른 layer들이다. 어떤 repo 가 어디 위치하는지를 정리하면 강의 본문이 절반은 풀린다.
이 repo 들의 관계를 한 문장으로 — “llvmbpf 가 컴파일하고, bpftime 이 사용자공간에서 실행하고, gpu_ext 가 driver 안 hook 점을 노출하고, agentsight 가 LLM 시대의 새 application”. observability stack 의 기반과 응용을 같은 author 가 한 묶음으로 깔고 있다.
stack 의 가치를 검증하는 가장 좋은 방법은 — 이 stack 이 없었다면 어떻게 풀었을까 를 물어보는 것. 두 개의 대표적 case.
nvidia-smi 의 memory 그래프는 정상으로 보이지만 throughput 이 절반. L3 (gpu_ext UVM hook) 의 page fault tracing 으로 어떤 tensor 의 page 가 얼마나 자주 evict 되는지 직접 본다.네 case 의 공통점 — 코드를 수정하지 않고도 답이 나오는 자리. 이 “zero instrument” 가 production observability 의 진짜 가치다. 개발자가 손을 댈 수 있는 자리에서는 NVTX 가 가장 풍부하지만, 손이 안 닿는 자리에서는 eBPF 가 유일한 답.
eBPF stack 이 모든 것을 대체하지 않는다. 도구 별로 강점과 한계를 표로 정리해두면 어느 자리에 어떤 도구를 쓸지 결정이 빨라진다.
실전 결정의 한 가지 트릭 — “dev 에서 reproduce 가 되는가” 를 첫 분기로 쓴다. 된다면 Nsight Systems 한 번 띄우는 게 항상 최선. 안 된다면 (production-only 버그) eBPF stack 으로 넘어간다. 두 stack 을 같은 schema 로 emit 하도록 정렬해두면 dev 에서의 직관이 production 으로 이전된다.
eBPF GPU stack 은 실제 production 에 깔아보면 몇 개의 만성적 문제가 있다. 강의에서 명시되지 않았더라도 — repo 의 issue / paper limitations 에서 일관되게 언급되는 것들.
gpu_ext 는 특정 driver 버전 (예: v575.57.08) 에 묶여 있다. driver upgrade 와 함께 fork 도 따라가야 한다.gpu_ext 의 hook 점이 적용되지 않는다.이 강의가 발표된 시점의 정확한 driver/CUDA 버전 매핑, B200 / Blackwell 에서의 PTX injection 실증 여부, 그리고 strugger detection 의 수치적 결과 — 자막 실패로 직접 확인 어려움. 강의 비디오를 다시 보고 채워야 할 항목들이다.
자막이 실패한 강의이지만 — 발표자의 repo 와 paper 가 stack 의 모양을 충분히 드러낸다. 다시 돌아왔을 때 빠르게 복원해야 하는 사실들.
bpftime = 사용자공간 VM + uprobe/PTX injection. gpu_ext = NVIDIA OGKM fork 에 struct_ops hook. 두 layer 가 다른 자리를 채운다.nvidia-smi 가 한가해 보여도 throughput 이 깎이는 패턴. gpu_ext 의 page fault tracing 만 직접 답.nvtx.annotate 를 forward / backward / optim 에 박고 Nsight Systems 로 한 step 의 timeline 을 본다. 의미론적 분해가 timeline 위에서 보이는지 확인.bpftime 을 설치하고 단순한 uprobe 로 cuLaunchKernel 의 호출 횟수를 기록. CUDA app 를 수정하지 않고 신호가 나오는지 검증.nvidia-smi 와 gpu_ext trace 를 동시에 보고 page fault 패턴 비교.L098 의 4-layer stack 은 다른 GPU Mode 강의들의 도구를 모두 한 timeline 위로 끌어올 수 있는 frame. 어느 강의가 어느 layer 와 매핑되는지를 묶어둔다.
자막이 실패한 강의라 노트의 많은 부분이 발표자의 repo 와 관련 paper 로부터 재구성됐다. 채워야 할 빈 자리들을 명시.
이 노트의 모든 capability matrix 항목과 case 예시는 발표자의 공개 repo (eunomia-bpf, bpftime, gpu_ext) 와 관련 paper (OSDI/ATC) 의 description 으로부터 재구성한 것이다. 강의 영상에서 직접 다룬 demo 와 수치는 자막 실패로 확인되지 않았다.