测试OpenCV中的parallel_for_性能

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)

Adr*_*tti 4

让我做一些考虑:

准确性

clock()函数根本不准确。它的刻度是粗略的1 / CLOCKS_PER_SEC,但更新的频率以及它是否统一取决于系统和实现。有关更多详细信息,请参阅这篇文章。

测量时间的更好替代方案:

试用和测试环境

措施总是会受到错误的影响。代码的性能测量会受到其他程序、缓存、操作系统作业、调度和用户活动的影响(简短的列表,还有更多)。为了获得更好的测量结果,您必须重复多次(假设 1000 次或更多),然后计算平均值。此外,您应该将测试环境准备得尽可能干净。

有关这些帖子测试的更多详细信息:

开销和可扩展性

在您的情况下,并行执行(以及您的测试代码结构)的开销比循环体本身高得多。在这种情况下,并行算法的效率并不高。并行执行必须始终在特定场景中进行评估、测量和比较。它并不是一种可以加速一切的灵丹妙药。请查看这篇有关如何量化可扩展性的文章。

举例来说,如果您必须对 100 个数字进行求和/相乘,那么最好使用SIMD指令(在展开的循环中效果更好)。

测量一下!

尝试使循环体为空(或者执行单个NOP操作或volatile写入,这样它就不会被优化掉)。您将粗略地测量开销。现在将其与您的结果进行比较。

关于此测试的注意事项

IMO 这种测试毫无用处。您无法以通用方式比较串行或并行执行。您应该始终根据特定情况进行检查(在现实世界中,许多事情都会发挥作用,例如同步)。

想象一下:您使循环体变得非常“重”,并且您会看到并行执行的速度大大提高。现在,您使真正的程序并行化,您会发现性能更差。为什么?因为并行执行会因锁、缓存问题或对共享资源的串行访问而减慢。

测试本身是没有意义的,除非您在特定情况下测试特定代码(因为有太多因素会发挥作用,您不能忽略它们)。这是什么意思?好吧,您只能比较您测试的内容......如果您的程序执行total *= buffertoClip[i];,那么您的结果是可靠的。如果你的真实程序做了其他事情,那么你必须用其他东西重复测试