📄 v1개정 이력 보기
Voronoi GPU 실처리 벤치마크 — RTX 5060 JFA 50초 병목 분석
초록
hb5u RTX 5060에서 운영 중인 Voronoi GPU 서비스(voronoi_gpu_service.py)를 실제 이미지(5712×4284 iPhone 16 사진)로 첫 실측 테스트한 결과를 기록한다. cell_count=3000 기준 GPU 처리 50.4초, 총 51.3초가 소요됐다. 프론트엔드에서 '0ms GPU 처리'로 표시된 원인 및 JFA Python 루프 구조가 병목임을 분석한다.
테스트 개요
- 일시: 2026-07-18 KST
- 서비스:
voronoi_gpu_service.py— hb5u RTX 5060, port 8892 - 테스트 이미지:
IMG_2718.jpeg— iPhone 16 촬영, 5712×4284 (5.3MB) - 파라미터:
cell_count=3000,max_dim=4000,show_edges=true,edge_opacity=0.22,edge_color=white - 테스트 방법: hb5u 로컬에서
curl -X POST http://localhost:8892/api/voronoi
실측 결과
| 항목 | 값 |
|---|---|
GPU 처리 시간 (X-Processing-Ms) |
50,402 ms (50.4초) |
총 소요 시간 (X-Total-Ms) |
51,280 ms (51.3초) |
| 입력 해상도 | 5712×4284 → 3999×3000 (max_dim=4000 축소) |
| 출력 파일 | voronoi_result.png — 907,024 bytes (3999×3000 RGB) |
| GPU | RTX 5060 (X-GPU: RTX5060) |
| HTTP 응답 코드 | 200 OK |
병목 분석 — JFA Python 루프
코드(render_voronoi_gpu) 흐름:
CPU: Sobel 엣지 검출 → 씨앗 샘플링 (68% 엣지 + 32% 랜덤)
GPU: seed_map 초기화 → JFA pass 반복 → 셀 평균 색상 → 엣지 오버레이
CPU: PNG 인코딩
JFA 핵심 루프:
step = max(w, h) // 2 # 3999x3000 → step=2000
while step >= 1:
seed_map = _jfa_pass(seed_map, sc, w, h, step, x_idx, y_idx)
step //= 2
seed_map = _jfa_pass(seed_map, sc, w, h, 1, x_idx, y_idx)
- 3999×3000 이미지에서 step: 2000→1000→500→…→1 = 12 JFA pass
- 각
_jfa_pass내부에서 8방향(dy×dx 조합) Python 루프 반복 - cupy 배열 연산 자체는 GPU에서 실행되지만, pass 단위 Python 제어 흐름이 CPU↔GPU 동기화를 매 pass마다 유발
cp.cuda.Stream.null.synchronize()호출은render_voronoi_gpu마지막에만 있지만,_jfa_pass내부의.any()호출이 암묵적 동기화를 일으킴
개선 가능 방향
| 방안 | 예상 효과 |
|---|---|
| cupy RawKernel — 단일 CUDA 커널로 JFA pass 통합 | 10~50배 단축 예상 |
| 이미지 해상도 사전 축소 (max_dim 1000~2000) | 선형 비례 단축 |
| cell_count 감소 (3000→500) | 부분 단축 |
'0ms GPU 처리' 표시 원인 추정
프론트엔드 VoronoiConverter.tsx에서 응답 헤더 X-Processing-Ms를 읽지 않거나,
health 폴링 응답과 처리 시간 표시 로직이 혼선됐을 가능성이 있다.
실측 결과 GPU 처리는 50초 이상이며 0ms는 오측이다.
결론
RTX 5060 GPU가 실제 탑재되어 cupy JFA 연산이 GPU에서 실행되지만, Python 수준의 pass 단위 제어가 병목 — 단일 CUDA 커널화가 실용 속도를 위한 필수 개선 과제다. 현재 cell_count=3000 기준 50초는 실서비스 UX로는 수용 불가. max_dim 축소 또는 커널화 병행 필요.
