【问题标题】:Testing parallel_for_ performance in OpenCV在 OpenCV 中测试 parallel_for_ 性能
【发布时间】:2013-12-12 08:10:18
【问题描述】:

我在 OpenCV 中测试了parallel_for_,通过与简单数组求和和乘法的正常操作进行比较。

我有 100 个整数的数组,每个整数分成 10 个,并使用 parallel_for_ 运行。

然后我也有正常的 0 到 99 的求和和乘法运算。

然后我测量了经过的时间,正常运行比parallel_for_运行快。

我的 CPU 是 Intel(R) Core(TM) i7-2600 四核 CPU。 parallel_for_ 运算耗时 0.002 秒(耗时 2 个时钟周期)进行求和,耗时 0.003 秒(耗时 3 个时钟周期)进行乘法。

但正常运算需要 0.0000 秒(少于一次单击周期)进行求和和乘法运算。我错过了什么?我的代码如下。

测试类

#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];
               }
           }
       }

};

主要

    #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;
    }

【问题讨论】:

  • 嗯,首先,clock() 对于任何测量都不够准确。其次,您无法仅通过一次试验来衡量性能。第三,对于如此小的循环体开销(并行执行和您的程序本身)高于计算时间(例如,如果您必须将 100 个数字相加/相乘,最好使用 SIMD 指令而不是使其并行)。
  • 谢谢。是的,我应该比较重要的计算。
  • 不仅仅是循环体本身,这类测试还有其他问题(有关更多详细信息,请参阅我的回答)。

标签: c++ performance opencv parallel-processing


【解决方案1】:

让我做一些考虑:

准确度

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

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

试用和测试环境

措施始终受errors 的影响。代码的性能测量会受到其他程序、缓存、操作系统作业、调度和用户活动的影响(短名单,还有更多)。要获得better measure,您必须重复 很多 次(比如说 1000 次或更多),然后计算平均值。此外,您应该准备好测试环境,使其尽可能干净。

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

开销和可扩展性

在您的情况下,并行执行(以及您的测试代码结构)的开销远高于循环体本身。在这种情况下,使算法并行是没有效率的。必须始终在特定场景中对并行执行进行评估、测量和比较。这不是加速一切的灵药。看看这篇关于How to Quantify Scalability的文章。

例如,如果您必须将 100 个数字相加/相乘,最好使用 SIMD 指令(在展开循环中甚至更好)。

测量它!

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

关于本次测试的注意事项

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

想象一下:你让你的循环体真的很“沉重”,你会看到并行执行的速度大大提高。现在你让你的真实程序并行,你会发现性能更差。为什么?因为锁、缓存问题或对共享资源的串行访问会减慢并行执行速度。

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

【讨论】:

    猜你喜欢
    • 2014-11-27
    • 2023-03-13
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    相关资源
    最近更新 更多