์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

NVIDIA Jetson OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ์˜ Zero-Copy ๋ฉ”๋ชจ๋ฆฌ ๋ณ‘๋ชฉ ๋ฐ ํ”„๋ ˆ์ž„ ์ง€์—ฐ ํ•ด๊ฒฐ ๊ฐ€์ด๋“œ

๊ฒŒ์ž„๊ต์ˆ˜ 2026. 8. 25. 16:01
๋ฐ˜์‘ํ˜•

๐ŸŒ English Abstract

This technical guide explores high-performance troubleshooting strategies for frame latency and memory bottlenecks encountered when deploying OpenCV CUDA pipelines on NVIDIA Jetson embedded platforms. Although Jetson features a Unified Memory Architecture (UMA), improper use of Zero-Copy allocations, cache invalidation overheads, and synchronous CPU-GPU memory staging can introduce severe processing lags. This article breaks down the inner workings of NVMM buffers, pinned host memory, and asynchronous CUDA streams, providing actionable C++ implementation patterns and profiling techniques using NVIDIA Nsight Systems.

1. ์„œ๋ก : Jetson ์•„ํ‚คํ…์ฒ˜์™€ OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ์˜ ํ•จ์ •

NVIDIA Jetson(AGX Orin, Orin Nano, Xavier ๋“ฑ) ์‹œ๋ฆฌ์ฆˆ๋Š” ์ž„๋ฒ ๋””๋“œ ์—ฃ์ง€(Edge AI) ํ™˜๊ฒฝ์—์„œ ๋›ฐ์–ด๋‚œ ์—ฐ์‚ฐ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ PC ํ™˜๊ฒฝ์˜ ์™ธ์žฅ ๊ทธ๋ž˜ํ”ฝ ์นด๋“œ(Discrete GPU, dGPU) ์•„ํ‚คํ…์ฒ˜๋Š” CPU์˜ ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ(System RAM)์™€ GPU์˜ VRAM์ด ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด PCIe ๋ฒ„์Šค๋ฅผ ํ†ตํ•œ ๋ช…์‹œ์  ๋ฐ์ดํ„ฐ ์ „์†ก์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, NVIDIA Jetson ์‹œ๋ฆฌ์ฆˆ๋Š” **ํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ ์•„ํ‚คํ…์ฒ˜(Unified Memory Architecture, UMA)**๋ฅผ ์ฑ„ํƒํ•˜์—ฌ CPU์™€ GPU๊ฐ€ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋™์ผํ•œ LPDDR5/LPDDR4X DRAM์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ด๋ก ์  ๋ฐฐ๊ฒฝ ๋•Œ๋ฌธ์— ๋งŽ์€ ์—”์ง€๋‹ˆ์–ด๋“ค์ด "Jetson์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ๋ณต์žก๋„ ์—†์ด **Zero-Copy ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น(Zero-Copy Memory Allocation)**์„ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋ ˆ์ž„ ์ง€์—ฐ(Frame Latency)์ด ์™„์ „ํžˆ ์‚ฌ๋ผ์งˆ ๊ฒƒ"์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ๊ฐœ๋ฐœ ํ˜„์žฅ์—์„œ OpenCV CUDA ๋ชจ๋“ˆ(cv::cuda::GpuMat)์„ ์ ์šฉํ•ด ๋ณด๋ฉด, ์˜ˆ๊ธฐ์น˜ ์•Š์€ ํ”„๋ ˆ์ž„ ๋“œ๋กญ(Frame Drop)์ด๋‚˜ ๋ณต์‚ฌ ๋ณ‘๋ชฉ(Memory Copy Bottleneck), CPU-GPU ๋™๊ธฐํ™” ๋ธ”๋กœํ‚น ํ˜„์ƒ์œผ๋กœ ์ธํ•ด 30 FPS์กฐ์ฐจ ์œ ์ง€ํ•˜์ง€ ๋ชปํ•˜๋Š” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ์ƒํ™ฉ์— ์ง๋ฉดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋ณธ ๊ธ€์—์„œ๋Š” Jetson ์—ฃ์ง€ ๋””๋ฐ”์ด์Šค์—์„œ OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ• ์‹œ ๋ฐœ์ƒํ•˜๋Š” Zero-Copy ๋ฉ”๋ชจ๋ฆฌ ๋ณ‘๋ชฉ์˜ ๊ทผ๋ณธ ์›์ธ์„ ์•„ํ‚คํ…์ฒ˜ ์ˆ˜์ค€์—์„œ ๋ถ„์„ํ•˜๊ณ , ํ”„๋ ˆ์ž„ ์ง€์—ฐ์„ ๊ทน๋‹จ์ ์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ์‹ค๋ฌด ์ตœ์ ํ™” ๋ฐฉ๋ฒ•๋ก ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.



2. Jetson ๋ฉ”๋ชจ๋ฆฌ ์•„ํ‚คํ…์ฒ˜์™€ Zero-Copy์˜ ์ž‘๋™ ๋งค์ปค๋‹ˆ์ฆ˜

Zero-Copy ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Jetson ์‹œ์Šคํ…œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ์™€ **DMA(Direct Memory Access)**, ๊ทธ๋ฆฌ๊ณ  ์บ์‹œ ์ผ๊ด€์„ฑ(Cache Coherency)์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2.1. Unified Memory vs Zero-Copy (Mapped Host Memory)

NVIDIA ์‹œ์Šคํ…œ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ  ๋ฐฉ์‹์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค:

  • CUDA Unified Memory (cudaMallocManaged): ํŽ˜์ด์ง€ ํดํŠธ(Page Fault) ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. CPU๋‚˜ GPU๊ฐ€ ํ•ด๋‹น ์ฃผ์†Œ์— ์ ‘๊ทผํ•  ๋•Œ ๋Ÿฐํƒ€์ž„์ด ๋™์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ฑฐ๋‚˜ ๋งตํ•‘์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์†Œ ์ ‘๊ทผ ํŒจํ„ด์ด ๋ถˆ๊ทœ์น™ํ•  ๊ฒฝ์šฐ ์‹ฌ๊ฐํ•œ ํŽ˜์ด์ง€ ํดํŠธ ์˜ค๋ฒ„ํ—ค๋“œ(Page Fault Overhead)๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Zero-Copy Memory (cudaHostAllocMapped / Pinned Memory): CPU์˜ ํ˜ธ์ŠคํŠธ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํŽ˜์ด์ง€ ์ž ๊ธˆ(Page-Locked/Pinned) ์ƒํƒœ๋กœ ํ• ๋‹นํ•˜๊ณ , ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ์ธํ„ฐ๋ฅผ GPU ๋””๋ฐ”์ด์Šค ์ฃผ์†Œ ๊ณต๊ฐ„์— ์ง์ ‘ ๋งคํ•‘(cudaHostGetDevicePointer)ํ•ฉ๋‹ˆ๋‹ค. GPU ์—ฐ์‚ฐ ์žฅ์น˜๋Š” PCIe ๋ฒ„์Šค(๋˜๋Š” ๋‚ด๋ถ€์— ์—ฐ๊ฒฐ๋œ AXI/NVLink ๋ฒ„์Šค)๋ฅผ ํ†ตํ•ด CPU ๋ฉ”๋ชจ๋ฆฌ์— ์ง์ ‘ ๋ฐ์ดํ„ฐ **์ŠคํŠธ๋ฆฌ๋ฐ(Read/Write Streaming)**์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

2.2. ์บ์‹œ ์ผ๊ด€์„ฑ(Cache Coherency)๊ณผ Snooping ์˜ค๋ฒ„ํ—ค๋“œ

Jetson ์•„ํ‚คํ…์ฒ˜๋Š” CPU L1/L2 ์บ์‹œ์™€ GPU L2 ์บ์‹œ ๊ฐ„ ์™„๋ฒฝํ•œ ํ•˜๋“œ์›จ์–ด ์บ์‹œ ์ผ๊ด€์„ฑ(Hardware Cache Coherency)์„ ์™„์ „ํžˆ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์˜์—ญ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. CPU๊ฐ€ Zero-Copy ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ๊ฒฝ์šฐ, ๊ทธ ๋ฐ์ดํ„ฐ๋Š” CPU ์บ์‹œ ๋ผ์ธ(Cache Line)์— ๋จผ์ € ๋ž˜์น˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GPU๊ฐ€ ์ด๋ฅผ ์ฆ‰์‹œ ์ฝ์œผ๋ ค ํ•˜๋ฉด CPU ์บ์‹œ ํ”Œ๋Ÿฌ์‹œ(Cache Flush)๋‚˜ ๋ฌดํšจํ™”(Invalidation) ์ž‘์—…์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋ฉฐ ์ด ๊ณผ์ •์—์„œ **์Šค๋ˆ„ํ•‘(Snooping) ๋ณ‘๋ชฉ**์ด ๋ฐœ์ƒํ•˜์—ฌ ์—ฐ์‚ฐ ์ง€์—ฐ์ด ๊ฐ€์ค‘๋ฉ๋‹ˆ๋‹ค.

3. OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ์—์„œ์˜ ๋ณ‘๋ชฉ ์›์ธ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… (Edge Cases)

Jetson ๊ฐœ๋ฐœ์ž๋“ค์ด OpenCV cv::cuda::GpuMat์„ ๋‹ค๋ฃฐ ๋•Œ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์ €์ง€๋ฅด๋Š” ์‹ค์ˆ˜์™€ ์‹œ์Šคํ…œ์ ์ธ ๋ณ‘๋ชฉ ์š”์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

3.1. cv::cuda::GpuMat::upload()์˜ ์•”๋ฌต์  ๋“€์–ผ ํŒฉํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ

๊ฐ€์žฅ ํ”ํžˆ ๋ฒ”ํ•˜๋Š” ์‹ค๋ฌด ์˜ค๋ฅ˜๋Š” ๊ธฐ์กด CPU ํŒŒ์ดํ”„๋ผ์ธ ์ฝ”๋“œ์˜ cv::Mat์„ cv::cuda::GpuMat::upload() ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Jetson์ด UMA ๊ตฌ์กฐ๋ผ ํ• ์ง€๋ผ๋„, ์ผ๋ฐ˜ cv::Mat์€ ํŽ˜์ด์ง€ ๊ฐ€๋Šฅ ๋ฉ”๋ชจ๋ฆฌ(Pageable Memory)์— ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. CUDA ๋“œ๋ผ์ด๋ฒ„๋Š” ์ด๋ฅผ GPU๋กœ ๋ณด๋‚ผ ๋•Œ ๋‚ด๋ถ€์ ์œผ๋กœ ์ž„์‹œ ํ•€๋“œ ํ•‘ํ ๋ฒ„ํผ(Staging Buffer)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ memcpy๋ฅผ ๋จผ์ € ์ˆ˜ํ–‰ํ•œ ๋’ค DMA ์ „์†ก์„ ์ผ์œผํ‚ต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ UMA ํ™˜๊ฒฝ์ž„์—๋„ ๋ถˆํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ๊ฐ€ 2ํšŒ ์ด์ƒ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

3.2. NVMM (NVIDIA Multimedia API) ๋ฒ„ํผ ๋งคํ•‘ ๋ฏธ์ˆ™

GStreamer ๋˜๋Š” DeepStream ํŒŒ์ดํ”„๋ผ์ธ(nvarguscamerasrc, v4l2src)์„ ์‚ฌ์šฉํ•  ๋•Œ ํ•˜๋“œ์›จ์–ด ๋น„๋””์˜ค ๋””์ฝ”๋”(NVDEC)๋Š” **NVMM(NVIDIA Multimedia Memory)** ์˜์—ญ์ธ NvBufSurface ๋˜๋Š” NvBuffer๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฒ„ํผ๋ฅผ CPU ๋ฉ”๋ชจ๋ฆฌ๋กœ ํ•œ ๋ฒˆ ๊ฐ€์ ธ์™”๋‹ค๊ฐ€ ๋‹ค์‹œ OpenCV CUDA๋กœ ๋„˜๊ธฐ๋ฉด ์—„์ฒญ๋‚œ ๋ฐ์ดํ„ฐ ๋ณ‘๋ชฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋“œ์›จ์–ด ๋””์ฝ”๋”์˜ ๋ฉ”๋ชจ๋ฆฌ ๋งต ํฌ์ธํ„ฐ(EGLImage ๋˜๋Š” Direct CUDA Pointer)๋ฅผ ์ถ”์ถœํ•˜์ง€ ์•Š๊ณ  ์ค‘๊ฐ„ ๋ณ€ํ™˜ ๊ณผ์ •์„ ๊ฑฐ์น˜๋Š” ๊ฒƒ์ด ํ”„๋ ˆ์ž„ ๋“œ๋กญ์˜ ์ฃผ์›์ธ์ž…๋‹ˆ๋‹ค.

3.3. ๋™๊ธฐํ™” ๋ธ”๋กœํ‚น๊ณผ ์ŠคํŠธ๋ฆผ(Stream) ๋ถ€์žฌ

OpenCV CUDA API์˜ ๋Œ€๋ถ€๋ถ„์€ ์ŠคํŠธ๋ฆผ ์ธ์ž(cv::cuda::Stream)๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ ์ŠคํŠธ๋ฆผ(Default/Null Stream) ์ƒ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  CUDA ์ปค๋„ ํ˜ธ์ถœ ์งํ›„ **๋ฌต์‹œ์  ๋™๊ธฐํ™”(Implicit Synchronization)**๋ฅผ ์œ ๋ฐœํ•˜์—ฌ, CPU ์—ฐ์‚ฐ๊ณผ GPU ์—ฐ์‚ฐ์˜ ํŒŒ์ดํ”„๋ผ์ด๋‹(Pipelining)์ด ํŒŒ๊ดด๋˜๊ณ  GPU ์—ฐ์‚ฐ ์žฅ์น˜๊ฐ€ Idle ์ƒํƒœ์— ๋น ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



4. ์‹ค๋ฌด ์ตœ์ ํ™” ๊ตฌํ˜„: Zero-Copy ๊ธฐ๋ฐ˜ OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ํ•ด์†Œํ•˜๊ณ  ์ง€์—ฐ ์—†๋Š”(Zero-Latency) ๊ณ ์„ฑ๋Šฅ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ C++ ์‹ค๋ฌด ์ฝ”๋“œ ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

4.1. Zero-Copy Allocator๋ฅผ ํ™œ์šฉํ•œ GpuMat ์ง์ ‘ ๋งตํ•‘

CPU์™€ GPU๊ฐ€ ๊ณต์œ ํ•˜๋ฉฐ ์บ์‹œ ํ”Œ๋Ÿฌ์‹œ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด cudaHostAllocWriteCombined ํ”Œ๋ž˜๊ทธ๋ฅผ ํ™œ์šฉํ•ด Pinned Memory๋ฅผ ์ง์ ‘ ๋™์  ํ• ๋‹นํ•˜๊ณ , ํ—ค๋”๋งŒ cv::Mat๊ณผ cv::cuda::GpuMat์— ๋™์‹œ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <cuda_runtime.h>

class ZeroCopyBuffer {
public:
    void* host_ptr = nullptr;
    void* device_ptr = nullptr;
    size_t buffer_size = 0;
    cv::Mat host_mat;
    cv::cuda::GpuMat gpu_mat;

    ZeroCopyBuffer(int width, int height, int type) {
        size_t elem_size = CV_ELEM_SIZE(type);
        buffer_size = width * height * elem_size;

        // 1. WriteCombined ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CPU ์บ์‹œ ์˜ค์—ผ ๋ฐฉ์ง€ ๋ฐ GPU ์ฝ๊ธฐ ์†๋„ ๊ทน๋Œ€ํ™”
        cudaError_t err = cudaHostAlloc(&host_ptr, buffer_size, cudaHostAllocMapped | cudaHostAllocWriteCombined);
        if (err != cudaSuccess) {
            std::cerr << "cudaHostAlloc Failed: " << cudaGetErrorString(err) << std::endl;
            return;
        }

        // 2. GPU์šฉ ๋””๋ฐ”์ด์Šค ํฌ์ธํ„ฐ ์ทจ๋“ (Jetson UMA ํ™˜๊ฒฝ์—์„œ๋Š” ๋™์ผ ์ฃผ์†Œ ๊ณต๊ฐ„์œผ๋กœ ๋งคํ•‘๋จ)
        cudaHostGetDevicePointer(&device_ptr, host_ptr, 0);

        // 3. ๋ณ„๋„์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ์—†์ด ๋™์ผํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ฒ„ํผ๋ฅผ ๋ฐ”๋ผ๋ณด๋Š” Header ๋ฐ”์ธ๋”ฉ
        host_mat = cv::Mat(height, width, type, host_ptr);
        gpu_mat = cv::cuda::GpuMat(height, width, type, device_ptr);
    }

    ~ZeroCopyBuffer() {
        if (host_ptr) {
            cudaFreeHost(host_ptr);
        }
    }
};

4.2. NVMM ๋ฒ„ํผ(NvBufSurface)๋กœ๋ถ€ํ„ฐ CUDA ๋ฉ”๋ชจ๋ฆฌ Direct Zero-Copy Interop

์นด๋ฉ”๋ผ ํ”„๋ ˆ์ž„ ์ž…๋ ฅ์„ ๋ฐ›๋Š” ๊ฒฝ์šฐ GStreamer/JetPack SDK์˜ NvBufSurface ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ Direct CUDA ํฌ์ธํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ cv::cuda::GpuMat์œผ๋กœ ๋ž˜ํ•‘ํ•˜๋Š” ์ตœ์ ํ™” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

#include "nvbufsurface.h"
#include "nvbufsurftransform.h"
#include <opencv2/cudaimgproc.hpp>

// GStreamer pad probe ๋˜๋Š” Buffer Callback ๋‚ด๋ถ€
void process_nvmm_buffer(NvBufSurface* surf, int frame_idx, cv::cuda::Stream& stream) {
    NvBufSurfaceParams *params = &surf->surfaceList[frame_idx];
    
    // NvBufSurface ๋งตํ•‘ (CUDA ๊ฐ€์ƒ ์ฃผ์†Œ ํ™•์ธ)
    if (surf->memType == NVBUF_MEM_SURFACE_ARRAY || surf->memType == NVBUF_MEM_HANDLE) {
        NvBufSurfaceMap(surf, frame_idx, 0, NVBUF_MAP_READ_WRITE);
        NvBufSurfaceSyncForDevice(surf, frame_idx, 0); // ์บ์‹œ sync

        // CUDA ํฌ์ธํ„ฐ ์ง์ ‘ ํš๋“ (๋ฉ”๋ชจ๋ฆฌ Copy 0ํšŒ)
        void* cuda_dev_ptr = params->dataPtr;

        // NV12 ๋˜๋Š” YUV420 ํ˜•ํƒœ์˜ NVMM ๋ฐ์ดํ„ฐ๋ฅผ GpuMat์œผ๋กœ ๋ž˜ํ•‘
        // Height๋Š” Y์ฑ„๋„ + UV์ฑ„๋„๋กœ ์ธํ•ด 1.5๋ฐฐ ์„ค์ •
        cv::cuda::GpuMat nv12_gmat(params->height * 3 / 2, params->width, CV_8UC1, cuda_dev_ptr, params->pitch);
        
        cv::cuda::GpuMat bgr_gmat;
        // CUDA ์ปค๋„์„ ํ†ตํ•ด GPU ๋‚ด๋ถ€์—์„œ ์ง์ ‘ BGR ์ƒ‰์ƒ ๊ณต๊ฐ„ ๋ณ€ํ™˜ ์ˆ˜ํ–‰ (๋น„๋™๊ธฐ)
        cv::cuda::cvtColor(nv12_gmat, bgr_gmat, cv::COLOR_YUV2BGR_NV12, 3, stream);

        // ์ดํ›„ OpenCV CUDA ๊ฐ€๊ณต ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ˆ˜ํ–‰...
        
        NvBufSurfaceUnMap(surf, frame_idx, 0);
    }
}

4.3. ๋น„๋™๊ธฐ ํŒŒ์ดํ”„๋ผ์ธ(Asynchronous Execution Stream) ๊ตฌ์„ฑ

๋‹จ์ผ ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ ์ง€์—ฐ ์‹œ๊ฐ„์„ ์ค„์ด๋ ค๋ฉด ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜์—ฌ '์นด๋ฉ”๋ผ ํ”„๋ ˆ์ž„ ์บก์ฒ˜(DMA Host)', 'OpenCV CUDA ์—ฐ์‚ฐ(GPU)', '๊ฒฐ๊ณผ ์ถ”๋ก  ๋ฐ ์ธ์ฝ”๋”ฉ(NVDLA/TensorRT)'์„ ํ•‘ํ(Ping-Pong) ๋ฉ€ํ‹ฐ ๋ฒ„ํผ ๊ตฌ์กฐ๋กœ ์ค‘์ฒฉ(Overlap)์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ์—์„œ ๋ชจ๋“  cv::cuda ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ stream ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ฉด CPU๋Š” GPU ์—ฐ์‚ฐ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๊ณง๋ฐ”๋กœ ๋‹ค์Œ ํ”„๋ ˆ์ž„ ๋””์ฝ”๋”ฉ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ํ”„๋ ˆ์ž„๋ฅ (FPS)์ด ๋น„์•ฝ์ ์œผ๋กœ ์ƒ์Šนํ•ฉ๋‹ˆ๋‹ค.

5. Nsight Systems ๊ธฐ๋ฐ˜ ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง ๋ฐ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ์ ˆ์ฐจ

์ตœ์ ํ™” ์ž‘์—… ์ „ํ›„์˜ ์‹ค์ œ ๋ณ‘๋ชฉ ์ง€์ ์„ ์‹œ๊ฐ์ ์œผ๋กœ ๊ฒ€์ฆํ•˜๋ ค๋ฉด NVIDIA ๊ณต์‹ ํ”„๋กœํŒŒ์ผ๋Ÿฌ์ธ **Nsight Systems (nsys)**๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

5.1. nsys ํƒ€์ž„๋ผ์ธ ์ˆ˜์ง‘ ๋ช…๋ น

# Jetson ํƒ€๊ฒŸ ์žฅ๋น„์—์„œ ํ”„๋กœํŒŒ์ผ๋ง ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘
nsys profile --trace=cuda,nvtx,osrt,gstreamer \
  --output=jetson_opencv_trace \
  --delay=5 --duration=10 \
  ./your_opencv_app

5.2. ํƒ€์ž„๋ผ์ธ ๋ถ„์„ ์‹œ ์ ๊ฒ€ํ•ด์•ผ ํ•  3๊ฐ€์ง€ ํ•ต์‹ฌ ์ง€ํ‘œ

  1. cudaMemcpyAsync (Host to Device / Device to Host) ๋ธ”๋ก ํฌ๊ธฐ: ํƒ€์ž„๋ผ์ธ์ƒ์— ํฐ ํญ์˜ cudaMemcpy ๋ฒ”์ฃผ๊ฐ€ ๋ณด์ธ๋‹ค๋ฉด Zero-Copy๊ฐ€ ์‹คํŒจํ•˜๊ณ  ๋ช…์‹œ์  ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ๋ณต์‚ฌ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์ฆ๊ฑฐ์ž…๋‹ˆ๋‹ค.
  2. CUDA Stream ๊ฐ„ Gap (๋นˆ ๊ณต๊ฐ„): GPU ์ปค๋„๊ณผ ์ปค๋„ ์‚ฌ์ด์— ๋น„์–ด์žˆ๋Š” ์‹œ๊ฐ„์ด ๊ธธ๋‹ค๋ฉด CPU ์ธก์˜ cv::Mat ์ƒ์„ฑ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๋ณ‘๋ชฉ์ด๋‚˜, cudaStreamSynchronize() ํ˜ธ์ถœ๋กœ ์ธํ•œ CPU ๋ธ”๋กœํ‚น์ด ๋ฐœ์ƒํ•˜๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค.
  3. Unified Memory Page Fault Event: Trace ํƒ€์ž„๋ผ์ธ ํ•˜๋‹จ์— Gpu Page Fault ์ด๋ฒคํŠธ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋‹ค์ˆ˜ ์ฐํžŒ๋‹ค๋ฉด Managed Memory ์‚ฌ์šฉ ์กฐ๊ฑด์„ ์žฌ๊ฒ€ํ† ํ•˜๊ณ  Pinned Mapped Memory ๋ฐฉ์‹์œผ๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


6. ๊ฒฐ๋ก : Jetson ๋””๋ฐ”์ด์Šค์šฉ ์‹ค๋ฌด ๊ฒ€์ฆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

NVIDIA Jetson ํ”Œ๋žซํผ ์ƒ์—์„œ OpenCV CUDA ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•  ๋•Œ ๋ณ‘๋ชฉ ์—†๋Š” ์ดˆ๊ณ ์† ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ํ•ต์‹ฌ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜๋“œ์‹œ ์‹ค๋ฌด์— ์ ์šฉํ•˜์‹ญ์‹œ์˜ค.

ํ•ญ๋ชฉ ๊ถŒ์žฅ ์„ค์ • / ๊ธฐ๋ฒ• ์ตœ์ ํ™” ํšจ๊ณผ
๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น cudaHostAllocWriteCombined + cudaHostGetDevicePointer CPU/GPU ๊ฐ„ ๋ช…์‹œ์  ๋ณต์‚ฌ ์™„์ „ ์ œ๊ฑฐ ๋ฐ CPU ์บ์‹œ ํ”Œ๋Ÿฌ์‹œ ๋ฐฉ์ง€
์นด๋ฉ”๋ผ/๋””์ฝ”๋”ฉ GStreamer NVMM (NvBufSurface) direct pointer mapping ๋น„๋””์˜ค ๋””์ฝ”๋” -> CUDA ์—ฐ์‚ฐ ๊ฐ„ Zero-Copy ๋‹ฌ์„ฑ
CUDA ์‹คํ–‰ cv::cuda::Stream ๋น„๋™๊ธฐ ๊ฐ์ฒด ์ „ํŒŒ CPU-GPU Pipeline Overlapping์„ ํ†ตํ•œ ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ ์ง€์—ฐ ์ตœ์†Œํ™”
์„ฑ๋Šฅ ์ธก์ • NVIDIA Nsight Systems (nsys) ํƒ€์ž„๋ผ์ธ ์ถ”์  ๋ณ‘๋ชฉ ๊ตฌ๊ฐ„(Memcpy, CPU Blocking) ์ˆ˜์น˜์  ๋ถ„์„ ๋ฐ ๊ฒ€์ฆ

Jetson์˜ ์•„ํ‚คํ…์ฒ˜์  ํŠน์„ฑ์ธ UMA๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ™œ์šฉํ•˜๊ณ , ์•”๋ฌต์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ๋ฐ ์บ์‹œ ๋™๊ธฐํ™” ์ด์Šˆ๋ฅผ ์ œ์–ดํ•จ์œผ๋กœ์จ ์—ฃ์ง€ AI ํ™˜๊ฒฝ์—์„œ๋„ ์ตœ๊ณ  ์ˆ˜์ค€์˜ FPS์™€ ์ตœ์ ์˜ ํ”„๋ ˆ์ž„ ์ง€์—ฐ ์‹œ๊ฐ„์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•