为啥函数第一次调用比第二次和第三次调用花费更多的时间等等?
Posted
技术标签:
【中文标题】为啥函数第一次调用比第二次和第三次调用花费更多的时间等等?【英文标题】:Why function first-time calling costs much more time than the second time calling it and third and so on?为什么函数第一次调用比第二次和第三次调用花费更多的时间等等? 【发布时间】:2017-10-09 01:22:21 【问题描述】:这是我基于 OpenCV 的代码:
int main()
clock_t start, stop;
Mat img = imread("lena.jpg", IMREAD_GRAYSCALE);
img.convertTo(img, CV_32F, 1.0);
float *imgInP = (float *)img.data; // get the input data point
Mat imgOut = Mat::zeros(Size(img.rows, img.cols), CV_32F); // create output mat
float *imgOutP = (float *)imgOutP.data; // get the output data point
// test several calling of opencv boxFilter
start = clock();
//blur(img, imgOut, Size(31, 31));
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cout << "BoxFilter on OpenCV 1 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
start = clock();
//blur(img, imgOut, Size(31, 31));
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cout << "BoxFilter on OpenCV 2 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
start = clock();
//blur(img, imgOut, Size(31, 31));
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cout << "BoxFilter on OpenCV 3 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
return 0;
这是上述程序的输出:
OpenCV 1 上的 BoxFilter:72.368ms
OpenCV 2 上的 BoxFilter:0.495 毫秒
OpenCV 3 上的 BoxFilter:0.403 毫秒
为什么第一次调用 boxFilter 所花费的时间(72.368 毫秒)比第二次(0.495 毫秒)和第三次(0.403 毫秒)要多得多。
更重要的是,如果我在第三次调用 boxFilter 时更改输入图像,输出也不会改变。所以,可能不是图片数据缓存的因素……
感谢您的建议。
我的系统是 Ubuntu 14.04,i5-4460,12GB RAM,OpenCV 版本:3.1,cmake 版本:3.2,g++ 版本:4.8.4
下面是我的 cmake 文件:
cmake_minimum_required(VERSION 3.7)
project(boxfilterTest)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
include_directories($OpenCV_INCLUDE_DIRS)
set(SOURCE_FILES main.cpp)
add_executable(boxfilterTest $SOURCE_FILES)
target_link_libraries(boxfilterTest $OpenCV_LIBS)
IDE 是 CLion。
【问题讨论】:
一个词:缓存。 抱歉再问一个问题,谁的缓存?指令缓存还是数据缓存?当我第三次调用boxFilter更改输入图像数据时,结果没有任何变化,时间也比第一次调用要小很多。 也许它会生成运行时代码?您可以通过执行另一个类似的过滤器来检查这一点,例如 30x31。 倒霉...,我把过滤器大小从 31, 31 改成了 15, 15,还是不行... 【参考方案1】:差异的原因是时序是由于指令缓存和数据缓存。可以通过强制将矩阵重新分配到不同的大小(例如调整图像大小)来验证数据缓存。如果在对boxFilter
的不同调用之间调整图像大小,则boxFilter
调用的执行时间会变得非常接近。这是演示上述现象的示例代码。
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
clock_t start, stop;
Mat img = imread("lena.jpg", IMREAD_GRAYSCALE);
img.convertTo(img, CV_32F, 1.0);
float *imgInP = (float *)img.data; // get the input data point
Mat imgOut = Mat::zeros(Size(img.rows, img.cols), CV_32F); // create output mat
float *imgOutP = (float *)imgOut.data; // get the output data point
// test several calling of opencv boxFilter
start = clock();
//blur(img, imgOut, Size(31, 31));
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cv::resize(img, img, cv::Size(), 1.1, 1.1); //Force data re-allocation
cout << "BoxFilter on OpenCV 1 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
start = clock();
//blur(img, imgOut, Size(31, 31));
//GaussianBlur(img, imgOut, Size(31, 31), 0.5);
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cv::resize(img, img, cv::Size(), 0.909, 0.909); //Force data re-allocation
cout << "BoxFilter on OpenCV 2 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
start = clock();
//blur(img, imgOut, Size(31, 31));
boxFilter(img, imgOut, CV_32F, Size(31, 31));
stop = clock();
cout << "BoxFilter on OpenCV 3 : " << 1000.0 * (stop - start) / CLOCKS_PER_SEC << " ms" << endl;
return 0;
程序输出:
无需重新分配数据:
OpenCV 1 上的 BoxFilter:2.459 毫秒
OpenCV 2 上的 BoxFilter:1.599 毫秒
OpenCV 3 上的 BoxFilter:1.568 毫秒
数据重新分配:
OpenCV 1 上的 BoxFilter:2.225 毫秒
OpenCV 2 上的 BoxFilter:2.368 毫秒
OpenCV 3 上的 BoxFilter:2.091 毫秒
【讨论】:
这并不能解释第一次调用 OP 时的 72 毫秒延迟。一定有其他的影响,因为 70 毫秒是一个很长的时间。 感谢您的回复。但是,我想知道为什么第一次调用也要花费这么多时间。我已将编译器从“nvcc”更改为“g++”,但看起来这不是确切的因素。再次感谢您的建议。【参考方案2】:嗯,我想可能是指令缓存造成的(毕竟CPU中有*MB L2缓存)。但我不知道如何验证和改进它。
【讨论】:
你能分享你运行代码的系统的规格吗?此外,OpenCV 的编译方式也是观察到的执行速度的决定因素。以上是关于为啥函数第一次调用比第二次和第三次调用花费更多的时间等等?的主要内容,如果未能解决你的问题,请参考以下文章
c语言中如何在一个字符串中查找/出现的位置?需要第一次出现和第二次出现中间的内容和第二次出现和第三