bat*_*man 5 c++ parallel-processing performance opencv
我parallel_for_
通过与简单的数组求和和乘法的正常操作进行比较,在OpenCV中进行了测试.
我有100个整数的数组,并分成10个并运行使用parallel_for_
.
然后我也有正常的0到99运算进行求和和多重复用.
然后我测量了经过的时间,正常操作比parallel_for_
操作更快.
我的CPU是Intel(R)Core(TM)i7-2600 Quard核心CPU.
parallel_for_
为了求和,操作耗时0.002秒(需要2个时钟周期),乘以0.003秒(耗时3个时钟周期).
但是对于求和和乘法,正常操作需要0.0000秒(少于一个单击周期).我错过了什么?我的代码如下.
TEST类
#include <opencv2\core\internal.hpp>
#include <opencv2\core\core.hpp>
#include <tbb\tbb.h>
using namespace tbb;
using namespace cv;
template <class type>
class Parallel_clipBufferValues:public cv::ParallelLoopBody
{
private:
type *buffertoClip;
type maxSegment;
char typeOperation;//m = mul, s = summation
static double total;
public:
Parallel_clipBufferValues(){ParallelLoopBody::ParallelLoopBody();};
Parallel_clipBufferValues(type *buffertoprocess, const type max, const char op): buffertoClip(buffertoprocess), maxSegment(max), typeOperation(op){
if(typeOperation == 's')
total = 0;
else if(typeOperation == 'm')
total = 1;
}
~Parallel_clipBufferValues(){ParallelLoopBody::~ParallelLoopBody();};
virtual void operator()(const cv::Range &r) const{
double tot = 0;
type *inputOutputBufferPTR = buffertoClip+(r.start*maxSegment);
for(int i = 0; i < 10; ++i)
{
if(typeOperation == 's')
total += *(inputOutputBufferPTR+i);
else if(typeOperation == 'm')
total *= *(inputOutputBufferPTR+i);
}
}
static double getTotal(){return total;}
void normalOperation(){
//int iteration = sizeof(buffertoClip)/sizeof(type);
if(typeOperation == 'm')
{
for(int i = 0; i < 100; ++i)
{
total *= buffertoClip[i];
}
}
else if(typeOperation == 's')
{
for(int i = 0; i < 100; ++i)
{
total += buffertoClip[i];
}
}
}
};
Run Code Online (Sandbox Code Playgroud)
主要
#include "stdafx.h"
#include "TestClass.h"
#include <ctime>
double Parallel_clipBufferValues<int>::total;
int _tmain(int argc, _TCHAR* argv[])
{
const int SIZE=100;
int myTab[SIZE];
double totalSum_by_parallel;
double totalSun_by_normaloperation;
double elapsed_secs_parallel;
double elapsed_secs_normal;
for(int i = 1; i <= SIZE; i++)
{
myTab[i-1] = i;
}
int maxSeg =10;
clock_t begin_parallel = clock();
cv::parallel_for_(cv::Range(0,maxSeg), Parallel_clipBufferValues<int>(myTab, maxSeg, 'm'));
totalSum_by_parallel = Parallel_clipBufferValues<int>::getTotal();
clock_t end_parallel = clock();
elapsed_secs_parallel = double(end_parallel - begin_parallel) / CLOCKS_PER_SEC;
clock_t begin_normal = clock();
Parallel_clipBufferValues<int> norm_op(myTab, maxSeg, 'm');
norm_op.normalOperation();
totalSun_by_normaloperation = norm_op.getTotal();
clock_t end_normal = clock();
elapsed_secs_normal = double(end_normal - begin_normal) / CLOCKS_PER_SEC;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
让我做一些考虑:
clock()
函数根本不准确。它的刻度是粗略的1 / CLOCKS_PER_SEC
,但更新的频率以及它是否统一取决于系统和实现。有关更多详细信息,请参阅这篇文章。
测量时间的更好替代方案:
措施总是会受到错误的影响。代码的性能测量会受到其他程序、缓存、操作系统作业、调度和用户活动的影响(简短的列表,还有更多)。为了获得更好的测量结果,您必须重复多次(假设 1000 次或更多),然后计算平均值。此外,您应该将测试环境准备得尽可能干净。
有关这些帖子测试的更多详细信息:
在您的情况下,并行执行(以及您的测试代码结构)的开销比循环体本身高得多。在这种情况下,并行算法的效率并不高。并行执行必须始终在特定场景中进行评估、测量和比较。它并不是一种可以加速一切的灵丹妙药。请查看这篇有关如何量化可扩展性的文章。
举例来说,如果您必须对 100 个数字进行求和/相乘,那么最好使用SIMD指令(在展开的循环中效果更好)。
尝试使循环体为空(或者执行单个NOP
操作或volatile
写入,这样它就不会被优化掉)。您将粗略地测量开销。现在将其与您的结果进行比较。
IMO 这种测试毫无用处。您无法以通用方式比较串行或并行执行。您应该始终根据特定情况进行检查(在现实世界中,许多事情都会发挥作用,例如同步)。
想象一下:您使循环体变得非常“重”,并且您会看到并行执行的速度大大提高。现在,您使真正的程序并行化,您会发现性能更差。为什么?因为并行执行会因锁、缓存问题或对共享资源的串行访问而减慢。
测试本身是没有意义的,除非您在特定情况下测试特定代码(因为有太多因素会发挥作用,您不能忽略它们)。这是什么意思?好吧,您只能比较您测试的内容......如果您的程序执行total *= buffertoClip[i];
,那么您的结果是可靠的。如果你的真实程序做了其他事情,那么你必须用其他东西重复测试。