AI Sparkup

최신 AI 쉽게 깊게 따라잡기⚡

LLM 추론 성능 측정 팁 – TTFT·TPOT·처리량·비용을 함께 보기

LLM 추론 성능은 “응답 시간이 몇 초인가” 하나로 판단하면 안 된다. 긴 프롬프트를 읽는 prefill, 토큰을 하나씩 쓰는 decode, 여러 사용자를 처리하는 스케줄러, GPU 메모리, 운영 비용이 서로 다른 병목을 만든다.

먼저 나눠야 할 지표

지표의미주로 보는 병목
TTFT(Time to First Token)요청 시작부터 첫 출력 토큰까지의 시간프롬프트 길이, prefill, 큐 대기
TPOT(Time Per Output Token)첫 토큰 이후 토큰 간 평균 시간decode, 메모리 대역폭, KV 캐시
처리량(throughput)초당 처리 토큰·요청 수배칭, 동시성, GPU 활용률
tail latencyp90·p95·p99 지연긴 요청, 큐 폭주, 캐시 miss
메모리 사용량모델 가중치와 KV 캐시가 차지하는 CPU/GPU 메모리동시 사용자 수, 컨텍스트 길이
토큰당 비용하드웨어·API 비용을 처리 토큰으로 나눈 값모델 크기, idle capacity, 실패 요청

특히 prompt token과 output token을 따로 기록해야 한다. 2,000토큰 프롬프트에 20토큰 답을 쓰는 요청은 prefill이 병목이고, 20토큰 프롬프트에 2,000토큰 답을 쓰는 요청은 decode가 병목이다. 총 토큰 수가 같아도 최적화 방향이 다르다.

단일 요청 벤치마크의 기준

단일 요청에서는 generate() 전체 시간을 한 번 재는 것보다 prefill과 decode를 분리해 본다.

import time

start = time.perf_counter()
outputs = model(input_ids, use_cache=True)
prefill_end = time.perf_counter()

past_key_values = outputs.past_key_values
next_token = outputs.logits[:, -1, :].argmax(dim=-1, keepdim=True)

decode_times = []
for _ in range(max_new_tokens - 1):
    step_start = time.perf_counter()
    outputs = model(next_token, past_key_values=past_key_values, use_cache=True)
    step_end = time.perf_counter()
    decode_times.append(step_end - step_start)
    past_key_values = outputs.past_key_values
    next_token = outputs.logits[:, -1, :].argmax(dim=-1, keepdim=True)

CUDA에서는 GPU 작업이 비동기로 실행되므로 타이머 앞뒤에 torch.cuda.synchronize()를 넣어야 wall-clock 측정이 맞는다. 커널 자체만 비교할 때는 CUDA event를 쓰고, 서비스 사용자가 체감하는 시간은 wall-clock으로 본다.

운영 벤치마크에서 빠뜨리기 쉬운 것

실제 서버에서는 단일 요청보다 분포가 중요하다.

  • 요청률(request rate)과 동시 사용자 수를 고정한다.
  • prompt token과 output token 분포를 실제 트래픽에 가깝게 만든다.
  • 평균뿐 아니라 p90·p95·p99 TTFT와 inter-token latency를 기록한다.
  • error rate, timeout rate, cancellation을 따로 본다.
  • GPU 메모리 peak와 KV cache 증가량을 컨텍스트 길이별로 잰다.
  • warmup 구간을 버리고 steady-state만 비교한다.

벤치마크가 모든 프롬프트 128토큰, 모든 출력 128토큰으로만 구성되면 비교는 쉽지만 제품 트래픽을 대표하지 못한다. RAG 앱, 코딩 에이전트, 채팅 앱은 길이 분포가 완전히 다르다.

비용도 성능이다

빠른 시스템이 항상 좋은 시스템은 아니다. 예를 들어 더 큰 GPU로 TPOT를 줄였지만 idle capacity가 커지면 토큰당 비용은 나빠질 수 있다.

cost_per_output_token = hardware_cost_per_second / output_tokens_per_second

여기에 저장소, 네트워크, 오케스트레이션, 실패 요청, 엔지니어링 운영비까지 더해야 현실적인 비용이 나온다. 양자화, 작은 모델 라우팅, continuous batching, prompt caching은 모두 지연과 비용을 동시에 보되 품질 회귀를 별도 평가해야 한다.

관련 문서

참고 자료



AI Sparkup 구독하기

최신 게시물 요약과 더 심층적인 정보를 이메일로 받아 보세요! (무료)