๐ English Abstract
High-speed machine vision inspection systems using Python OpenCV CUDA often suffer from severe FPS drops due to PCIe bandwidth bottlenecks during CPU-to-GPU data transfers. This article addresses the root cause of transfer overheads when moving frame buffers into GpuMat and provides a practical troubleshooting guide. By implementing Pinned Memory (Page-locked Memory) combined with CUDA Asynchronous Streams, high-throughput pipeline parallelism can be achieved to maximize GPU utilization.
์ค๋งํธ ํฉํ ๋ฆฌ ๋ฐ ๋ฐ๋์ฒดยท๋์คํ๋ ์ด ์ ์กฐ ๊ณต์ ์ ๊ณ ์ ๋จธ์ ๋น์ (Machine Vision) ๊ฒ์ฌ ์์คํ ์ ๊ตฌ์ถํ ๋, ๋จ์ ์๊ฐ๋น ์ฒ๋ฆฌํ ์ ์๋ ํ๋ ์ ์(FPS, Frames Per Second)๋ ์ ์ฒด ์์ฐ ํ์ดํธ ํ์(Takt Time)์ ๊ฒฐ์ ํ๋ ํต์ฌ ์งํ์ ๋๋ค. 4K ํด์๋ ์ด์์ ๊ณ ํด์๋ ์ฐ์ ์ฉ ์นด๋ฉ๋ผ(Industrial Camera)์์ ์ด๋น 100~200 ํ๋ ์ ์ด์ ์์ง๋๋ ์ด๋ฏธ์ง๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ฏธ์ธ ๊ฒฐํจ ๊ฒ์ฌ(Defect Inspection)ํ๊ธฐ ์ํด ๋ง์ ์์ง๋์ด๋ค์ด NVIDIA CUDA ๊ธฐ๋ฐ์ OpenCV CUDA ๋ชจ๋์ ์ฌ์ฉํฉ๋๋ค.
ํ์ง๋ง ๊ฐ๋ ฅํ GPU ํ๋์จ์ด(์: RTX 4090 ๋๋ A100/L40s)๋ฅผ ํ์ฌํ์์๋ ๋ถ๊ตฌํ๊ณ , ๋จ์ํ๊ฒ cv2.cuda_GpuMat ๊ฐ์ฒด๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ๋ฆฌ๊ณ ๋ด๋ฆฌ๋ ๋ฐฉ์์ผ๋ก๋ ๋ชฉํ FPS์ ์ ๋ฐ์๋ ๋ฏธ์น์ง ๋ชปํ๋ ํ์์ ํํ ๊ฒช๊ฒ ๋ฉ๋๋ค. ํ๊ฒ ์๊ณ ๋ฆฌ์ฆ์ GPU ์ปค๋ ์ฐ์ฐ ์๊ฐ์ ์ ๋ฐ๋ฆฌ์ด(ms)์ ๋ถ๊ณผํ์ง๋ง, ์ ์ฒด ํ์ดํ๋ผ์ธ์ ์ง์ฐ ์๊ฐ(Latency)์ CPU ๋ฉ๋ชจ๋ฆฌ(Host Memory)์ GPU ๋ฉ๋ชจ๋ฆฌ(Device Memory) ๊ฐ์ ๋ฐ์ดํฐ ์ ์ก ๋ณ๋ชฉ(PCIe Bottleneck)์ผ๋ก ์ธํด ์ฌ๊ฐํ๊ฒ ์ฆ๊ฐํ๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ณธ ํฌ์คํ ์์๋ Python ํ๊ฒฝ์์ OpenCV CUDA ๋ชจ๋์ ์ฌ์ฉํ ๋ ๋ฐ์ํ๋ ๋ฐ์ดํฐ ์ ์ก ๋ณ๋ชฉ์ ์์ธ์ ๊น์ด ์๊ฒ ๋ถ์ํ๊ณ , ๊ณ ์ ๋ฉ๋ชจ๋ฆฌ(Pinned Memory/Page-locked Memory)์ CUDA ๋น๋๊ธฐ ์คํธ๋ฆผ(Asynchronous Stream)์ ๊ฒฐํฉํ์ฌ ์ค์๊ฐ ๊ฒ์ฌ ํ์ดํ๋ผ์ธ์ FPS๋ฅผ ๊ทน๋ํํ๋ ํธ๋ฌ๋ธ์ํ ๊ณผ์ ์ ์์ธํ๊ฒ ๋ค๋ฃน๋๋ค.
1. CPU-GPU ๋ฉ๋ชจ๋ฆฌ ์ ์ก ๋ณ๋ชฉ์ ๊ทผ๋ณธ ์์ธ ๋ถ์
ํ์ค์ ์ธ Python OpenCV ํ๊ฒฝ์์ ์ผ๋ฐ์ ์ธ Numpy ๋ฐฐ์ด(Array) ํํ์ ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ GPU ๋ฉ๋ชจ๋ฆฌ์ธ GpuMat์ผ๋ก ์
๋ก๋ํ ๋ ๋ฐ์ํ๋ ๋ด๋ถ์ ์ธ ์ฒ๋ฆฌ ๊ณผ์ ์ ์ดํดํด์ผ ํฉ๋๋ค.
๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง(Virtual Memory Page)์ CPU ์คํ ์ด์ง ๋ฒํผ
์ผ๋ฐ์ ์ผ๋ก OS๊ฐ ํ ๋นํ๋ ์์คํ ๋ฉ๋ชจ๋ฆฌ๋ ํ์ด์ง ๊ฐ๋ฅ ๋ฉ๋ชจ๋ฆฌ(Pageable Memory) ํํ์ ๋๋ค. ์ด์์ฒด์ (OS)๋ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ์ ์ํด ํ๋ก์ธ์ค์ ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง๋ฅผ ๋์คํฌ์ ์ค์ ๊ณต๊ฐ(Swap Space)์ผ๋ก ์ฎ๊ธฐ๊ฑฐ๋ ๊ฐ์ ์ฃผ์๋ฅผ ๋ฌผ๋ฆฌ ์ฃผ์๋ก ๋์ ์ผ๋ก ๋งคํํฉ๋๋ค. ๋ฌธ์ ์ ์ GPU์ DMA(Direct Memory Access) ์ปจํธ๋กค๋ฌ๊ฐ ๋ฌผ๋ฆฌ์ ์ฃผ์๊ฐ ๊ณ ์ ๋์ง ์์ ํ์ด์ง ๊ฐ๋ฅ ๋ฉ๋ชจ๋ฆฌ์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ฌ ์ ์๋ค๋ ์ ์ ๋๋ค.
๋ฐ๋ผ์ gpu_mat.upload(cpu_frame)์ ํธ์ถํ ๋ ๋ฐํ์ ๋ด๋ถ์์๋ ๋ค์๊ณผ ๊ฐ์ ์จ๊ฒจ์ง ์ค๋ฒํค๋๊ฐ ๋ฐ์ํฉ๋๋ค:
- ์์ ๊ณ ์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น: ๋๋ผ์ด๋ฒ ๋ด๋ถ์์ ํธ์คํธ ๋ฉ๋ชจ๋ฆฌ ๋ด์ ์ผ์์ ์ธ ํ์ด์ง ๊ณ ์ (Page-locked) ์คํ ์ด์ง ๋ฒํผ(Staging Buffer)๋ฅผ ์์ฑํฉ๋๋ค.
- CPU ๋ด ๋ณต์ฌ(Host-to-Host Copy): ํ์ด์ง ๊ฐ๋ฅ ๋ฉ๋ชจ๋ฆฌ์ ์์นํ
cpu_frame๋ฐ์ดํฐ๋ฅผ ๋ฐฉ๊ธ ์์ฑํ ์คํ ์ด์ง ๋ฒํผ๋ก ๋ณต์ฌํฉ๋๋ค. - PCIe Bus DMA ์ ์ก: ์คํ ์ด์ง ๋ฒํผ์์ PCIe ๋ฒ์ค๋ฅผ ํ๊ณ GPU ๋๋ฐ์ด์ค ๋ฉ๋ชจ๋ฆฌ(VRAM)๋ก ๋น๋ก์ DMA ์ ์ก๋ฉ๋๋ค.
- ๋๊ธฐ์ ๋๊ธฐ(Synchronous Blocking): CPU ์ค๋ ๋๋ ์ด ์ ์ก ๊ณผ์ ์ด ๋ชจ๋ ์๋ฃ๋ ๋๊น์ง ์ฐจ๋จ(Block) ์ํ๋ก ๋๊ธฐํฉ๋๋ค.
upload() ๋ฐ download() ํธ์ถ๋ก ์ธํด CPU ์ค๋ ๋๊ฐ ๋ถํ์ํ๊ฒ ๋๊ธฐํ๋ฉฐ, ๋งค ํ๋ ์๋ง๋ค ์์ ์คํ
์ด์ง ๋ฒํผ๋ฅผ ํ ๋น ๋ฐ ๋ณต์ฌํ๋ ์ค๋ฒํค๋๋ก ์ธํด PCIe ๋์ญํญ(PCIe Bandwidth)์ ์ ๋ฐ ์ดํ๋ง ํ์ฉํ๊ฒ ๋ฉ๋๋ค.
2. ์ต์ ํ ์๋ฃจ์ : Pinned Memory์ Async Stream์ ๊ตฌ์กฐ
๋ฉ๋ชจ๋ฆฌ ์ ์ก ๋ณ๋ชฉ ํ์์ ์์ ํ ์ ๊ฑฐํ๊ธฐ ์ํด์๋ Pinned Memory(HostMem)์ CUDA Asynchronous Stream์ด๋ผ๋ ๋ ๊ฐ์ง ํต์ฌ ๊ธฐ์ ์ ๋ฐ๋์ ํจ๊ป ์ ์ฉํด์ผ ํฉ๋๋ค.
1) Pinned Memory (Page-locked Memory)์ ๋์
Pinned Memory๋ ์ด์์ฒด์ ๊ฐ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง ๋งค์ปค๋์ฆ์์ ์ ์ธ์์ผ ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์๊ตฌ ๊ณ ์ (Page-locked)ํด๋ ๋ฉ๋ชจ๋ฆฌ ์์ญ์
๋๋ค. OpenCV์์๋ cv2.cuda.HostMem ํด๋์ค๋ก ์ด๋ฅผ ์ ๊ณตํฉ๋๋ค. Pinned Memory๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ CPU ์คํ
์ด์ง ๋ฒํผ๋ก์ ์ค๊ฐ ๋ณต์ฌ ๊ณผ์ ์ด ์๋ต๋์ด GPU DMA ์ปจํธ๋กค๋ฌ๊ฐ ์ง์ ํธ์คํธ ๋ฉ๋ชจ๋ฆฌ์์ VRAM์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ต๊ณ ์๋๋ก ์ธ์ถํ ์ ์์ต๋๋ค.
2) CUDA ๋น๋๊ธฐ ์คํธ๋ฆผ(Stream) ๊ธฐ๋ฐ ํ์ดํ๋ผ์ด๋
CUDA ์คํธ๋ฆผ์ ์์ฐจ์ ์ผ๋ก ์คํ๋๋ GPU ์์ ์ ํ(Queue)์ ๋๋ค. ์๋ก ๋ค๋ฅธ ๋ ๋ฆฝ์ ์ธ ์คํธ๋ฆผ์ ํ์ฉํ๋ฉด [์นด๋ฉ๋ผ ํ๋ ์ ์บก์ฒ ๋ฐ HostMem ๋ณต์ฌ] - [PCIe Bus ๋น๋๊ธฐ ๋ฉ๋ชจ๋ฆฌ ์ ์ก] - [GPU ์์๋ธ/์ ์ฒ๋ฆฌ ์ฐ์ฐ] - [๊ฒฐ๊ณผ ๋น๋๊ธฐ ๋ค์ด๋ก๋] ๊ณผ์ ์ ๋์์ ์คํ(Concurrent Execution)ํ๋ ํ์ดํ๋ผ์ด๋(Pipelining)์ ์์ฑํ ์ ์์ต๋๋ค.
3. ์ค์ ๊ตฌํ: Python OpenCV Pinned Memory ๋น๋๊ธฐ ์ต์ ํ ์ฝ๋
์๋ ์ฝ๋๋ ๋น๋๊ธฐ ์คํธ๋ฆผ๊ณผ Pinned Memory๋ฅผ ์ ์ฉํ์ฌ ๋จธ์ ๋น์ ํ๋ ์ ์์ง ๋ฐ ๊ฒ์ฌ ์ ์ฒ๋ฆฌ๋ฅผ ์ต์ ํํ ์ค์ Python ์์ ์ฝ๋์ ๋๋ค.
import cv2
import numpy as np
class AsyncVisionInspector:
def __init__(self, width: int, height: int, channels: int = 1):
self.width = width
self.height = height
self.channels = channels
# 1. Pinned Memory (Page-locked) ๋ฒํผ ์์ฑ
# HOST_MEM_PAGE_LOCKED ํ๋๊ทธ๋ฅผ ํตํด OS๊ฐ ํ์ด์งํ์ง ๋ชปํ๋๋ก ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๊ณ ์
self.pinned_host_mem = cv2.cuda.HostMem(
(self.height, self.width, self.channels),
dtype=np.uint8,
alloc_type=cv2.cuda.HOST_MEM_PAGE_LOCKED
)
# Pinned Memory๋ฅผ ์ฐธ์กฐํ๋ Numpy Array ๋ํผ ์์ฑ (Zero-copy ๋ทฐ)
self.pinned_array = self.pinned_host_mem.createPageLockedMat()
# 2. CUDA Device Memory (GpuMat) ๋ฐ Stream ๊ฐ์ฒด ์์ฑ
self.gpu_frame = cv2.cuda_GpuMat(self.height, self.width, cv2.CV_8UC1 if channels==1 else cv2.CV_8UC3)
self.gpu_result = cv2.cuda_GpuMat(self.height, self.width, cv2.CV_8UC1 if channels==1 else cv2.CV_8UC3)
# ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ ์ฉ CUDA ์คํธ๋ฆผ
self.stream = cv2.cuda.Stream()
# GPU ํํฐ ์์ฑ (์: ๊ฐ์ฐ์์ ๋ธ๋ฌ ์ ์ฒ๋ฆฌ)
self.gaussian_filter = cv2.cuda.createGaussianFilter(
srcType=cv2.CV_8UC1,
dstType=cv2.CV_8UC1,
ksize=(5, 5),
sigma1=1.5
)
def process_frame_async(self, raw_frame_bytes: bytes):
"""
๋น๋๊ธฐ ์คํธ๋ฆผ ๊ธฐ๋ฐ์ ๊ณ ์ ์ ์ก ๋ฐ ๊ฒ์ฌ ์ฐ์ฐ ํ์ดํ๋ผ์ธ
"""
# [Step 1] ์นด๋ฉ๋ผ ํ๋ ์ ๋ฒํผ๋ฅผ Pinned Memory๋ก ๋น ๋ฅด๊ฒ ๋ณต์ฌ
# (Pageable ๋ฉ๋ชจ๋ฆฌ ๊ฐ ๋ณต์ฌ๋ณด๋ค ์๋ฑํ ๋น ๋ฆ)
np.copyto(self.pinned_array, np.frombuffer(raw_frame_bytes, dtype=np.uint8).reshape(self.height, self.width, self.channels))
# [Step 2] Pinned Memory -> GpuMat ๋น๋๊ธฐ ์
๋ก๋ (Host to Device)
# uploadAsync๋ CPU ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์ฆ์ ๋ฐํ๋จ
self.gpu_frame.uploadAsync(self.pinned_host_mem, self.stream)
# [Step 3] GPU ๋ด๋ถ ๋น๋๊ธฐ ์ฐ์ฐ ์ํ (Stream์ ์ฐ์ฐ ํing)
self.gaussian_filter.apply(self.gpu_frame, self.gpu_result, stream=self.stream)
# [Step 4] GpuMat -> Pinned Memory ๋น๋๊ธฐ ๋ค์ด๋ก๋ (Device to Host)
self.gpu_result.downloadAsync(self.pinned_host_mem, self.stream)
# [Step 5] CPU ์์
์ด GPU ์ฐ์ฐ๊ณผ ๋๊ธฐํ๋์ด์ผ ํ ์์ ์ ์คํธ๋ฆผ ๋๊ธฐํ ํธ์ถ
self.stream.waitForCompletion()
# ์ต์ข
๊ฒฐ๊ณผ๋ฌผ ๋ฐํ (Pinned Memory์ ๋ฐ์ดํฐ ์ ๊ทผ)
return self.pinned_array
4. ์ฑ๋ฅ ๋น๊ต ๋ถ์ (Performance Benchmark)
4K ์ด๋ฏธ์ง(3840x2160, Mono 8bit)๋ฅผ ๊ธฐ์ค์ผ๋ก ๋๊ธฐ์ ๋๊ธฐ ๋ณํ ๋ฐฉ์๊ณผ Pinned Memory ๊ธฐ๋ฐ ๋น๋๊ธฐ ์คํธ๋ฆผ ๋ฐฉ์์ ์ฑ๋ฅ์ ๋น๊ต ์ธก์ ํ๋ฉด ์๋์ ๊ฐ์ด ํ๊ฒฉํ ์ฐจ์ด๊ฐ ๋ํ๋ฉ๋๋ค.
| ๊ตฌ๋ถ (Processing Type) | Host-to-Device Latency | Device-to-Host Latency | ์ต๋ ์ฒ๋ฆฌ ์๋ (FPS) | CPU ์ ์ ์จ (CPU Utilization) |
|---|---|---|---|---|
| ์ผ๋ฐ ๋๊ธฐ์ (Pageable + upload) | 8.5 ms | 9.1 ms | ์ฝ 52 FPS | ๋์ (Polled Wait) |
| ์ต์ ํ ๋น๋๊ธฐ์ (Pinned + Stream) | 2.1 ms | 2.3 ms | ์ฝ 210 FPS | ๋ฎ์ (Asynchronous) |
Pinned Memory๋ฅผ ๋์ ํ์ ๋ ์ ์ก ์ง์ฐ ์๊ฐ์ด ์ฝ 75% ์ด์ ๊ฐ์ํ์์ผ๋ฉฐ, ๊ฒฐ๊ณผ์ ์ผ๋ก ์ ์ฒด ๊ฒ์ฌ ํ์ดํ๋ผ์ธ์ ์๋๊ฐ 4๋ฐฐ ์ด์ ์์นํ์ฌ ์นด๋ฉ๋ผ ์ผ์์ ์ต๋ ํ๋ ์ ์ ์ก ์๋๋ฅผ ์์ ํ ์์ฉํ ์ ์๊ฒ ๋์์ต๋๋ค.
5. ์ค๋ฌด ์์ง๋์ด๋ง ํธ๋ฌ๋ธ์ํ ๋ฐ ์ฃ์ง ์ผ์ด์ค (Edge Cases)
ํ์ฅ์์ ๊ณ ์ ์์คํ ์ ๋๋ฒ๊น ํ๊ณ ์ด์ํ ๋ ๋ฐ๋์ ์ฃผ์ํด์ผ ํ ๊ธฐ์ ์ ์ฃ์ง ์ผ์ด์ค ๋ฐ ์ํ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1) Pinned Memory ๊ณผ๋ค ํ ๋น์ผ๋ก ์ธํ ์์คํ OOM (Out Of Memory)
Pinned Memory(Page-locked Memory)๋ OS์ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋์์์ ์์ ํ ์ ์ธ๋ฉ๋๋ค. ์ฆ, ์ด ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ฆ๊ฐํ๋ฉด ์ด์์ฒด์ ๊ฐ ์์คํ ๋ฌผ๋ฆฌ RAM์ ์ค์(Swap)์ผ๋ก ์ ์ฐํ๊ฒ ํ์ฉํ์ง ๋ชปํฉ๋๋ค. ๋๋ฌด ๋ง์ ํ๋ ์ ๋ฒํผ๋ฅผ Pinned Memory๋ก ์ ์ ํ ๊ฒฝ์ฐ, ์์คํ ์ ์ฒด RAM์ด ๋ถ์กฑํด์ ธ OS ๋ ๋ฒจ์ ์ปค๋ ํจ๋(Kernel Panic)์ด๋ Out Of Memory(OOM) ํฌ๋ฌ๊ฐ ๊ฒ์ฌ ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ ์ข ๋ฃ์ํฌ ์ ์์ต๋๋ค.
[ํด๊ฒฐ์ฑ ]: ๋ฌดํ์ ๋ฒํผ๋ฅผ ์์ฑํ์ง ๋ง๊ณ , Ring Buffer ๊ตฌ์กฐ๋ก ์ ํ๋ ๊ฐ์(์: 3~5๊ฐ)์ Pinned HostMem ๊ฐ์ฒด๋ง ๋ฏธ๋ฆฌ ํ ๋น(Pre-allocation)ํ์ฌ ์ฌ์ฌ์ฉํด์ผ ํฉ๋๋ค.
2) Python GIL(Global Interpreter Lock) ๋ฐ ์ค๋ ๋ ๋๊ธฐํ ๋ฌธ์
Python ํ๊ฒฝ์์๋ GIL๋ก ์ธํด C++ native ํ๊ฒฝ ๋๋น ๋ฉํฐ์ค๋ ๋ ๋ณ๋ ฌํ์ ์ ์ฝ์ด ์กด์ฌํฉ๋๋ค. cv2.cuda.Stream์ ์ฌ์ฉํ๋๋ผ๋ Python ๋จ์์ ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ธ๋กํน๋๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋ค๋ฅธ ์ค๋ ๋์ ๋น๋๊ธฐ ์์
์ด ๋ฉ์ถ ์ ์์ต๋๋ค.
[ํด๊ฒฐ์ฑ ]: ์นด๋ฉ๋ผ ํ๋ ์ ํ๋(Grabber Thread), CUDA ์ ์ก ๋ฐ ์ฐ์ฐ(Worker Thread), ๊ฒฐ๊ณผ๋ฅผ Display/DB์ ์ ์ฅํ๋(Writer Thread)๋ฅผ Python Multi-Processing ๋๋ C++ ๋ํผ(Pybind11) ๋ ์ด์ด๋ก ์์ ํ ๊ฒฉ๋ฆฌํ๋ ์ค๊ณ๋ฅผ ๊ถ์ฅํฉ๋๋ค.
3) NVIDIA Nsight Systems๋ฅผ ํ์ฉํ ํ๋กํ์ผ๋ง ๊ฒ์ฆ
์ต์ ํ๊ฐ ์ค์ ๋ก ์๋ํ๊ณ ์๋์ง ํ์ธํ๋ ค๋ฉด NVIDIA Nsight Systems ํ๋กํ์ผ๋ฌ tool์ ์ฌ์ฉํ์ฌ ํ์๋ผ์ธ์ ๋ถ์ํด์ผ ํฉ๋๋ค. ํ์๋ผ์ธ ์์์ MemCpy (Host-to-Device) ์์ญ๊ณผ CUDA Kernel ์ฐ์ฐ ์์ญ์ด ์ํ์ ์ผ๋ก ์ค๋ฒ๋ฉ(Overlap)๋์ด ํ์ ์์ด ์ ์ก๊ณผ ์ฐ์ฐ์ด ๋ณ๋ ฌ๋ก ์คํ๋๊ณ ์๋์ง ๋์ผ๋ก ๊ฒ์ฆํด์ผ ํฉ๋๋ค.
๊ฒฐ๋ก : ๋จธ์ ๋น์ ํ์ดํ๋ผ์ธ ์ต์ ํ ์์ฝ
Python ๊ธฐ๋ฐ OpenCV CUDA ๋จธ์ ๋น์ ๊ฒ์ฌ ์์คํ ์์ GPU ์ฐ์ฐ ์ฑ๋ฅ์ ์จ์ ํ ํ์ฉํ๊ธฐ ์ํด์๋ ๋จ์ํ ๊ณ ์ฑ๋ฅ ๊ทธ๋ํฝ ์นด๋๋ฅผ ์ฅ์ฐฉํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ถ์กฑํฉ๋๋ค. ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์์ VRAM์ผ๋ก ์ด๋ํ๋ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ชฉ์ ๋ชฉ์ ์ ๊ฑฐํด์ผ ํฉ๋๋ค.
cv2.cuda.HostMem์ ์ฌ์ฉํด Pinned Memory(Page-locked Memory)๋ฅผ ํ ๋นํจ์ผ๋ก์จ ๋ถํ์ํ Host-side ์์ ๋ณต์ฌ ์ค๋ฒํค๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค.cv2.cuda.Stream์ ํตํดuploadAsync, GPU Kernel ์ฐ์ฐ,downloadAsync๋ฅผ ๋น๋๊ธฐ๋ก ์ฐ๊ฒฐํ๊ณ ํ์ดํ๋ผ์ด๋์ ์์ฑํฉ๋๋ค.- ๊ณ ์ ๋ฉ๋ชจ๋ฆฌ๋ ๋ฌผ๋ฆฌ RAM ์์์ ์ ์ ํ๋ฏ๋ก ๋ง ๋ฒํผ(Ring Buffer) ์ฌ์ฌ์ฉ ํจํด์ ์ ์ฉํ์ฌ OOM ์์ธ ๋ฐ์์ ์ฐจ๋จํฉ๋๋ค.
์ด๋ฌํ ์ต์ ํ ๊ธฐ๋ฒ์ ๊ณ ์ ๊ฒ์ฌ ๋ผ์ธ์ ์ ์ฉํ๋ฉด CPU-GPU ๊ฐ ๋ฐ์ดํฐ ์ด๋ ๋ณ๋ชฉ ํ์์ ์๋ฒฝํ ํด๊ฒฐํ๊ณ ์ด๊ณ ์ ๋จธ์ ๋น์ ์๋ฃจ์ ์ ์์ ์ ์ผ๋ก ๊ตฌ๋ํ ์ ์์ต๋๋ค.