๐ English Abstract
High-resolution real-time image processing using OpenCV CUDA often suffers from performance bottlenecks during Host-to-Device (H2D) data transfers over the PCIe bus. This article explores how to eliminate transfer latencies by leveraging Pinned Memory (Page-locked Memory) via cv::cuda::HostMem and overlapping memory copy with GPU execution using CUDA Asynchronous Streams (cv::cuda::Stream). It provides deep-dive troubleshooting strategies, practical C++ implementation patterns, and edge-case optimizations for embedded systems like NVIDIA Jetson.
1. ๊ฐ์: GPU ์ฐ์ฐ๋ณด๋ค ๋ฌด์์ด ๋ฐ์ดํฐ ์ ์ก ๋ณ๋ชฉ (PCIe Bottleneck)
์ค์๊ฐ ์์ ์ฒ๋ฆฌ ์์คํ (Real-time Image Processing System) ๊ตฌ์ถ ์, ๋ง์ ์์ง๋์ด๋ค์ด OpenCV CUDA ๋ชจ๋์ ๋์ ํ๋ฉด ์ฆ๊ฐ์ ์ธ ํ๋ ์๋ ์ดํธ(FPS) ์์น์ ๊ธฐ๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ค์ ๊ณ ํด์๋(4K ์ด์) ์นด๋ฉ๋ผ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๋ค ๋ณด๋ฉด, GPU ์ปค๋(Kernel) ์ํ ์๊ฐ์ ๋ถ๊ณผ ์ ๋ฐ๋ฆฌ์ด(ms)์ ๋ถ๊ณผํจ์๋ ์ ์ฒด ํ์ดํ๋ผ์ธ์์ ํ๋ ์ ๋๋กญ(Frame Drop)์ด ๋ฐ์ํ๋ ํ์์ ์์ฃผ ๋ชฉ๊ฒฉํ๊ฒ ๋ฉ๋๋ค.
์ด๋ฌํ ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ GPU์ ์ฐ์ฐ ๋ฅ๋ ฅ ๋ถ์กฑ์ด ์๋๋ผ, CPU์ ํธ์คํธ ๋ฉ๋ชจ๋ฆฌ(Host Memory)์์ GPU์ ์ฅ์น ๋ฉ๋ชจ๋ฆฌ(Device Memory)๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ณผ์ ์์ ๋ฐ์ํ๋ ๋ณ๋ชฉ ํ์(Host-to-Device Bottleneck)์ ์์ต๋๋ค. PCIe(Peripheral Component Interconnect Express) ๋ฒ์ค ๋์ญํญ์ ํ๊ณ์ ๋๊ธฐ์(Synchronous) ๋ฐ์ดํฐ ๋ณต์ฌ ๋ฐฉ์์ด ๊ฒฐํฉํ๋ฉด, GPU๋ ์ฐ์ฐ์ ๋๊ธฐํ๋ฉฐ ๋๊ฒ(Idle) ๋๊ณ CPU ์ญ์ ๋ธ๋กํน(Blocking) ์ํ์ ๋น ์ง๋๋ค.
๋ณธ ๊ธ์์๋ ์ด ๋ณ๋ชฉ์ ๊ทผ๋ณธ์ ์ผ๋ก ํด๊ฒฐํ๊ธฐ ์ํด Pinned Memory(Page-locked Memory)์ ๋ฉ์ปค๋์ฆ์ ํํค์น๊ณ , CUDA ๋น๋๊ธฐ ์คํธ๋ฆผ(Asynchronous Stream)์ ๊ฒฐํฉํ์ฌ ์ ์ก๊ณผ ์ฐ์ฐ์ ์์ ํ๊ฒ ์ค๋ฒ๋ฉ(Overlap)ํ๋ ๊ณ ์ฑ๋ฅ ํ์ดํ๋ผ์ธ ๊ตฌ์ถ๋ฒ์ ๋ค๋ฃน๋๋ค.
2. ๋ฉ์ปค๋์ฆ ๋ถ์: Pageable Memory vs Pinned Memory
๊ธฐ๋ณธ์ ์ผ๋ก ์ด์์ฒด์ (OS)๊ฐ ํ ๋นํ๋ ์ผ๋ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ๋ ํ์ด์ง ๊ฐ๋ฅ ๋ฉ๋ชจ๋ฆฌ(Pageable Memory)์ ๋๋ค. OS ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์(Virtual Memory Manager)๋ ํ์์ ๋ฐ๋ผ ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋์คํฌ์ ์ค์ ์์ญ(Swap Space)์ผ๋ก ๋ด๋ณด๋ผ(Page-out) ์ ์์ต๋๋ค.
๊ธฐ๋ณธ cv::Mat ๋ฐ์ดํฐ ์ ์ก์ ๋นํจ์จ์ฑ
์ด์์ฒด์ ์ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ํน์ฑ ๋๋ฌธ์, GPU DMA(Direct Memory Access) ์ปจํธ๋กค๋ฌ๋ Pageable Memory์์ ์ง์ ์ฅ์น ๋ฉ๋ชจ๋ฆฌ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๊ธฐ๋ณธ cv::Mat ๊ฐ์ฒด๋ฅผ GPU๋ก ์ ์ก(upload)ํ ๋ ๋ด๋ถ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ 2๋จ๊ณ ๊ณผ์ ์ด ๊ฐ์ ๋ก ์คํ๋ฉ๋๋ค:
- ์์ Pinned Memory ํ ๋น ๋ฐ ๋ณต์ฌ: CUDA ๋๋ผ์ด๋ฒ๊ฐ ํธ์คํธ ์ธก์ ์คํ ์ด์ง ๋ฒํผ(Staging Buffer) ์ญํ ์ Pinned Memory๋ฅผ ์์ ํ ๋นํ๊ณ , Pageable ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ด๊ณณ์ผ๋ก ๋ณต์ฌํฉ๋๋ค (CPU L3 ์บ์/๋ฉ๋ชจ๋ฆฌ ๋์ญํญ ์๋น).
- PCIe DMA ์ ์ก: ์คํ ์ด์ง ๋ฒํผ์ ๋ฐ์ดํฐ๋ฅผ DMA๋ฅผ ํตํด GPU VRAM(Device Memory)์ผ๋ก ์ ์กํฉ๋๋ค.
์ด ๊ณผ์ ์์ ๋ฐ์ํ๋ ๋ถํ์ํ ๋ฉ๋ชจ๋ฆฌ ๋ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ(Memcpy)์ ๋๊ธฐํ ๋๊ธฐ ์๊ฐ์ ๊ณ ์ฃผ์ฌ์จ ์์ ์ฒ๋ฆฌ์์ ์ฌ๊ฐํ ์ง์ฐ์๊ฐ(Latency)์ ์ด๋ํฉ๋๋ค.
Pinned Memory (Page-locked Memory)์ ์๋ฆฌ
Pinned Memory๋ OS์๊ฒ "์ด ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง๋ ์ ๋๋ก ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ค์์ ํ์ง ๋ง๊ณ ๋ฌผ๋ฆฌ RAM ์์น์ ๊ณ ์ (Lock)ํด๋ผ"๋ผ๊ณ ๋ช
๋ นํ์ฌ ์์ฑํ ๋ฉ๋ชจ๋ฆฌ์
๋๋ค. OpenCV์์๋ cv::cuda::HostMem ํด๋์ค๋ฅผ ํตํด ์ด๋ฅผ ์ง์ํฉ๋๋ค.
- DMA ์ง์ฃผํ: GPU DMA ์ปจํธ๋กค๋ฌ๊ฐ ํธ์คํธ RAM์ ๊ณ ์ ๋ ๋ฌผ๋ฆฌ ์ฃผ์์ ์ง์ ์ ๊ทผํ์ฌ PCIe ๋ฒ์ค๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํฉ๋๋ค. Intermediate Staging Buffer ๋ณต์ฌ๊ฐ ์๋ต๋ฉ๋๋ค.
- ๋น๋๊ธฐ ์ ์ก ๊ฐ๋ฅ: ๋ฉ๋ชจ๋ฆฌ ์์น๊ฐ ๊ณ ์ ๋์ด ์์ผ๋ฏ๋ก CPU ์์ ๊ณผ GPU ๋ฐ์ดํฐ ์ ์ก ์์ ์ ๋น๋๊ธฐ(Asynchronous)๋ก ์๋ฒฝํ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.
3. ์ค์ ์ต์ ํ ๊ตฌํ: cv::cuda::HostMem๊ณผ cv::cuda::Stream ํ์ดํ๋ผ์ด๋
์ค์๊ฐ ํ์ดํ๋ผ์ธ์์ ์ฑ๋ฅ์ ๊ทน๋ํํ๋ ค๋ฉด cv::cuda::HostMem ์ฌ์ฉ์ ๊ทธ์น์ง ์๊ณ , CUDA ๋น๋๊ธฐ ์คํธ๋ฆผ(Stream)์ ํ์ฉํด ํ๋ ์ $N$์ ์ ์ก, ํ๋ ์ $N-1$์ GPU ์ฐ์ฐ, ํ๋ ์ $N-2$์ ๊ฒฐ๊ณผ ์์ (D2H)์ ๋์์ ์งํํ๋ ๋๋ธ/ํธ๋ฆฌํ ๋ฒํผ๋ง(Double/Triple Buffering) ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํด์ผ ํฉ๋๋ค.
๋น๋๊ธฐ ํ์ดํ๋ผ์ธ C++ ์์ค์ฝ๋ ์์
#include <opencv2/opencv.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudawarping.hpp>
#include <iostream>
#include <vector>
constexpr int STREAM_COUNT = 2; // Double Buffering
struct FrameBuffer {
cv::cuda::HostMem host_pinned_in; // Pinned Memory for Input
cv::cuda::HostMem host_pinned_out; // Pinned Memory for Output
cv::cuda::GpuMat gpu_in;
cv::cuda::GpuMat gpu_processed;
cv::cuda::Stream stream;
};
int main() {
int width = 3840;
int height = 2160;
// 1. ๋ฒํผ ๋ฐ ์คํธ๋ฆผ ์ด๊ธฐํ (์ฌ์ ํ ๋น)
std::vector<FrameBuffer> buffers(STREAM_COUNT);
for (int i = 0; i < STREAM_COUNT; ++i) {
// PAGE_LOCKED ์ต์
์ ํตํ Pinned Memory ํ ๋น
buffers[i].host_pinned_in = cv::cuda::HostMem(height, width, CV_8UC3, cv::cuda::HostMem::AllocType::PAGE_LOCKED);
buffers[i].host_pinned_out = cv::cuda::HostMem(height, width, CV_8UC1, cv::cuda::HostMem::AllocType::PAGE_LOCKED);
}
// ๋ฐ์ดํฐ ์์ง ๋ผ์ด๋ธ ๋ฃจํ (๊ฐ์)
int frame_idx = 0;
while (true) {
int buf_idx = frame_idx % STREAM_COUNT;
FrameBuffer& buf = buffers[buf_idx];
// ์ด์ ํ๋ ์์ ์คํธ๋ฆผ ์์
์๋ฃ ์ฌ๋ถ ํ์ธ ๋ฐ ๋๊ธฐํ
buf.stream.waitForCompletion();
// [CPU Step] ์นด๋ฉ๋ผ ๋ฑ ํ๋ ์ Grabber๋ก๋ถํฐ Pinned Memory ํฌ์ธํฐ๋ก ์ง๋์
cv::Mat frame_view = buf.host_pinned_in.createMatHeader();
// simulate_camera_capture(frame_view.data); // Zero-copy into Pinned Memory
// [Non-blocking CUDA Steps]
// 1. Host-to-Device ๋น๋๊ธฐ ์ ์ก
buf.gpu_in.upload(buf.host_pinned_in, buf.stream);
// 2. GPU ์ฐ์ฐ ์ปค๋ ํ ๋ฑ๋ก (๋น๋๊ธฐ)
cv::cuda::cvtColor(buf.gpu_in, buf.gpu_processed, cv::COLOR_BGR2GRAY, 0, buf.stream);
cv::cuda::gaussianBlur(buf.gpu_processed, buf.gpu_processed, cv::Size(5, 5), 1.5, 0, cv::BORDER_DEFAULT, buf.stream);
// 3. Device-to-Host ๋น๋๊ธฐ ์ ์ก
buf.gpu_processed.download(buf.host_pinned_out, buf.stream);
// CPU๋ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ฆ์ ๋ค์ ํ๋ ์ ๋ฃจํ๋ก ์ง์
ํ์ฌ ๋ค๋ฅธ ์คํธ๋ฆผ ์ง์
frame_idx++;
if (frame_idx > 1000) break; // ํ
์คํธ ์ข
๋ฃ ์กฐ๊ฑด
}
// ๋ชจ๋ ์คํธ๋ฆผ ์์
์์ ๋๊ธฐ
for (auto& buf : buffers) {
buf.stream.waitForCompletion();
}
return 0;
}
4. ์ค๋ฌด ํธ๋ฌ๋ธ์ํ ๋ฐ ์ฃ์ง ์ผ์ด์ค (Troubleshooting & Edge Cases)
1) Pinned Memory ๊ณผ๋ค ํ ๋น์ผ๋ก ์ธํ ์์คํ ๋ฝ์ (System OOM & Thrashing)
Pinned Memory๋ OS๊ฐ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ๋ก ํ์ด์ง ์์์ ์ํํ ์ ์๋ Non-paged Pool ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์ฌ์ฉํฉ๋๋ค. ์ค์๊ฐ ์ฑ๋ฅ์ ๊ทน๋ํํ๊ณ ์ ๋ชจ๋ ํ๋ ์ ๋ฒํผ๋ฅผ Pinned Memory๋ก ๊ฑฐ๋ํ๊ฒ ํ ๋น(์: ์์ญ ๊ธฐ๊ฐ๋ฐ์ดํธ)ํ๋ฉด, OS ์์ฒด์ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ฌ์ฉํ ์ ์๋ ์ค์ํ ๊ฐ๋ฅํ ๋ฌผ๋ฆฌ RAM ์์ญ์ด ๊ทน๋จ์ ์ผ๋ก ์ค์ด๋ญ๋๋ค.
ํด๊ฒฐ์ฑ
: ์ ํ๋ฆฌ์ผ์ด์
์์ ์์ ์ ring-buffer ํํ์ cv::cuda::HostMem์ ์ต์ํ์ ๊ฐ์(์: 2~4๊ฐ)๋ง ๋ฏธ๋ฆฌ ํ๋ฆฌ์ดํฌ๋ก์ผ์ด์
(Pre-allocation)ํ์ฌ ์ฌ์ฌ์ฉํ์ญ์์ค. ๋์ ํ ๋น/ํด์ (malloc/free)๋ฅผ ๋ฃจํ ๋ด๋ถ์์ ๋ฐ๋ณตํ๋ฉด cudaHostAlloc ์์ฒด์ ๋ฌด๊ฑฐ์ด ์์คํ
์ฝ ์ปจํ
์คํธ ์ค์์นญ ๋น์ฉ ๋๋ฌธ์ ์คํ๋ ค ์ฑ๋ฅ์ด ์
ํ๋ฉ๋๋ค.
2) ์๋ฒ ๋๋ ํ๋ซํผ(NVIDIA Jetson)์์์ ์ ๋ก์นดํผ(Zero-Copy) ๋ฉ๋ชจ๋ฆฌ ์ฐฉ๊ฐ
NVIDIA Jetson Xavier / Orin ๋ฑ๊ณผ ๊ฐ์ ์๋ฒ ๋๋ SoC ํ๊ฒฝ์ CPU์ GPU๊ฐ ๋์ผํ ๋ฌผ๋ฆฌ DRAM์ ๊ณต์ ํ๋ ํตํฉ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ(Unified Memory Architecture, UMA)๋ฅผ ๊ฐ์ง๋๋ค. discrete GPU(๋ฐ์คํฌํฑ/์๋ฒ์ฉ NVLink, PCIe ์นด๋) ํ๊ฒฝ๊ณผ๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ๋ฉ์ปค๋์ฆ์ด ๋ค๋ฆ ๋๋ค.
Jetson ํ๊ฒฝ์์๋ AllocType::SHARED ์ต์
์ด๋ Unified Memory๋ฅผ ํตํด upload()/download() ํธ์ถ ์์ฒด๋ฅผ ์์ ์๋ตํ ์ ์์ต๋๋ค. Discrete GPU ์ ์ฉ ์ต์ ํ ๊ธฐ๋ฒ(PCIe ๋์ญํญ ๊ทน๋ํ์ฉ Pinned Memory)์ Jetson์ ๊ทธ๋๋ก ์ ์ฉํ๋ฉด ๋ถํ์ํ ๋ฉ๋ชจ๋ฆฌ ์บ์ ํ๋ฌ์(Cache Flush) ๋ฐ ๋๊ธฐํ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก target hardware์ ๋ฐ๋ฅธ ๋ถ๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
3) ๋ฉํฐ์ค๋ ๋ ๋ฉํฐ์คํธ๋ฆผ ๊ฒฝ์ ์ํ (Data Race & Synchronization Failures)
ํ๋ ์์ ์์ ํ๋ ์์ฐ์ ์ค๋ ๋(Producer Thread)์ GPU๋ก ์ด์ก ๋ฐ ์ฐ์ฐ์ ์ง์ํ๋ ์๋น์ ์ค๋ ๋(Consumer Thread)๊ฐ ๋ถ๋ฆฌ๋์ด ์์ ๋, Pinned ๋ฉ๋ชจ๋ฆฌ์ ํฌ์ธํฐ ์ ๊ทผ ์์ ๋๊ธฐํ๊ฐ ์ ๋๋ก ์ด๋ฃจ์ด์ง์ง ์์ผ๋ฉด **ํ๋ฉด ๊นจ์ง(Tearing)**์ด๋ **๋ฉ๋ชจ๋ฆฌ ์ค์ผ(Corruption)**์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
ํด๊ฒฐ์ฑ
: cv::cuda::Stream::query()๋ฅผ ํ์ฉํ ๋น๋๊ธฐ ํด๋ง ์ํ ์ฒดํฌ๋ cv::cuda::Event๋ฅผ ์ด์ฉํด GPU ์ ์ก ์์
์ด ์์ ํ ๋๋ ํ ์ค๋ ๋๊ฐ ๋ฒํผ์ ๋ฎ์ด์ฐ๋๋ก ๋น๋๊ธฐ ์ด๋ฒคํธ๋ฅผ ๋๊ธฐํ ํ๋๊ทธ๋ก ํ์ฉํ์ธ์.
- ์ผ๋ฐ
cv::Mat์ ๋ฃจํ ๋ด๋ถ์์ ์ง์ upload()ํ์ง ๋ง๊ณ ,cv::cuda::HostMem์ ์ฌ์ฉ ์ค์ธ๊ฐ? cv::cuda::Stream๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ CPU-GPU ์ ์ก ๋ฐ ์ฐ์ฐ์ ๋น๋๊ธฐํ ํ์๋๊ฐ?- ๋ฉ๋ชจ๋ฆฌ ํ ๋น(Allocation)๊ณผ ํด์ (Deallocation)๊ฐ ํซ๋ฃจํ(Hot Loop) ๋ฐ์์ ์ฌ์ ์๋ฃ๋์๋๊ฐ?
5. ์ฑ๋ฅ ์ธก์ ๋ถ์ (Benchmarking)
์๋ ํ๋ 4K (3840x2160, RGB 3์ฑ๋) ํด์๋ ์์์ ๊ธฐ์ค์ผ๋ก, ๋๊ธฐ์ ์ผ๋ฐ ๋ฉ๋ชจ๋ฆฌ ํ์ดํ๋ผ์ธ๊ณผ ๋น๋๊ธฐ Pinned Memory ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ๋ ์ดํด์ ๋ฐ ํ๋ ์ ์ฒ๋ฆฌ ์๋๋ฅผ ๋น๊ตํ ์์ ๊ฒฐ๊ณผ์ ๋๋ค.
| ์ ์ฉ ๋ฐฉ์ (Strategy) | H2D ์ ์ก ์ง์ฐ (Latency) | GPU ์ฒ๋ฆฌ ๋ฐ D2H | ์ ์ฒด FPS (Frame Rate) |
|---|---|---|---|
| 1. ๋๊ธฐ์ + Pageable (๊ธฐ๋ณธ) | 18.5 ms (Blocking) | 4.2 ms | ~44 FPS |
| 2. ๋๊ธฐ์ + Pinned Memory | 8.1 ms (Blocking) | 4.2 ms | ~81 FPS |
| 3. ๋น๋๊ธฐ Stream + Pinned (์ต์ ํ) | 0 ms (Overlapped) | 4.2 ms (Overlapped) | 230+ FPS |
NVIDIA Nsight Systems ํ์๋ผ์ธ ํ๋กํ์ผ๋ฌ๋ก ๋ถ์ ์, ์ต์ ํ ์ ์ฉ ํ์๋ ์ ์ก ํ์๋ผ์ธ(MemCpy H2D)๊ณผ ์ปค๋ ์คํ ํ์๋ผ์ธ(Kernel Execution)์ด ์๋ฒฝํ ์์ง์ผ๋ก ์ค์ฒฉ(Overlap)๋์ด PCIe ์ ์ก ์ง์ฐ์ด ์ ์ฒด ํ์ดํ๋ผ์ธ ์คํ ์๊ฐ์์ ์์ ํ ์ํ(Hide)๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
6. ๊ฒฐ๋ก
OpenCV CUDA ๋ชจ๋์ ํ์ฉํ ๊ณ ์ฑ๋ฅ ์์ ์ฒ๋ฆฌ ์์คํ
์์ CPU-GPU ๊ฐ ๋ฐ์ดํฐ ์ ์ก์ ์์คํ
์ ์ฒด์ ์ฑ๋ฅ์ ๊ฒฐ์ ์ง๋ ํต์ฌ ์ ์ด ์์์
๋๋ค. cv::Mat์ ๋จ์ upload() ๊ตฌ์กฐ์์ ๋ฒ์ด๋ cv::cuda::HostMem์ ํตํ Pinned Memory ํ์ฉ๊ณผ cv::cuda::Stream ๊ธฐ๋ฐ์ ๋น๋๊ธฐ ํ์ดํ๋ผ์ด๋์ ๋์
ํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ณต์กํ ์ปค๋ ์๊ณ ๋ฆฌ์ฆ ์์ ์์ด ์ฒ๋ฆฌ๋์ 2~4๋ฐฐ ์ด์ ๊ทน์ ์ผ๋ก ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ํคํ ์ฒ ์ค๊ณ ์ด๊ธฐ๋ถํฐ ๋ฉ๋ชจ๋ฆฌ ํ๋ฆฌ์ดํฌ๋ก์ผ์ด์ ๊ณผ ๋ฉํฐ ์คํธ๋ฆผ ๊ตฌ์กฐ๋ฅผ ๋ฐ์ํ์ฌ ์ค์๊ฐ ์์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ์จ์ ์ฑ๋ฅ์ 100% ์ด๋์ด๋ด์๊ธฐ ๋ฐ๋๋๋ค.