1P by GN⁺ 14시간전 | ★ favorite | 댓글 1개
  • GPU는 연산 속도가 메모리 접근 속도보다 월등히 빨라서, 메모리 계층 구조가 성능의 병목을 일으킴
  • 연산 집약도(Arithmetic Intensity, AI) 에 따라 연산이 메모리 바운드, 계산 바운드 상태로 구분되며, A100 GPU의 임계점은 약 13 FLOPs/Byte임
  • 성능 최적화 주요 전략으로 연산 합치기(Fusion)와 타일링(Tiling)이 있음; Fusion은 불필요한 메모리 왕복을 줄이고, Tiling은 데이터 재사용을 극대화함
  • 동기화, Coalesced Load, 뱅크 충돌 해결 등 GPU 하드웨어의 구조적 특성을 이해하는 것이 고성능 커널 작성에 중요함
  • 점유율(Occupancy), 스레드 분기 최소화, 양자화(Quantization) 등 추가적인 고려사항이 실제 성능에 중요한 영향을 미침

GPU의 컴퓨트 및 메모리 계층 구조

  • GPU는 일반적으로 메모리 대역폭보다 산술 연산 처리 속도가 훨씬 높음
  • 예를 들어, NVIDIA A100은 약 19.5 TFLOPS(32비트 부동소수점) 성능을 내지만, 메모리 대역폭은 약 1.5TB/s 수준임
  • 4바이트 데이터를 읽는 동안 수십 개의 계산을 처리할 수 있으므로, 데이터 이동이 성능의 병목임
  • 글로벌 메모리(VRAM) 는 모든 데이터가 존재하는 느린 오프칩 메모리이며, Streaming Multiprocessor(SM) 는 컴퓨팅을 담당함
  • SM에는 고속 온칩 Shared Memory(SRAM) 가 있고, 여기서 프로그램이 직접 관리하는 캐시로 활용 가능함
  • 스레드는 가장 작은 실행 단위이며, 각 스레드는 개별 레지스터 집합을 갖고 있음
  • 32개의 스레드Warp를 이루며, Block은 동일 SM에서 실행될 스레드 그리드임

성능 구간: 메모리 바운드 vs 컴퓨트 바운드

  • 커널의 성능은 메모리 바운드(데이터 이동 속도에 의해 제한) 또는 컴퓨트 바운드(SM 연산 능력에 의해 제한) 중 하나임
  • 연산 집약도(AI) 는 Total FLOPs / Total Bytes Accessed로 정의되며, 이 값이 중요 지표가 됨
  • Roofline 모델: x축이 AI, y축이 FLOPS/s인 그래프에서 커널의 실현 성능을 나타냄
    • AI가 낮아 메모리 바운드이면 대각선(메모리 대역폭 계단)
    • AI가 높아 계산 바운드이면 수평선(최고 연산 성능 계단)
  • A100의 Ridge Point는 19.5 TFLOPS / 1.5 TB/s ≈ 13 FLOPs/Byte임
  • AI를 높이면 성능이 향상되며, 커널이 컴퓨트 바운드에 도달할 수 있음

연산 집약도 높이기 전략

  • 간단한 모델: 스레드 1개가 C[i,j] 1개 계산 → AI = 0.25 (매우 낮음, 메모리 바운드)
  • 스레드가 2x2 타일 계산 시에도 AI = 0.5 (여전히 낮음)
  • AI를 높이기 위해서는 여러 스레드가 블록 단위로 Shared Memory에 대형 타일을 적재해 데이터 재사용을 극대화해야 함
  • Block 내 스레드 협력을 통해 AI > 13로 증가시켜 컴퓨트 바운드에 진입 가능함

오버헤드 바운드 상태

  • CPU(호스트)가 GPU에 작업을 할당하는 과정에서 오버헤드 발생 가능
  • GPU 커널이 너무 작거나 많으면, GPU는 작업을 기다리며 대기하는 상황 발생
  • 현대 프레임워크는 비동기 실행을 도입해, 커맨드 스트림을 미리 큐잉하여 오버헤드를 최소화함

성능 증진을 위한 두 가지 핵심 전략: Fusion과 Tiling

Operator Fusion (연산 합치기)

  • 단순 연산(chain), 예: y = relu(x + 1)에서는 각 연산이 별도 커널로 동작하면 데이터가 글로벌 메모리를 왕복함
  • Fusion은 여러 연산을 하나의 커널로 합쳐 중간 값을 글로벌 메모리에 저장하지 않고, 레지스터 내에서 연산 처리 후 최종 결과만 기록함
  • 예시: Triton, torch.compile Inductor 등 JIT 컴파일러가 자동화 처리

Tiling (타일링)

  • 행렬곱 등 복잡한 연산에서, 단일 스레드 모델로는 AI가 낮음
  • 블록 단위로 타일을 나눈 후, 블록 내 모든 스레드가 협력해 데이터 타일을 Shared Memory에 적재, 대규모 데이터 재사용 구현
  • 연산은 "Load(글로벌 -> Shared Memory) - Synchronize(동기화) - Compute(연산)" 3단계 패턴을 따름

Coalesced Load와 벡터화

  • 글로벌 메모리에서 Shared Memory로 데이터를 옮길 땐, Coalesced Access(워프 32개 스레드가 연속된 128바이트 구간 접근)가 중요
  • 벡터화(예: float4) 로 한 번에 여러 데이터 로드 시, 하드웨어 리소스 절약 및 메모리 대역폭 활용 극대화
  • 데이터 정렬(alignment)이 필수이며, 행렬 내 바이트 수 K값이 4의 배수여야 효율적임

Shared Memory 뱅크와 뱅크 충돌

  • Shared Memory는 32개의 독립된 뱅크로 구성되어, 워프 32개 스레드가 각기 다른 뱅크에 접근해야 충돌 없이 동작
  • 행 단위 접근은 충돌 없음, 열 단위 접근은 충돌(같은 뱅크 접근) 발생
  • B 타일은 "로드 및 전치" 전략으로 Shared Memory에 전치로 저장해, 연산 시 행 접근 중심으로 뱅크 충돌을 피함

고속 온칩 연산 패턴

기본 전략 1: 한 스레드가 한 output 계산

  • BLOCK_DIM=32 제한 하에 AI 최대 8로, 컴퓨트 바운드 진입 불가

전략 2: 한 스레드가 여러 output 계산

  • BLOCK_DIM=16, TILE_DIM=64로 설정 시, 한 스레드가 4x4 출력 계산 → AI=16
  • AI>13이므로 A100 기준으로 compute-bound 성능 달성 가능
  • Shared Memory에서 float4 등 벡터화 로드로 효율적 연산 가능

타일화의 실제 한계: 타일 양자화

  • 행렬 크기가 타일 크기의 배수가 아니면, 경계 블록이 실제보다 큰 영역을 계산(불필요한 연산)하며 패딩 처리됨
  • 경계의 스레드는 guard 조건으로 불필요한 메모리 접근은 막지만, 연산 루프는 동일하게 돌려 쓰레기 계산(예: C += A * 0) 발생

추가 성능 튜닝 요소

점유율(Occupancy)와 대기(Latency) 숨기기

  • 워프가 메모리 읽기 등 장시간 대기 시, SM은 다른 워프로 즉각 전환해 유휴 시간을 줄임(대기 숨기기, latency hiding)
  • 여러 Thread Block을 동시에 할당하면, 높은 점유율로 대기 시간 최소화
  • Block이나 타일 크기가 너무 커지면 resident block 수가 줄고, 점유율 저하로 성능 저하 발생

스레드 분기 최소화

  • 워프 내 if-else 조건 분기가 발생하면, 두 경로를 순차적으로 실행해 효과적인 성능 절반 수준으로 감소함
  • min, max 등 branchless 코드로 분기 최소화 필요

양자화(Quantization)

  • FP32 → FP16/BFP16 등 정밀도 축소 시, 메모리 이동량 및 처리 가능 데이터 수가 각각 2배로 증가함
  • A100 기준 FP16 연산은 312 TFLOPS(상대적으로 FP32의 19.5 TFLOPS 대비 최대 16배 성능) 도달 가능
  • 양자화로 Roofline상의 AI 오른쪽(메모리 효율)과 위쪽(최고 연산 성능) 동시 달성 가능

전체 요약

  • GPU 성능의 본질적 한계는 메모리 대역폭온칩 연산 능력의 불균형에 기인함
  • 성능 향상은 데이터 재사용 극대화(타일링) 및 중간 메모리 트래픽 최소화(Fusion) 로 달성
  • 하드웨어 구조(워프, 뱅크, 코얼레스드 액세스, 동기화) 특성을 이해해야 고성능 커널 작성 및 최적화가 가능함
  • 실전에서는 점유율, 분기 최소화, 양자화 등 추가적인 요소가 실질적 속도에 직접적인 영향 미침
  • 고성능 GPU 연산 설계는 이론적 AI 향상, 하드웨어 특성 활용, 실제 데이터 배치 및 사이즈 대응 등 복합적인 고려가 필요함
Hacker News 의견
  • 전체 프로그램 최적화가 컴파일러 레벨에서 얼마나 잘 되고 있는지 궁금증, 각각의 LLM 아키텍처를 하나씩 최적화하는 현재 방식이 뭔가 뒤처지는 느낌이라는 생각

  • 같은 4070에서 llama.cpp와 vllm을 돌려서 더 많은 프롬프트를 배치로 처리하려고 시도 경험 공유, batch 8부터 llama.cpp는 심각하게 느려지고 GPU 사용률은 괜찮아 보여도 실제론 병목이 생긴 상황 설명, vllm은 훨씬 더 잘 처리함을 체감함

    • vllm이 paged kv 캐시와 GPU가 선호하는 fully coalesced 레이아웃을 사용해서 배치에 최적화된 성능 제공, 반면 llama.cpp는 단일 프롬프트에 좋은 flat 레이아웃이라서 batch 상황에서는 L2 메모리 접근 패턴이 깨져 속도 저하

    • llama.cpp에서 kv tensor를 [seq, head, dim]에서 [head, seq, dim] 형태로 interleave하면 vllm에서 fused attention kernel로 데이터 공급하는 방식을 따라가 2배 정도 연산 성능 바로 향상 경험 공유

    • 병목의 원인은 GPU 자체가 아니라 shared memory 접근 방식과 global read를 어떻게 설계하느냐에 있음, vllm이 바로 그 점을 레이아웃 변경으로 공략

    • 이런 병목 분석에 2일 넘게 걸렸고, GPU 활용 그래프만 봐선 알 수 없었으며 대부분 시행착오로 알게 된 점

    • 이런 실험을 좀 더 수월하게, 핫 리로드 방식으로 반복할 수 있는 방법이 있는지 궁금증 제시

    • GPU가 병목이 아니라고 했지만, 실제로는 메모리 레이아웃의 비효율이 결국 GPU의 연산 효율을 낮추는 병목이었다는 지적

    • deepseek 직원이 어제 공개한 nano-vllm 프로젝트 언급, 1200줄밖에 안 되는데 vanilla vllm보다 더 빠른 성능 기록했다는 소식 공유 https://github.com/GeeeekExplorer/nano-vllm

    • llama.cpp에서 변경된 레이아웃을 pull request로 올렸는지 질문, 2배 향상은 모두에게 큰 이득이 될 수 있을 거라는 의견

    • ik_llama.cpp라는 프로젝트도 시도해보라고 추천 https://github.com/ikawrakow/ik_llama.cpp

  • 좋은 정보가 담긴 아티클로, 이 내용이 NVIDIA가 GPU 아키텍처를 개발할 때 선택하는 요소들에 대한 이야기라는 의견 전달, 타사와의 차이점을 오해하지 말라고 강조

    • 예를 들어 AMD Instinct MI300은 FP32에서 최대 160 TFLOPS와 6TB/s의 HBM3/3E 대역폭으로 ridge-point가 바뀌며 이는 A100의 13 FLOPs/byte의 두 배인 27 FLOPs/byte, 대용량 HBM메모리(128~256GB)는 tiling depth와 occupancy 간 현실적 트레이드 오프도 바꿔놓음, 단 이런 GPU는 비싸고, CUDA 미지원이라는 트레이드오프 존재

    • AMD가 컴퓨팅 소프트웨어에 더 신경 쓰기 전까지는 NVIDIA GPU만 존재감을 가질 수밖에 없다는 의견

  • 스포일러로, 실제로 중요한 건 GPU 동작 원리 자체보다 머신러닝 계산에 어떻게 활용하는지라는 점 강조

    • 사실상 내용은 CUDA의 일반적인 요약에 가깝고, relu 예제와 torch 언급 빼곤 머신러닝과 큰 상관 없는 구성이라는 지적
  • 대비 색상 사용을 반드시 해야 한다는 의견, 가독성 강조

    • font-weight: 300 사용 경험 공유, 대다수 Mac 디자이너가 폰트 스무딩 옵션에 맞춰 개발해서 일반적으로는 "normal"로 보이게 설정하는데, Mac은 얇은 폰트도 반쯤 두껍게 보이게 처리, 그래서 디자이너들은 더 얇은 폰트로 "보통" 느낌을 내는 경향 언급, 관련 링크 공유 https://news.ycombinator.com/item?id=23553486

    • 저자가 다크 모드로 편집하고 포맷하는 중일 수 있다는 추측, edge://flags/#enable-force-dark를 씌우면 링크가 잘 보인다는 점 언급

    • 작성자가 링크와 코드 블록 내 주석은 읽는 데 특히 더 노력 필요했던 점 지적, 콘트라스트 증가 제안, 콘텐츠 품질 자체는 매우 훌륭했다는 평가

    • 웹사이트가 텍스트에 알파 투명도를 써서 심각하게 콘트라스트를 떨어뜨리는 큰 실수라는 비판

  • 이 글은 사실 Nvidia GPU의 기본적인 사실들에 좀 더 가까운 제목이 더 나을 것 같다는 제안, WARP 용어도 최신 Nvidia GPU의 특징이며, 2003년쯤의 Nvidia GPU는 비디오 게임 렌더링만을 위한 하드웨어라서, 오늘날의 범용 연산 GPU와는 완전히 다르다는 배경 설명, 결국 게시글 내용은 모든 GPU에 적용될 수 있는 일반적 설명은 아니라는 요약

  • 정말 좋은 입문용 자료라서 감사하다는 의견, AI PC를 직접 조립할 때 GPU에 대해 며칠씩 조사했는데, 이 글이 반드시 알아야 할 핵심과 고부가가치 응용분야(생성형 AI)까지 잘 정리돼 있어 큰 도움됐다는 후일담, 특히 A100 GPU의 메모리 계층 구조 다이어그램이 매우 유용했다는 평가

  • ASCII 다이어그램 사용에 대한 의아함