Study · GPU · Interactive

Where the bytes live,
and why decode waits for them.
byte는 어디에 사는가,
그리고 decode는 왜 그 byte를 기다리는가.

A datacenter GPU is a small city built around one shortage: bytes per second. This is a guided tour of the NVIDIA A100-40GB — the floorplan, the memory ladder, the roofline, and a single LLM decode step traced byte by byte — ending at the number that rules inference: 14 GB ÷ 1.55 TB/s ≈ 9 ms per token. 데이터센터 GPU는 단 하나의 부족 자원, 초당 bytes를 중심으로 지어진 작은 도시다. NVIDIA A100-40GB를 따라가는 가이드 투어 — floorplan, memory 사다리, roofline, 그리고 byte 단위로 추적한 LLM decode 한 스텝 — 의 끝에는 추론을 지배하는 숫자 14 GB ÷ 1.55 TB/s ≈ 9 ms per token이 있다.

108SMs
312TFLOP/s BF16 (dense)
40 MBL2 cache
40 GBHBM2e
1.555 TB/sHBM bandwidth
≈200FLOP/byte ridge point
Before you start: you should know what a matrix–vector multiplication is, and roughly how a transformer LLM generates text — one token at a time, attending over previous tokens whose keys and values are kept in a KV cache. If that last phrase is fuzzy, read Attention anatomy first. No GPU background is assumed — building it is exactly what this page is for. 시작 전에: matrix–vector 곱이 무엇인지, 그리고 transformer LLM이 텍스트를 어떻게 생성하는지 — 한 번에 token 하나씩, 이전 token들의 key·value를 KV cache에 담아 attention한다는 것 — 정도는 알고 있어야 한다. 마지막 문장이 흐릿하다면 Attention anatomy를 먼저 읽자. GPU 배경지식은 전제하지 않는다 — 그걸 쌓는 것이 이 페이지의 목적이다.

§1The itch: 99.5% of the machine goes missing문제의식: 기계의 99.5%가 사라진다

Rent the GPU this page is about — an NVIDIA A100 — and the datasheet promises 312 trillion floating-point operations per second. Now load a 7-billion-parameter chat model and generate text for a single user. Measured against that promise, the arithmetic units are doing ≈1.6 TFLOP/s — half a percent of what you paid for. At any given instant, 99.5% of the machine is doing nothing. 이 페이지의 주인공인 GPU — NVIDIA A100 — 를 빌리면 datasheet는 초당 312조 번의 부동소수점 연산을 약속한다. 이제 7B 파라미터 챗 모델을 올리고 사용자 한 명에게 텍스트를 생성해 보자. 그 약속에 견줘 실측하면 연산 유닛이 하는 일은 ≈1.6 TFLOP/s — 지불한 것의 0.5%다. 어느 순간을 잘라 봐도 기계의 99.5%는 놀고 있다.

the datasheet promisedatasheet의 약속 312 TFLOP/s (BF16) what batch-1 decode achievesbatch-1 decode가 실제로 내는 것 ≈1.6 TFLOP/s — 0.5% of peak
Same GPU, same silicon. The gap between the two bars is the subject of this page. 같은 GPU, 같은 실리콘. 두 막대 사이의 간극이 이 페이지의 주제다.

Nothing in the obvious toolbox fixes this. A newer GPU with even more tensor cores makes single-user decode barely faster. The FLOPs were never the scarce resource — something else is, and until you can name that resource and put a number on it, every optimization aims at the wrong target. Naming it precisely is the goal here. 뻔한 도구상자 안에는 해결책이 없다. tensor core를 더 얹은 최신 GPU로 바꿔도 단일 사용자 decode는 거의 빨라지지 않는다. 애초에 부족한 자원이 FLOP이 아니었기 때문이다 — 다른 무언가가 부족하고, 그것의 이름과 숫자를 대기 전까지 모든 최적화는 엉뚱한 과녁을 겨눈다. 그 이름을 정확히 대는 것이 이 페이지의 목표다.

So which resource is actually scarce? 그렇다면 실제로 부족한 자원은 무엇인가?

§2Foundations: bytes, FLOPs, and one ratio기초: byte, FLOP, 그리고 비율 하나

A processor spends two currencies on every piece of work. The first is arithmetic: floating-point operations, FLOPs. The second is data movement: bytes carried from memory to the arithmetic units. They are priced separately — compute in FLOP/s, movement in bytes/s, which is called bandwidth. One further distinction matters. Latency is how long one byte takes to arrive, and it can be hidden by overlapping many requests in flight. Bandwidth is how many bytes arrive per second, and it cannot be hidden — if the computation needs the bytes, they must physically cross the wires. 프로세서는 모든 작업에 두 가지 통화를 지불한다. 첫째는 연산 — 부동소수점 연산, FLOP. 둘째는 데이터 이동 — memory에서 연산 유닛까지 실어 나르는 byte. 둘의 가격표는 따로 붙는다 — compute는 FLOP/s로, 이동은 bytes/s, 즉 bandwidth로. 구분 하나가 더 필요하다. Latency는 byte 하나가 도착하는 데 걸리는 시간이고, 요청 여러 개를 겹쳐 띄우면 숨길 수 있다. bandwidth는 초당 도착하는 byte의 양이고, 숨길 수 없다 — 연산에 그 byte가 필요하다면 물리적으로 전선을 건너와야 하기 때문이다.

Why not build memory that is both huge and fast? Physics forbids it. Storage next to the arithmetic (SRAM) is fast but burns die area per bit; dense storage (DRAM) must sit farther away, behind narrower connections. Every computer is therefore built as a hierarchy: a few fast kilobytes beside the math, gigabytes at a distance, each level trading capacity for speed. A datacenter GPU is the most extreme version of this bargain ever mass-produced. 크면서 동시에 빠른 memory를 만들면 되지 않을까? 물리학이 금지한다. 연산기 옆의 저장소(SRAM)는 빠르지만 bit당 die 면적을 태우고, 밀도가 높은 저장소(DRAM)는 더 좁은 연결 뒤, 더 먼 곳에 놓일 수밖에 없다. 그래서 모든 컴퓨터는 계층으로 지어진다: 연산기 옆의 빠른 몇 KB, 멀리 떨어진 몇 GB — 각 계층이 용량과 속도를 맞바꾼다. 데이터센터 GPU는 이 거래의 역사상 가장 극단적인 양산품이다.

memory (HBM)memory (HBM) 40 GB 1.555 TB/s computecompute 312 TFLOP/s balance point: 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP per byte균형점: 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP per byte
The whole machine, as one pipe and one engine. Everything on this page is about the pipe. 기계 전체를 파이프 하나와 엔진 하나로 그리면 이렇다. 이 페이지의 전부는 그 파이프에 대한 이야기다.

One derived number decides which currency you run out of. Divide the machine's two peaks: 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP per byte. That is the machine's balance point: to keep the arithmetic fully fed, a workload must perform about 200 FLOPs for every byte it pulls from main memory. A workload's own ratio — FLOPs performed per byte moved — is its arithmetic intensity (AI). Above ~200 the workload is compute-limited; below it, memory-limited, and the surplus FLOPs are free but useless. 어느 통화가 먼저 바닥나는지는 파생 숫자 하나가 결정한다. 기계의 두 peak을 나눠 보자: 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP per byte. 이것이 기계의 균형점이다: 연산기를 계속 먹여 살리려면 main memory에서 가져오는 byte 하나당 약 200 FLOP을 수행해야 한다. 워크로드 자신의 비율 — 옮긴 byte당 수행한 FLOP — 이 arithmetic intensity(AI)다. ~200 위면 compute-limited, 아래면 memory-limited이고, 남는 FLOP은 공짜지만 쓸모가 없다.

Now the workload. LLM decode produces one token at a time, and each token multiplies a single activation vector against every weight matrix in the model — a matrix–vector product. Each 2-byte FP16 weight is read once and used for exactly 2 FLOPs (one multiply, one add). That is an arithmetic intensity of about 1 — one, against a machine that wants 200. Hold that pair of numbers; the rest of the page is watching it play out in silicon. 이제 워크로드 차례다. LLM decode는 한 번에 token 하나를 만들고, token 하나는 activation 벡터 하나를 모델의 모든 weight 행렬과 곱한다 — matrix–vector 곱이다. 2-byte FP16 weight 하나는 한 번 읽혀 정확히 2 FLOP(곱하기 하나, 더하기 하나)에 쓰인다. arithmetic intensity로는 약 1 — 200을 원하는 기계에 1을 들고 도착하는 셈이다. 이 숫자 쌍을 기억해 두자; 페이지의 나머지는 이것이 실리콘 위에서 펼쳐지는 과정이다.

Takeaway핵심 한 줄 Achievable speed = min(peak compute, bandwidth × arithmetic intensity). The A100's balance point is ≈200 FLOP/byte — and LLM decode arrives carrying AI ≈ 1. 달성 가능한 속도 = min(peak compute, bandwidth × arithmetic intensity). A100의 균형점은 ≈200 FLOP/byte인데 — LLM decode는 AI ≈ 1을 들고 도착한다.

What does this shortage look like on the actual silicon? 이 부족은 실제 실리콘 위에서는 어떤 모습인가?

§3The die, mapped: compute is an islandDie 지도: compute는 섬이다

We now have the vocabulary — bytes, bandwidth, a balance point of ≈200 — but those are abstractions. The missing 99.5% from §1 has a physical address. Here is the A100's floorplan; the geography alone tells most of the story. 이제 어휘는 갖췄다 — byte, bandwidth, ≈200이라는 균형점 — 하지만 아직은 추상이다. §1에서 사라진 99.5%에는 물리적 주소가 있다. A100의 floorplan을 보자; 지리만으로도 이야기의 대부분이 설명된다.

The floorplan: compute is an island, memory is the ocean around it Floorplan: compute는 섬이고, memory는 그 주위의 바다다

Simplified A100 die. Hover any region for its numbers; click an SM to zoom into its internals on the right. 단순화한 A100 die. 영역에 hover하면 해당 숫자가 나오고, SM을 클릭하면 오른쪽에서 그 내부를 확대해 볼 수 있다.

HBM2e HBM2e HBM2e HBM2e HBM2e HBM2e L2 · 20 MB partition L2 · 20 MB partition
A100-40GB die

826 mm² of silicon, one bottleneck

108 streaming multiprocessors (SMs) share a 40 MB L2 cache and five active HBM2e stacks delivering 1.555 TB/s. Every weight an LLM touches must cross from the flanking HBM into this island — hover a region to see its numbers.

Inside one SMSM 하나의 내부 (click any SM)(아무 SM이나 클릭) warp sched register file 64 KB FP32 / INT32 FP64 lanes Tensor Core 3rd gen warp sched register file 64 KB FP32 / INT32 FP64 lanes Tensor Core 3rd gen warp sched register file 64 KB FP32 / INT32 FP64 lanes Tensor Core 3rd gen warp sched register file 64 KB FP32 / INT32 FP64 lanes Tensor Core 3rd gen L1 data cache + shared memory · 192 KB combined (up to 164 KB configurable as shared memory) LD/ST units SFU · Tex

Per SM: 4 processing blocks, each with a warp scheduler, a 64 KB register-file partition (256 KB total) and one tensor core (4 per SM, 432 on the die). All four share 192 KB of combined L1/shared storage — up to 164 KB usable as software-managed shared memory. SM당 processing block 4개 — 각각 warp scheduler 1개, 64 KB register-file 파티션(총 256 KB), tensor core 1개(SM당 4개, die 전체 432개)를 가진다. 네 블록이 L1/shared 통합 192 KB를 공유하며, 최대 164 KB를 소프트웨어가 관리하는 shared memory로 쓸 수 있다.

The A100 die packs 108 SMs, each with 4 third-generation tensor cores, a 256 KB register file, and 192 KB of combined L1/shared storage (up to 164 KB configurable as shared memory). All of them talk to a 40 MB L2 split into two partitions, and the L2 talks to five active HBM2e stacks sitting physically beside the die on a silicon interposer. The geography is the point: FLOPs are manufactured in the middle, but every byte of an LLM's weights lives off-die and must be imported at 1.555 TB/s — the width of that bridge, not the size of the island, decides how fast you decode. A100 die에는 108개의 SM이 들어 있고, 각 SM은 3세대 tensor core 4개, 256 KB register file, L1/shared 통합 192 KB(최대 164 KB를 shared memory로 설정 가능)를 가진다. 이들 모두는 두 파티션으로 나뉜 40 MB L2와 통신하고, L2는 실리콘 interposer 위 die 바로 옆에 물리적으로 놓인 5개의 활성 HBM2e 스택과 통신한다. 핵심은 이 지리다: FLOP은 가운데 섬에서 만들어지지만, LLM weight의 모든 byte는 die 밖에 살며 1.555 TB/s로 수입되어야 한다 — decode 속도를 정하는 것은 섬의 크기가 아니라 그 다리의 폭이다.

Takeaway핵심 한 줄 Compute is an island: FLOPs are made in the middle of the die, but every weight byte lives off-die and must cross a 1.555 TB/s bridge. The scarce resource is the width of that bridge, not the number of SMs. compute는 섬이다: FLOP은 die 한가운데서 만들어지지만, 모든 weight byte는 die 밖에 살며 1.555 TB/s 다리를 건너야 한다. 부족한 자원은 SM의 개수가 아니라 그 다리의 폭이다.

The die is not empty of memory — registers, shared memory, L2. Why can't the model simply live on-die? die 안에도 memory는 있다 — register, shared memory, L2. 그런데 왜 모델이 그냥 on-die에 살 수 없을까?

§4The memory ladder: capacity for speed, ×1000 at a timeMemory 사다리: 용량과 속도를 1000배 단위로 맞바꾸다

The floorplan showed several pools of on-die storage. Whether they can rescue decode comes down to two numbers per pool: how big, and how fast. Put the four levels side by side — on a log scale — and a brutal trade appears. floorplan에는 on-die 저장소 풀이 여럿 보였다. 이들이 decode를 구할 수 있는지는 풀마다 숫자 두 개 — 얼마나 크고, 얼마나 빠른가 — 로 결정된다. 네 계층을 log scale로 나란히 놓으면 잔혹한 거래 조건이 드러난다.

The ladder: every step up costs ~1000× capacity, buys ~10× speed 사다리: 한 칸 오를 때마다 용량 ~1000×를 내주고 속도 ~10×를 산다

Log-scale bars — equal visual steps are multiplicative. Hover a level for what actually fits there during LLM inference. Log-scale 막대 — 시각적으로 같은 간격이 곱셈 배수다. 각 계층에 hover하면 LLM 추론 중 실제로 거기 들어가는 것이 보인다.

capacity용량 aggregate bandwidth합산 bandwidth latency (shorter is better)latency (짧을수록 좋음)
Registers inside each SM partition각 SM 파티션 내부
256 KB / SM · ≈27 MB on die
≈100+ TB/s-class operand rate
≈1–2 cycles (≈1 ns)
What fits: only the accumulator fragments of the tile being multiplied right now — each thread holds a few dozen 32-bit values. Fun fact: the die-wide register file (≈27 MB) is two-thirds the size of L2, and orders of magnitude faster. 들어가는 것: 지금 이 순간 곱해지고 있는 tile의 accumulator 조각뿐 — 스레드 하나가 32-bit 값 수십 개를 쥔다. 재미있는 사실: die 전체 register file(≈27 MB)은 L2의 2/3 크기이면서 몇 자릿수나 더 빠르다.
Shared memory / L1 per SM, software-managedSM당, 소프트웨어 관리
192 KB combined / SM (≤164 KB shared) · ≈17.7 MB usable die-wide
≈19.5 TB/s aggregate (128 B/clk × 108 SMs)
≈20–30 cycles (≈20 ns)
What fits: the working tiles of a GEMM. A 128×128 FP16 tile is 32 KB, so double-buffered A- and B-tiles plus pipeline stages fill it. That's ~0.0005% of a 7B model resident at once — everything else must stream. 들어가는 것: GEMM의 작업 tile. 128×128 FP16 tile 하나가 32 KB라, double-buffered A·B tile과 pipeline 스테이지만으로 가득 찬다. 7B 모델의 ~0.0005%만 동시에 상주하는 셈 — 나머지는 전부 스트리밍해야 한다.
L2 cache shared, two 20 MB partitions공유, 20 MB 파티션 × 2
40 MB
several TB/s aggregate (microbenchmarks: ~3–7 TB/s, access-pattern dependent)
≈200+ cycles (≈150–250 ns; far partition costs more)
What fits: barely one weight matrix — a single 4096×4096 FP16 projection is 33.5 MB. Or ~76 tokens' worth of a 7B model's KV cache (≈524 KB per token). Weights stream through L2; they cannot live in it. 들어가는 것: weight 행렬 하나가 간신히 — 4096×4096 FP16 projection 하나가 이미 33.5 MB다. 아니면 7B 모델 KV cache로 ~76 token 분량 (token당 ≈524 KB). weight는 L2를 통과해 흐를 뿐, 거기 상주할 수 없다.
HBM2e off-die, five active stacksdie 밖, 활성 스택 5개
40 GB
1.555 TB/s
≈400–500 ns
What fits: the model itself. A 7B model in FP16 is ~14 GB; a 4k-token KV cache adds ~2 GB; the rest is activations, workspace, and headroom. This is the only level that holds the weights — which is why its 1.555 TB/s, not the 312 TFLOP/s, sets the decode speed limit. 들어가는 것: 모델 그 자체. FP16 7B 모델이 ~14 GB, 4k-token KV cache가 ~2 GB를 더하고, 나머지는 activation·workspace·여유분이다. weight를 담는 유일한 계층이며, 그래서 decode 속도 한계를 정하는 것은 312 TFLOP/s가 아니라 이곳의 1.555 TB/s다.
Bandwidths are aggregates across the die; per-byte latency is hidden by parallelism, but bandwidth cannot be hidden — every byte of a 7B model must physically cross the HBM interface for every generated token. Bandwidth는 die 전체 합산 수치다. byte당 latency는 병렬성으로 숨길 수 있지만 bandwidth는 숨길 수 없다 — 생성되는 token마다 7B 모델의 모든 byte가 HBM 인터페이스를 물리적으로 건너야 한다.

Each level trades roughly three orders of magnitude of capacity for one order of magnitude of bandwidth and latency. The numbers worth memorizing: shared memory aggregates to ≈19.5 TB/s (about 12× HBM), and the register file, at ≈27 MB die-wide, is a faster and nearly as large pool as L2 — which is why high-performance GEMM kernels are really register-file choreography. The ladder also explains why caching weights is hopeless: the largest on-die pool (L2, 40 MB) barely holds one 4096×4096 FP16 matrix (33.5 MB) out of a 13.5 GB model. 각 계층은 대략 용량 세 자릿수를 bandwidth·latency 한 자릿수와 맞바꾼다. 외울 가치가 있는 숫자들: shared memory는 합산 ≈19.5 TB/s(HBM의 약 12×)이고, register file은 die 전체 ≈27 MB로 L2에 버금가는 크기이면서 더 빠른 풀이다 — 고성능 GEMM kernel이 사실상 register-file 안무인 이유다. 이 사다리는 weight caching이 왜 가망 없는지도 설명한다: 가장 큰 on-die 풀(L2, 40 MB)이 13.5 GB 모델 중 4096×4096 FP16 행렬 하나(33.5 MB)를 간신히 담는다.

Takeaway핵심 한 줄 Every step up the ladder buys ~10× bandwidth and costs ~1000× capacity. All on-die pools together hold well under 100 MB against a 13.5 GB model — weights cannot be cached, only streamed, so every generated token re-reads the model from HBM. 사다리를 한 칸 오를 때마다 bandwidth ~10×를 사고 용량 ~1000×를 내준다. on-die 풀을 다 합쳐도 100 MB에 한참 못 미치는데 모델은 13.5 GB다 — weight는 cache할 수 없고 스트리밍할 수만 있으며, 그래서 생성되는 token마다 모델을 HBM에서 다시 읽는다.

If the bytes must stream no matter what, can we predict a workload's speed from its FLOPs and bytes alone? 어차피 byte가 스트리밍되어야 한다면, 워크로드의 속도를 FLOP과 byte만으로 예측할 수 있을까?

§5The roofline: the whole argument in one pictureRoofline: 지금까지의 논증을 그림 한 장으로

Fair warning: this is the hardest section of the page — take it slowly. The roofline model compresses everything so far into a single picture: one axis of arithmetic intensity, two ceilings, and every workload's speed limit readable at a glance. It is the one diagram worth internalizing before doing any performance work on GPUs. 미리 말해 두면, 여기가 이 페이지에서 가장 어려운 구간이다 — 천천히 가자. roofline 모델은 지금까지의 모든 것을 그림 한 장으로 압축한다: arithmetic intensity라는 축 하나, 천장 두 개, 그리고 한눈에 읽히는 모든 워크로드의 속도 한계. GPU 성능 작업을 하기 전에 체화할 가치가 있는 단 하나의 다이어그램이다.

The roofline: two ceilings, and decode lives under the slanted one Roofline: 천장은 두 개, decode는 기울어진 쪽 아래에 산다

Achievable FLOP/s = min(peak compute, bandwidth × arithmetic intensity). Log–log axes. Drag the batch slider and switch weight precision to move the ● marker. 달성 가능 FLOP/s = min(peak compute, bandwidth × arithmetic intensity). Log–log 축. batch 슬라이더를 움직이고 weight 정밀도를 바꾸면 ● 마커가 이동한다.

0.2514 1664256 1024 0.251 416 64256 arithmetic intensity — FLOP / byte from HBM (log) achievable TFLOP/s (log) HBM roof · 1.555 TB/s × AI 312 TFLOP/s BF16 ridge ≈ 200 FLOP/B prefill GEMM decode GEMV, B=1 attention · long KV batched decode · B=8
Batch size B (weights amortize, AI ≈ B × FLOP-per-weight-byte)Batch 크기 B (weight 읽기가 분할상환되어 AI ≈ B × FLOP-per-weight-byte)
1864512
Weight precision (weight-only quantization)Weight 정밀도 (weight-only quantization)
Arithmetic intensity산술 강도 (AI)≈ 8 FLOP/B
Achievable달성 가능≈ 12.4 TFLOP/s (4.0% of peak)
Aggregate decode ceiling합산 decode 상한≈ 889 tok/s (8 seq × 111)
Regime동작 영역memory-bound
The division that sets the ceiling (per sequence)상한을 정하는 나눗셈 (sequence당) 14 GB weights ÷ 1.555 TB/s ≈ 9.0 ms/token → ~111 tok/s

At B=1 every generated token must read all weights once. Quantize FP16→INT4 and the same division reads 3.5 GB ÷ 1.555 TB/s ≈ 2.3 ms → ~440 tok/s: compression is a bandwidth multiplier, not a compute trick. B=1에서는 생성되는 token마다 모든 weight를 한 번씩 읽어야 한다. FP16→INT4로 quantize하면 같은 나눗셈이 3.5 GB ÷ 1.555 TB/s ≈ 2.3 ms → ~440 tok/s가 된다: 압축은 compute 트릭이 아니라 bandwidth 곱셈기다.

Arithmetic intensity (AI) is FLOPs performed per byte moved from HBM. The machine's balance point is 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP/byte. Prefill GEMMs (thousands of tokens sharing each weight read) sit far right, compute-bound. Single-batch decode is a GEMV: 2 FLOPs per 2-byte weight, AI ≈ 1, achieving ≈1.6 TFLOP/s — half a percent of peak, and no kernel cleverness can fix it because the bytes are mandatory. Batching amortizes weight reads (AI ≈ B), which is why serving systems fight for large batches; attention over a long KV cache, however, stays at AI ≈ 1 even when batched, because each sequence reads its own KV — this is exactly the seam that KV-cache compression and quantization attack. Arithmetic intensity(AI)는 HBM에서 옮긴 byte당 수행한 FLOP이다. 이 기계의 균형점은 312 TFLOP/s ÷ 1.555 TB/s ≈ 200 FLOP/byte. Prefill GEMM(수천 개의 token이 weight 읽기를 공유)은 오른쪽 끝 compute-bound에 앉는다. Batch 1 decode는 GEMV다: 2-byte weight당 2 FLOP, AI ≈ 1, 달성 성능 ≈1.6 TFLOP/s — peak의 0.5%이고, byte 이동이 필수이므로 어떤 kernel 묘수로도 고칠 수 없다. Batching은 weight 읽기를 분할상환하므로(AI ≈ B) serving 시스템이 큰 batch를 위해 싸우는 것이고, 반면 긴 KV cache에 대한 attention은 batch를 해도 AI ≈ 1에 머문다 — 각 sequence가 자기 KV를 읽기 때문이다. 바로 이 지점이 KV-cache 압축과 quantization이 공략하는 틈이다.

Takeaway핵심 한 줄 Achievable FLOP/s = min(312 TFLOP/s, 1.555 TB/s × AI). Batch-1 decode sits at AI ≈ 1, 200× below the ridge — 99.5% of the compute is structurally unreachable. Batching amortizes weight reads (AI ≈ B), but attention over each sequence's own KV cache stays at AI ≈ 1. 달성 가능 FLOP/s = min(312 TFLOP/s, 1.555 TB/s × AI). batch-1 decode는 ridge보다 200× 아래인 AI ≈ 1에 앉아 있다 — compute의 99.5%는 구조적으로 닿을 수 없다. batching이 weight 읽기를 분할상환하지만(AI ≈ B), 각 sequence가 자기 KV cache를 읽는 attention은 AI ≈ 1에 머문다.

Ceilings and slopes are still abstract. What do the mandatory bytes look like, one matrix at a time, while a single token is made? 천장과 기울기는 여전히 추상적이다. token 하나가 만들어지는 동안, 그 필수 byte들은 행렬 단위로 어떤 모습일까?

§6One decode step, traced byte by byteDecode 한 스텝을 byte 단위로 추적하다

The roofline becomes concrete the moment you watch one token being manufactured. Below is the full byte-ledger of a single decode step for a 7B-class model — every matrix that must cross the bridge, in order, with a running meter of bytes and FLOPs. token 하나가 제조되는 과정을 지켜보는 순간 roofline은 구체가 된다. 아래는 7B급 모델의 decode 한 스텝에 대한 완전한 byte 장부다 — 다리를 건너야 하는 모든 행렬을 순서대로, byte와 FLOP 계기판과 함께.

One decode step, traced: 15.4 GB in, one token out Decode 한 스텝 추적: 15.4 GB가 들어가고 token 하나가 나온다

Llama-7B-class model (d=4096, 32 layers, FFN 11008, vocab 32k), FP16, 4096 tokens of context, batch 1. Step through what actually moves. Llama-7B급 모델 (d=4096, 32 layers, FFN 11008, vocab 32k), FP16, context 4096 tokens, batch 1. 실제로 무엇이 움직이는지 단계별로 따라가 보자.

HBM · 40 GB weights 13.5 GB FP16 KV cache 2.15 GB @ 4k ctx activations (tiny) L2 40 MB 108 SMs SMEM / L1 activation x[1×4096] = 8 KB, stays here registers accumulators tensor cores ≈2 FLOPs per weight byte-pair, then the weight is discarded idle — waiting for a token
step 0 / 7
A new token needs to be generated. The entire model sits in HBM; the “state” the GPU actually computes on — one 4096-long activation vector — is 8 KB. Press Next (or Play) to watch what has to move.
bytes from HBMHBM에서 온 bytes
0 B
FLOPs done수행한 FLOPs
0
time if BW-limitedBW-limited일 때 시간 0 ms
time if compute-limitedcompute-limited일 때 시간 0 ms
Punchline: ≈15.4 GB moved for ≈15 GFLOP — arithmetic intensity ≈ 1. The byte-time floor is ~9.9 ms; the FLOP time is ~0.05 ms. The tensor cores are idle ~99.5% of the step, and measured decode throughput on good kernels sits near this bandwidth ceiling — not the 312 TFLOP/s brochure number. 결론: ≈15 GFLOP을 위해 ≈15.4 GB가 움직였다 — arithmetic intensity ≈ 1. byte 시간 하한은 ~9.9 ms, FLOP 시간은 ~0.05 ms. tensor core는 스텝의 ~99.5% 동안 놀고 있고, 좋은 kernel의 실측 decode throughput은 312 TFLOP/s라는 카탈로그 숫자가 아니라 이 bandwidth 천장 근처에 앉는다.

For a 7B-class FP16 model with 4k context at batch 1, one token costs ≈13.5 GB of weights + ≈2.15 GB of KV cache + a 262 MB LM head read — ≈15.4 GB of traffic for ≈15 GFLOP of work. Divide: 15.4 GB ÷ 1.555 TB/s ≈ 9.9 ms, an upper bound near ~100 tok/s, while the same FLOPs would take the tensor cores ~0.05 ms. Everything in efficient inference follows from this division — quantize weights and KV (shrink the numerator), batch requests (amortize it), or restructure attention so fewer bytes are mandatory. My research lives in that numerator. 4k context, batch 1의 7B급 FP16 모델에서 token 하나의 비용은 weight ≈13.5 GB + KV cache ≈2.15 GB + LM head 읽기 262 MB — ≈15 GFLOP의 연산을 위한 ≈15.4 GB의 트래픽이다. 나눠 보면: 15.4 GB ÷ 1.555 TB/s ≈ 9.9 ms, 약 ~100 tok/s 근처의 상한이고, 같은 FLOP은 tensor core로 ~0.05 ms면 끝난다. 효율적 추론의 모든 것이 이 나눗셈에서 나온다 — weight와 KV를 quantize하고(분자 줄이기), 요청을 batching하고 (분자 분할상환), 필수 byte 자체가 줄도록 attention을 재구성하는 것. 내 연구는 그 분자 안에 산다.

Fine print on the numbers숫자에 대한 작은 글씨

Peak specs (108 SMs, 40 GB @ 1.555 TB/s, 40 MB L2, 312 TFLOP/s dense BF16/FP16 tensor core, 192 KB L1+shared per SM with ≤164 KB shared) are from NVIDIA's A100 white paper for the SXM 40 GB part. On-die bandwidth and latency figures (L2 and shared-memory throughput, ~20/200/450 ns tiers) are microbenchmark-derived ballparks that vary with access pattern and clocks — treat them as order-of-magnitude anchors, not datasheet promises. Tokens/s figures are bandwidth ceilings; real kernels land 70–90% of the way there. Peak 스펙(108 SMs, 40 GB @ 1.555 TB/s, 40 MB L2, dense BF16/FP16 tensor core 312 TFLOP/s, SM당 L1+shared 192 KB 중 ≤164 KB shared)은 SXM 40 GB 부품에 대한 NVIDIA A100 white paper 기준이다. On-die bandwidth·latency 수치(L2와 shared-memory throughput, ~20/200/450 ns 단계)는 microbenchmark에서 나온 어림값으로 접근 패턴과 클럭에 따라 달라진다 — datasheet의 약속이 아니라 자릿수 앵커로 취급하라. tok/s 수치는 bandwidth 상한이며, 실제 kernel은 그 70–90% 지점에 도달한다.

Takeaway핵심 한 줄 One token costs ≈15.4 GB of HBM traffic for ≈15 GFLOP of math — a ~9.9 ms byte-floor against ~0.05 ms of compute. Decode latency is a traffic number, not a compute number. token 하나의 비용은 ≈15 GFLOP의 연산을 위한 ≈15.4 GB의 HBM 트래픽 — ~0.05 ms짜리 연산에 ~9.9 ms의 byte 하한이 붙는다. decode latency는 compute 숫자가 아니라 트래픽 숫자다.

If the bytes set the floor, the only way forward is to change the bytes. Where is the field pushing? byte가 하한을 정한다면, 나아갈 길은 그 byte 자체를 바꾸는 것뿐이다. 지금 이 분야는 어디를 밀고 있을까?

§7Where this goes: attacking the division앞으로의 방향: 나눗셈을 공격하다

Every live direction in efficient inference is an attack on the division 15.4 GB ÷ 1.555 TB/s. Route one shrinks the numerator: quantize the weights and the KV cache — see the reviews of KIVI, KVQuant and TurboQuant — or decide some KV bytes were never needed at all (H2O, DuoAttention). Route two changes which bytes are mandatory, by redesigning the architecture around a smaller or constant-size state (Gated DeltaNet, MiniMax-01, MobileLLM). Route three changes the decode pattern itself so each weight-read produces many tokens — diffusion language models (LLaDA, Fast-dLLM). 효율적 추론의 살아 있는 방향은 전부 15.4 GB ÷ 1.555 TB/s라는 나눗셈에 대한 공격이다. 첫째 길은 분자를 줄인다: weight와 KV cache의 quantization — KIVI, KVQuant, TurboQuant 리뷰 참고 — 또는 애초에 필요 없던 KV byte를 골라내는 것(H2O, DuoAttention). 둘째 길은 필수 byte의 목록 자체를 바꾼다 — 더 작거나 고정 크기인 state를 중심으로 아키텍처를 재설계하는 것 (Gated DeltaNet, MiniMax-01, MobileLLM). 셋째 길은 decode 패턴 자체를 바꿔 weight 한 번 읽기로 여러 token을 만들어 낸다 — diffusion language model이다 (LLaDA, Fast-dLLM).

None of it is settled. Long-context attention still reads its own KV at AI ≈ 1 even at large batch, and the hardware keeps making the problem sharper: each GPU generation grows FLOPs faster than bandwidth, so the ridge point keeps moving right. The division at the top of this page is not a snapshot of 2020 silicon — it is the trendline the whole field is racing. 어느 것도 끝난 이야기가 아니다. 긴 context의 attention은 batch를 키워도 여전히 AI ≈ 1로 자기 KV를 읽고, 하드웨어는 문제를 계속 더 날카롭게 만든다: GPU 세대마다 FLOP이 bandwidth보다 빨리 자라 ridge point가 오른쪽으로 밀린다. 이 페이지 맨 위의 나눗셈은 2020년 실리콘의 스냅샷이 아니라, 이 분야 전체가 경주하고 있는 추세선이다.

Going deeper

Pull the thread실을 더 당겨보기

Primary source

NVIDIA A100 white paper

The datasheet behind every number in the die map — SM diagram, memory subsystem, tensor-core formats.Die map의 모든 숫자 뒤에 있는 datasheet — SM 다이어그램, memory 서브시스템, tensor-core 포맷.

nvidia.com · PDF
The model

Roofline (Williams et al., 2009)

The original insightful-performance-model paper — two ceilings, one x-axis, endless mileage.통찰형 성능 모델의 원조 논문 — 천장 두 개, x축 하나, 끝없는 활용도.

CACM · classic
Back of envelope

Transformer inference arithmetic

kipply's walkthrough of the same bytes-per-token accounting done here, extended to multi-GPU serving.여기서 한 것과 같은 token당 byte 회계를 multi-GPU serving까지 확장한 kipply의 워크스루.

blog · essential
Hierarchy in action

FlashAttention

What "IO-aware" means in practice: restructure attention around SMEM tiles so the mandatory HBM bytes shrink."IO-aware"가 실전에서 뜻하는 것: SMEM tile 중심으로 attention을 재구성해 필수 HBM byte를 줄인다.

arXiv 2205.14135
Study

Back to the bench

More interactive tear-downs — model anatomy, quantization pipelines, and the rest of the GPU track.더 많은 인터랙티브 분해 노트 — 모델 해부, quantization 파이프라인, GPU 트랙의 나머지.

All study notes
Research

Where this bites

KV-cache compression and diffusion-LLM acceleration — my research is an attack on the numerator of that division.KV-cache 압축과 diffusion-LLM 가속 — 내 연구는 그 나눗셈의 분자에 대한 공격이다.

Research areas