我使用 CUDA 编写了一个屏蔽模板匹配算法。正如我所测试的,该算法的功能是正确的。然而,当我尝试使用以下代码将算法的 CUDA 实现与 OpenCV 实现进行比较时,出现了一些奇怪的情况。
for (int i = 0; i < 200; i++){
// ---------------------------------------- GPU --------------------------------------------
double t1 = (double)cv::getTickCount();
gpu_img.upload(img);
matcher->match(gpu_img, gpu_result); // gpu
gpu_result.download(result);
t1 = ((double)cv::getTickCount() - t1) / cv::getTickFrequency();
std::cout << t1 * 1000 << std::endl;
double max_val_gpu;
double min_val_gpu;
cv::Point max_loc_gpu;
cv::minMaxLoc(result, &min_val_gpu, &max_val_gpu, 0, &max_loc_gpu);
std::cout << "min_val_gpu: " << min_val_gpu << " max_val_gpu: " << max_val_gpu << std::endl;
std::cout << "max_loc_gpu: " << max_loc_gpu.x << " " << max_loc_gpu.y << std::endl;
// -------------------------------------------------------------------------------------------
// ---------------------------------------- CPU -----------------------------------------------
double t4 = (double)cv::getTickCount();
cv::matchTemplate(img, temp, result, 5, mask); // cpu
t4 = ((double)cv::getTickCount() - t4) / cv::getTickFrequency();
std::cout << "cpu version: " << t4 * 1000 << " ms" << std::endl;
double min_val_cpu;
double max_val_cpu;
cv::Point max_loc_cpu;
cv::minMaxLoc(result, &min_val_cpu, &max_val_cpu, 0, &max_loc_cpu);
std::cout << "min_val_cpu: " << min_val_cpu << " max_val_cpu: " << max_val_cpu << std::endl;
std::cout << "max_loc_cpu: " << max_loc_cpu.x << " " << max_loc_cpu.y << std::endl;
// ---------------------------------------------------------------------------------------------
}
经过多次迭代后,CUDA函数的时间消耗突然增加(从4ms到20ms)。
我测试了其他 CUDA 函数,包括简单的向量相加和 OpenCV CUDA API。我发现所有这些功能都可能被 CPU 代码减慢。
如果我在每次迭代中运行CPU函数两次,则CUDA内核的时间消耗在第55次迭代左右突然增加(也从4ms增加到20ms)。即使 CPU 代码被单个语句 waitKey(100) 替换,CUDA 内核仍然会变慢。
代码运行在Win10、cuda 11.1;由 vs2015 & nvcc 11.1 编译。 GPU是RTX 3060。
使用“nsys profile”分析代码的性能。
似乎所有 CUDA API 和内核都变慢了。
当 CUDA 内核缺乏要处理的数据时,NVIDIA GPU 似乎会降低其时钟频率。这个问题可以通过设置 Nvidia 控制面板并使用
nvidia-smi -lgc
修复时钟频率来解决。