PyTorch 내부 구조 08 - CUDA Stream, Event, Asynchronous Execution
PyTorch의 CUDA 연산은 기본적으로 비동기이기 때문에 실제 병목을 읽으려면 stream semantics를 알아야 한다
GPU 연산은 왜 생각보다 늦게 보일까
PyTorch에서 CUDA op를 호출했다고 곧바로 CPU가 그 연산이 끝날 때까지 기다리는 것은 아니다. 기본적으로 많은 작업은 비동기 enqueue된다. 그래서 timing, synchronization, dependency를 잘못 읽기 쉽다.
stream을 알아야 하는 이유
- kernel launch 순서 이해
- data transfer와 compute 겹치기
- 잘못된 benchmark 피하기
- custom op에서 synchronization 실수 줄이기
특히 cuda.synchronize()를 어디서 하느냐에 따라 측정 결과가 크게 달라질 수 있다.
event와 dependency
여러 stream을 쓰면 event를 통해 순서를 맞출 수 있다. 하지만 무분별한 synchronize는 overlap 기회를 없애고, 반대로 필요한 synchronization이 없으면 correctness 문제가 생길 수 있다.
다음 글에서는 C++ extension으로 넘어간다. Python 경계를 넘어 operator를 붙이기 시작하면 stream과 device semantics도 더 조심해서 다뤄야 한다.