【问题标题】:sending oclMat to function creates huge difference in runtime将 oclMat 发送到函数会在运行时产生巨大差异
【发布时间】:2015-05-19 07:18:28
【问题描述】:

我写了一个带有 3 个输入的函数(屏蔽):

  1. inputOCL - 一个 oclMat
  2. comparisonValue - 双精度值
  3. method - 确定比较方法的 int 变量

对于我的示例,我选择了 method=1,它代表 CMP_GT,测试 inputOCL>comparisonValue element-wise。

该函数的目的是将 inputOCL 中不符合给定 copmarison 的所有元素清零。

这里是函数掩码:

void masking(cv::ocl::oclMat inputOCL, double comparisonValue, int method){
// NOTE: method can be set to 1-->5 corresponding to (==, >, >=, <, <=, !=)

cv::ocl::oclMat valueOCL(inputOCL.size(), inputOCL.type());
valueOCL.setTo(cv::Scalar(comparisonValue));
cv::ocl::oclMat logicalOCL;
cv::ocl::compare(inputOCL, valueOCL, logicalOCL, method);
logicalOCL.convertTo(logicalOCL, inputOCL.type());
cv::ocl::multiply(logicalOCL, inputOCL, inputOCL);  
cv::ocl::multiply(1 / 255.0, inputOCL, inputOCL); }

在对函数计时时,我发现在运行以下代码时运行函数或直接运行计算之间的运行时差异很大:

int main(int argc, char** argv){

double value1 = 1.23456789012345;
double value2 = 1.23456789012344;

// initialize matrix
cv::Mat I(5000, 5000, CV_64F, cv::Scalar(value1));
// copy input to GPU
cv::ocl::oclMat inputOCL(I);
int method = 1;
static double start_TIMER;

// computation done in function
start_TIMER = cv::getTickCount();
masking(inputOCL, value2, method);
std::cout << "\nFunction runtime = " << ((double)(cv::getTickCount() - start_TIMER)) / cv::getTickFrequency() << " Seconds\n";

// direct computation
start_TIMER = cv::getTickCount();
cv::ocl::oclMat valueOCL(inputOCL.size(), inputOCL.type());
valueOCL.setTo(cv::Scalar(value2));
cv::ocl::oclMat logicalOCL;
cv::ocl::compare(inputOCL, valueOCL, logicalOCL, method);
logicalOCL.convertTo(logicalOCL, inputOCL.type());
cv::ocl::multiply(logicalOCL, inputOCL, inputOCL);
cv::ocl::multiply(1 / 255.0, inputOCL, inputOCL);
std::cout << "\nDirect runtime = " << ((double)(cv::getTickCount() - start_TIMER)) / cv::getTickFrequency() << " Seconds\n";
}

运行时可以在这个截图中看到:

为什么运行时差异如此之大?

【问题讨论】:

  • 只是出于兴趣,你能把这两个 couts 的结果贴出来
  • 您测量的运行时间范围是多少?
  • 我在原帖中添加了截图。
  • 在直接情况下,您似乎没有提到临时oclMat 销毁的时间。你也试过测量吗?
  • 你有另一个矩阵valueOCL。你把两个都毁了吗?

标签: opencv image-processing opencl gpgpu


【解决方案1】:

我要感谢 asarsakov(让我注意到销毁 oclMat 的问题)和 DarkZeros(注意到我忘记销毁函数中的第二个临时 oclMat)。

但是,这并不能反映整个解决方案。似乎我能够获得相同的“直接”和“功能”结果的唯一方法是使用 cv::ocl::oclMat& 而不是 cv::ocl::oclMat 发送 oclMats。

请参阅以下代码(整个代码、函数和所有代码)以获得产生相同结果的最终解决方案。通过更改 main 开头的布尔变量,我们可以控制计算(直接或通过函数)以及控制计时器内 oclMat 的释放。

#include "opencv2/ocl/ocl.hpp"
#include <conio.h>

void masking(cv::ocl::oclMat &inputOCL, cv::ocl::oclMat &valueOCL, cv::ocl::oclMat &logicalOCL, double comparisonValue, int method){
// NOTE: the method input is 1-->5 corresponding to (==, >, >=, <, <=, !=)  
valueOCL.setTo(cv::Scalar(comparisonValue));
cv::ocl::compare(inputOCL, valueOCL, logicalOCL, method);
logicalOCL.convertTo(logicalOCL, inputOCL.type());
cv::ocl::multiply(logicalOCL, inputOCL, inputOCL);
cv::ocl::multiply(1 / 255.0, inputOCL, inputOCL);   
}

int main(int argc, char** argv){

bool direct  = 1; // 1 for direct, 0 for function
bool release = 1; // 1 with releasing temporary oclMat, 0 without releasing them

// initialize data  
int method = 1;
static double start_TIMER;
double value1 = 1.23456789012345;
double value2 = 1.23456789012344;
cv::Mat I(5000, 5000, CV_64F, cv::Scalar(value1));

if (direct){
    // direct computation
    cv::ocl::oclMat inputOCL1(I);
    cv::ocl::oclMat valueOCL1(inputOCL1.size(), inputOCL1.type());
    cv::ocl::oclMat logicalOCL1;
    start_TIMER = cv::getTickCount();
    valueOCL1.setTo(cv::Scalar(value2));
    cv::ocl::compare(inputOCL1, valueOCL1, logicalOCL1, method);
    logicalOCL1.convertTo(logicalOCL1, inputOCL1.type());
    cv::ocl::multiply(logicalOCL1, inputOCL1, inputOCL1);
    cv::ocl::multiply(1 / 255.0, inputOCL1, inputOCL1);     
    if (release){ valueOCL1.release(); logicalOCL1.release(); }
    std::cout << "\nDirect runtime = " << ((double)(cv::getTickCount() - start_TIMER)) / cv::getTickFrequency() << " Seconds\n";
}

if (!direct){
    // computation done in function
    cv::ocl::oclMat inputOCL2(I);
    cv::ocl::oclMat valueOCL2(inputOCL2.size(), inputOCL2.type());
    cv::ocl::oclMat logicalOCL2;
    start_TIMER = cv::getTickCount();
    masking(inputOCL2, valueOCL2, logicalOCL2, value2, method);     
    if (release){ valueOCL2.release(); logicalOCL2.release(); }
    std::cout << "\nFunction runtime = " << ((double)(cv::getTickCount() - start_TIMER)) / cv::getTickFrequency() << " Seconds\n";      
}

printf("\nPress any key to exit...");
_getch();
return 0;
}

【讨论】:

  • 可能cv::ocl::multiplycv::ocl::compare 也有需要销毁的内部内核。通常这些操作很快,所以我无法解释为什么 cv::ocl 需要这么长时间.我可以确认的是,区别在于对象的破坏,如果您将所有“直接”计算包装在“{}”中并在封闭后执行 std::cout,那么时间应该是相同的,因为所有对象都将被销毁。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-27
  • 2015-08-14
  • 2019-12-13
  • 1970-01-01
相关资源
最近更新 更多