본문으로 건너뛰기

[vllm] vLLM 성능 최적화: GPU-CPU 간 불필요한 동기화 제거하기

PR 링크: vllm-project/vllm#42347 상태: Merged | 변경: +129 / -108

들어가며

LLM 추론 엔진인 vLLM은 높은 처리량과 낮은 지연 시간을 목표로 합니다. 하지만 GPU와 CPU 간의 데이터 전송이나 동기화(Synchronization)는 종종 성능 병목의 주범이 됩니다. 특히 .any()와 같은 연산은 GPU에서 CPU로 결과를 가져오기 위해 파이프라인을 멈추고 동기화를 강제하는데, 이는 작은 배치 사이즈에서 치명적인 성능 저하를 유발합니다. 이번 PR은 vLLM의 다양한 모듈에서 이러한 불필요한 GPU-CPU 동기화를 제거하여 성능을 개선하는 과정을 담고 있습니다.

코드 분석

1. LoRA 연산 최적화 (vllm/lora/ops/triton_ops/utils.py)

기존 코드에서는 torch.tensor()를 사용하여 CPU 데이터를 GPU로 복사했습니다. 이는 동기화 이슈를 유발할 수 있는 방식입니다.

Before:

lora_ptr_tensor = torch.tensor(tensor_ptrs, device=device, dtype=torch.uint64)

After:

lora_ptr_tensor = async_tensor_h2d(tensor_ptrs, dtype=torch.uint64, device=device)

async_tensor_h2d를 사용함으로써 호스트에서 디바이스로의 비동기 전송을 활용하여 동기화 대기 시간을 줄였습니다.

2. 모델 모델링 및 유틸리티 (vllm/model_executor/models/)

다양한 모델 파일에서 MultiModalFieldConfigkeep_on_cpu=True 설정을 통해 불필요한 GPU 메모리 할당 및 전송을 방지했습니다. 또한 glm4_1v.py 등에서는 non_blocking=True 옵션을 활용하여 데이터 전송 효율을 높였습니다.

Before:

num_patches=MultiModalFieldConfig.batched("image"),

After:

num_patches=MultiModalFieldConfig.batched("image", keep_on_cpu=True),

3. 비트 연산 최적화 (vllm/model_executor/models/bert.py)

torch.ones_like를 생성하고 비트 연산을 수행하던 방식에서 상수를 직접 사용하는 방식으로 변경하여 메모리 할당을 줄였습니다.

Before:

ids_mask = (torch.ones_like(input_ids, dtype=torch.int32, device=input_ids.device) << TOKEN_TYPE_SHIFT)

After:

ids_mask = 1 << TOKEN_TYPE_SHIFT

왜 이게 좋은가

이번 최적화의 핵심 교훈은 '동기화 지점을 최소화하라'는 것입니다. 특히 리뷰 과정에서 논의된 isinf().any()와 같은 조건문은 GPU 연산 자체보다 CPU로 결과를 가져오는 동기화 비용이 훨씬 큽니다.

성능 수치를 보면, 조건부 체크를 제거하고 clamp를 무조건 수행하는 방식이 clean한 입력 데이터에 대해서도 약 2배에서 최대 8배까지 빠른 성능을 보였습니다. 이는 GPU 연산이 가볍더라도 동기화가 발생하면 전체 파이프라인이 멈추기 때문입니다. 비동기 전송(non_blocking=True)과 불필요한 텐서 생성을 피하는 것만으로도 추론 엔진의 처리량을 크게 향상시킬 수 있습니다.

참고 자료

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글