---
title: "GPU occupancy가 두 배여도 실행 시간이 줄지 않는 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-11-02T09:57:03.752Z"
updated_at: "2026-10-06T03:16:51.724Z"
tags: ["gpu occupancy"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/gpu-occupancy%EA%B0%80-%EB%91%90-%EB%B0%B0%EC%97%AC%EB%8F%84-%EC%8B%A4%ED%96%89-%EC%8B%9C%EA%B0%84%EC%9D%B4-%EC%A4%84%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# GPU occupancy가 두 배여도 실행 시간이 줄지 않는 이유

이 글은 AI가 활용됐습니다.

[원문](https://ariser.io/@writer_a9817d5a8de0/gpu-occupancy%EA%B0%80-%EB%91%90-%EB%B0%B0%EC%97%AC%EB%8F%84-%EC%8B%A4%ED%96%89-%EC%8B%9C%EA%B0%84%EC%9D%B4-%EC%A4%84%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0)

GPU occupancy가 50%에서 100%로 올라갔는데 커널 시간은 거의 줄지 않을 수 있다. SM에 머무는 warp가 많다는 것과 지금 다음 명령을 실행할 warp가 많다는 것은 다르다. GPU occupancy는 자원 배치의 중요한 지표지만 단독으로 성능을 설명하지는 않는다.

## 머물 수 있는 warp와 실행할 수 있는 warp

CUDA는 block이 요구하는 레지스터와 shared memory, SM의 thread·block 한계로 동시에 배치할 작업이 제한된다고 설명한다. occupancy는 SM이 지원하는 최대 warp 수에 대한 상주 warp 수의 비율로 읽는다. 스케줄러는 그중 다음 명령을 실행할 준비가 된 warp를 선택한다. [CUDA Programming Guide, Hardware Multithreading](https://docs.nvidia.com/cuda/cuda-programming-guide/03-advanced/advanced-kernel-programming.html#hardware-multithreading)

예를 들어 load 결과를 기다리는 warp는 SM에 남아 레지스터를 사용하지만, 그 결과를 필요로 하는 다음 연산을 아직 실행할 수 없다. 다른 준비된 warp가 있으면 그 기다림 동안 명령을 발행할 기회가 생긴다. 모두가 같은 의존성이나 자원을 기다리면 warp 개수를 더 세어도 그 순간의 준비된 명령은 늘지 않을 수 있다.

## 자원 한계를 block 단위로 계산한다

가상의 SM 한계를 thread 2,048개, warp 64개, block 16개, 레지스터 65,536개와 shared memory 64KiB로 정하자. 특정 GPU 제품의 사양표가 아닌 배치 계산용 숫자다. 한 block에는 thread 256개, 즉 warp 8개가 있고 shared memory 8KiB를 사용한다.

thread당 레지스터 64개라면 block 하나는 16,384개를 요구한다. 레지스터 한계로 네 block, thread 한계로 여덟 block, shared memory 한계로 여덟 block까지 들어갈 수 있으므로 최소인 네 block이 결정한다. 상주 warp는 32개, occupancy는 50%다.

thread당 레지스터를 32개로 줄이고 다른 조건을 유지하면 레지스터도 여덟 block을 허용한다. 이제 여덟 block, 64개 warp로 occupancy 100%가 된다. 실제 GPU는 레지스터 배정 단위와 추가 한계를 가지므로 이런 단순 나눗셈만으로 실제 occupancy를 확정하지는 않는다. 컴파일 결과와 대상 장치의 배치 규칙을 함께 확인한다.

## 더 많은 warp가 기다림을 숨길 조건

설명용 스케줄러는 cycle마다 준비된 warp 하나의 명령을 발행할 수 있다고 정하자. 이미 32개 상주 warp 중 충분한 수가 독립된 명령을 준비하고 있어서 매 cycle 발행이 이루어진다면, 상주 수를 64개로 늘려도 이 모델의 발행 상한인 한 명령/cycle은 그대로다. occupancy 두 배가 처리량 두 배를 보장하지 않는 반례다.

반대로 32개가 자주 모두 기다리고 추가 warp가 독립된 일을 준비한다면 빈 cycle을 줄일 수 있다. 핵심 조건은 단순히 추가 warp가 존재하는지가 아니라 기다리는 동안 실행할 명령을 제공하는지다. 이 자체 스케줄 모델은 실제 SM의 발행 폭이나 메모리 지연을 측정한 결과가 아니다.

레지스터를 줄이는 변경에도 비용이 붙을 수 있다. 값이 레지스터에 들어가지 않아 local memory로 spill되면 명령과 메모리 접근이 늘어난다. CUDA 문서도 레지스터 제한으로 occupancy가 높아지면서 spill이 발생하면 성능 특성이 달라질 수 있다고 설명한다. [CUDA Programming Guide, Kernel Launch and Occupancy](https://docs.nvidia.com/cuda/cuda-programming-guide/02-basics/writing-cuda-kernels.html#kernel-launch-and-occupancy)

공유 데이터를 더 자주 다시 읽거나 한 thread의 독립 연산을 줄이는 변경도 생각해야 한다. 더 많은 warp로 얻은 지연 은폐의 이득이 늘어난 작업량과 자원 경쟁을 이길지는 실행 조건에 따라 다르다. 메모리 대역폭이 이미 포화라면 추가 동시 요청이 그 대역폭을 두 배로 만들지도 않는다.

비교할 때에는 컴파일된 레지스터·spill과 shared memory 사용량, 실제 상주와 준비 상태, 실행 시간 및 처리한 작업량을 함께 본다. 입력 크기와 workload가 달라지면 같은 occupancy의 의미도 달라질 수 있다.

GPU occupancy를 올리는 목적은 숫자를 채우는 데 있지 않다. 유휴 실행 시간을 줄이는 데 있다. 자원 한계로 상주 수가 정해지는 과정과 실제 다음 명령이 준비되는 과정을 나누어 보면, occupancy가 오른 변경을 유지할지 되돌릴지 성능 근거로 판단할 수 있다.

