Computing

CUDA Graphs : 개념 설명 및 구현 예제 본문

가속기 Accelerator/GPU

CUDA Graphs : 개념 설명 및 구현 예제

jhson989 2022. 4. 18. 20:00

cuDNN

cuDNN 8.0 부터 도입된 cuDNN backend API는 network 생성과 execution을 분리하여 성능상의 이점을 가져온다. 프로그래머는 코드 상에서 미리 deep learning primitives들의 graph(network)를 선언한다. 빌드 과정에서 graph는 최적화되며, 주로 operation fusion을 예로 든다. 컴파일 단계에서 operation(kernel)들을 하나의 operation로 만들어 최적화하는 기법인데 kernel launch overhead를 줄일 수 있을 뿐만 아니라, 불필요한 메모리 I/O도 줄일 수 있다. 

 

이러한 cuDNN backend API는 CUDA Graphs를 기반으로 만들어졌다고 한다. 이번 포스터에서는 [1], [2], [3], [4]를 바탕으로 CUDA Graphs에 대하여 정리하고자 한다.

 

 

 

Introduction

CUDA Graphs는 새롭게 도입된 work submission 모델이다. 기존에 kernel을 launch하거나 GPU memory operation, 기록을 위한event operation 등을 사용할 시, 각각의 operation마다 CUDA API 호출하여야 했다. 문제는 operation들을 여러번 실행시킬 경우 host는 그 개수만큼 여러번 함수를 호출해야 하는데, 이 overhead가 생각외로 크다고 한다. [3]에 따르면, 리눅스 시스템 상에서 CUDA 10.0을 이용한 CUDA kernel launch는 대략 2.2us가 소요된다. 수~수십 us가 소요되는 작은 kernel을 여러번 실행시키는 경우에는 kernel launch 시간만도 큰 부분을 차지하는 것이다. 시간에 따른 모형의 변화를 예측하는 시뮬레이션이나 실시간성이 중요한 자율주행과 같은 딥러닝 애플리케이션에서 이러한 overhead는 특히 큰 영향이 있을 것이다. CUDA Graphs는 여러번의 operation 실행을 하나의 큰 work(=graph)로 합쳐 한번만 host에서 실행시킴으로서 이 overhead를 줄이고자 한다. 

 

 

 

Graph structure

CUDA Graphs라는 이름과 마찬가지로 CUDA API를 graph 형태로 만들어 그 graph를 driver에 제출하겠다는 의미이다. Fig 1. 은 CUDA Graphs를 잘 나타내는 그림이다.

Fig 1. CUDA graphs 예시 [2]

CUDA Graph의 node는 CUDA operation을 의미하며, edge는 operation간의 dependency를 나타낸다. Graph는 directed acyclic graph(DAG)이다. 언젠가는 끝날 것이기에 acyclic이지 않을까 생각한다.

Graph의 node는 CUDA operation이며 다음 10개 중 하나이다. 이때 graph의 node로 child graph가 들어올 수 있는데, 이처럼 CUDA graph를 hirerarchical 구조로 설계할 수 있다.

  • kernel
  • CPU function call
  • memory copy
  • memset
  • empty node
  • waiting on an event 
  • recording an event 
  • signalling an external semaphore
  • waiting on an external semaphore
  • child graph

Graph의 edge는 operation간의 dependecy를 나타낸다. 한 operation이 완료된 후에 다른 operation이 실행되어야 하는 경우 둘 사이에는 dependency가 있는데, edge를 연결하여 이를 나타낸다.

Dependencies가 만족된 operation들은 언제든 실행될 수 있다. 또한, Fig 1. 의 B와 X처럼 graph 내에서 dependency가 없는 경우 둘은 동시에 스케쥴링될 수 있다. 실제 스케쥴링은 CUDA system이 담당하기에 프로그래머는 dependencies만 정의하여 실행 순서를 알려주고, 최적 스케쥴링은 CUDA system이 알아서 판단한다.

 

 

 

장점

CUDA Graph의 핵심은 graph definition과 그것의 execution을 분리한다는 것이다. 프로그래머는 declarative programming처럼 실행할 CUDA operation들을 graph로 선언한다. 완성된 하나의 graph는 instantiate되고, GPU driver에 의해 실행된다.

이러한 방식은 CUDA opearation 호출 overhead를 줄일 수 있다. GPU kernel 실행을 위해서 host driver는 내부적으로 여러개의 operation을 실행하는데, 이는 overhead가 된다고 한다. 여러번 GPU kernel을 실행할 경우 이 overhead가 쌓여 큰 성능상의 문제가 될 수 있다. 이를 Graph는 한번의 launch로 줄일 수 있다. 다만 definition 시간이 필요하다는 점에서 많이 반복 실행시키지 않을 경우 성능상에 그렇게 큰 이점이 안될 수도 있겠다는 생각이 든다.

이 뿐만 아니라, 실행 전 미리 모든 workflow를 알 수 있기에 추가적인 optimization이 가능해진다. 구체적으로 어떠한 optimization이 된다는 것은 명시하지 않았지만, computation과 memory transfer를 overlapping하거나, 한 kernel이 모든 GPU 하드웨어를 쓰지 않는다면 dependecy가 없는 두 kernel을 동시에 실행하는 것과 같은 최적화가 가능하지 않을까 한다.

마지막으로 graph는 definition은 여러번 재사용될 수 있다.  정리하자면 다음 3가지 장점을 가진다.

  1. CPU operation launch overhead 감소
  2. 추가적인 optimization 가능
  3. 한번 graph를 정의하면, 여러번 재사용 가능

 

 

 

Implementation 

Graph를 이용한 work submission 방식은 크게 3가지 단계로 이루어진다.

 

  • Definition
    • Operations 및 dependencies를 명시하여 graph를 생성함
    • 2가지 방식 존재
      • Stream capturing : definition 과정에서 kernel들을 실행함. kernel은 실제 실행되지는 않고 graph에 기록됨. 자동으로 node와 edge가 추가됨
      • Graph API : Graph API를 직접 node와 edge를 선언해줌. 명시적으로 graph를 그리는 방식
  • Instantiation
    • Graph definition(=template)를 바탕으로 intance 생성. graph의 타탕성 확인(validate), setup, initialization 등을 이 단계에서 진행하여, graph launch 시 필요한 일들을 줄이는 것을 목표로 함. 생성된 graph instance를 executable graph라고 함
  • Execution
    • Executable graph는 다른 CUDA operation처럼 launch되어 실행됨. 다시 instantiate할 필요없이 반복 실행시킬 수 있음

 

 

 

구현 예제

https://github.com/jhson989/cuda-graphs-tutorial

다음 github repository에 stream capturing 방식의 graph 구현 예제를 추가하였다.

 

 

 

Reference

[1] https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cuda-graphs

[2] https://developer.nvidia.com/blog/cuda-graphs/

[3] Steve Abbott, HIGHLIGHTS OF CUDA 10 FOR SUMMIT, OLCF User Conference Call

[4] Mostafa Hagog, Kevin Vincent, Yang Xu, Mathieu Zhang, Seth Walters, Scott Yokim, Anerudhan Gopal, CUDNN V8: New Advances in Deep Learning Acceleration, NVIDIA, March 2020

'가속기 Accelerator > GPU' 카테고리의 다른 글

GPU 프로그램이 느린 이유 - 1 : Memory Bound  (0) 2022.03.31
cuBLAS MatMul Tutorial  (0) 2022.03.28
CUDA PTX - 2 : Inline PTX Assembly  (0) 2022.03.21
CUDA PTX - 1 : Introduction  (0) 2022.03.19