如何在不影响性能的情况下隔离C ++代码?

时间:2014-07-04 16:06:06

标签: c++ image-processing refactoring compiler-optimization

我无法重构我的C ++代码。代码本身只有200行,但是,如果它是图像处理事务,它会循环很多,我正在包围的障碍(我假设)处理非常坚韧的细节(例如内存访问)。

程序产生正确的输出,但应该最终实时运行。最初,每320x240px帧花费约3分钟,但现在大约需要2秒钟(在中档工作站和低端笔记本电脑硬件上运行大致相同;红旗?)。然而,与每秒24次相差甚远。基本上,我所做的任何改变都会在数百万次重复中传播,并且当我接近实时标记时,跟踪我的初学者错误会变得更加笨重。

在2点,该程序计算出一个计算成本较低的欧几里德距离变量,称为 taxicab 距离(绝对差值之和)。

现在,删节版本:

std::vector<int> positiveRows, positiveCols;
/* looping through pixels, reading values */
distance = (abs(pValues[0] - qValues[0]) + abs(pValues[1] - qValues[1]) + abs(pValues[2] - qValues[2]));
if(distance < threshold)
{
  positiveRows.push_back(row);
  positiveCols.push_back(col);
}

如果我将功能包装起来,如下所示:

int taxicab_dist(int Lp,
                 int ap,
                 int bp,
                 int Lq,
                 int aq,
                 int bq)
{
    return (abs(Lp - Lq) + abs(ap - aq) + abs(bp - bq));
}

并在同一个.cpp文件中调用它,没有性能下降。如果我在单独的.hpp / .cpp文件中声明和定义,我会得到显着减速。这直接反对我在本科课程中被告知的内容(“包括文件与复制粘贴相同”)。我最接近原始代码的性能是通过声明参数 const ,但它仍然需要大约100毫秒,我的判断认为这对于这样一个微不足道的任务是不可承受的。然后,我不明白为什么它会减慢(显着)如果我也使它们 const int&amp; 。然后,当我做最明智的事情,并选择将数组作为参数时,我再次受到性能影响。我甚至不敢尝试任何模板化的恶作剧,或者尝试让函数修改它的行为以便它接受任意数量的对,至少在我理解我自己进入之前是这样。

所以我的问题是:如何将计算定义转换为单独的文件,并使其与原始解决方案执行相同?此外,如果编译器将我的程序优化为运行2秒而不是15 ,那么巨大的红旗(错误的算法设计,不使用更多异域C ++关键字/功能) )?

我猜测我找不到答案的主要原因是因为我不知道这个东西叫什么名字。我听说过HPC社区中的“矢量化”这两个术语。这会与此有关吗?

如果它有任何帮助,可以找到整个代码here

1 个答案:

答案 0 :(得分:2)

正如Joachim Pileborg所说,你应该首先介绍一下。找出程序中大部分执行时间的位置。这是您应该优化的地方。

在矢量中保留空间
向量从小开始,然后根据需要重新分配。这涉及在内存中分配更大的空间,然后将旧元素复制到新的向量。最后释放内存。 std::vector具有在构造上保留空间的能力。对于大尺寸的矢量,这可以节省时间,消除了许多重新分配。

使用速度优化进行编译
使用现代编译器,您应该设置高速优化并查看它们可以执行的操作。编译器编写者有很多技巧,可以经常发现位置以优化您或我想念的位置。

真相是汇编语言
您需要查看汇编语言列表。如果汇编语言只显示区域中的两条指令,那么认为是瓶颈,那么你真的无法加快速度。

循环展开
您可以通过多次复制for循环中的内容来获得更高的性能。这称为循环展开。在某些处理器中,分支或跳转指令比数据处理指令花费更多的执行时间。展开循环减少了执行的分支指令的数量。同样,当您提高优化级别时,编译器可能会自动执行此操作。

数据缓存优化
在网上搜索“数据缓存优化”。加载和卸载数据缓存会浪费时间。如果您的数据可以适合处理器的数据高速缓存,则不必继续加载卸载(称为高速缓存未命中)。还要记住在执行其他操作之前,在一个位置对数据执行所有操作。这降低了处理器重新加载高速缓存的可能性。

多处理器计算
如果您的平台具有多个处理器(例如图形处理单元(GPU)),则可以将某些任务委派给它。请注意,您还通过与其他处理器通信来增加时间。因此,对于小型任务,通信开销可能会浪费您通过委派获得的时间。

并行计算
与多处理器类似,您可以让操作系统委派任务。操作系统可以委派给您处理器中的不同内核(如果您有多核处理器),或者在另一个线程中运行它。再次存在成本:管理任务或线程和通信的开销。

<强>摘要
优化的三个规则:

  1. 不要
  2. 不要
  3. 资料
    概述后,查看执行最多的区域。这将比优化永远不会被调用的部分获得更多时间。设计优化通常会比代码优化花费更多时间。同样,需求变更(例如消除)可能比设计优化获得更多时间。
  4. 在您的程序正常运行且功能强大之后,只有在有保证的情况下才能进行优化。如果您的用户界面太慢,用户可以去喝杯咖啡,那么这是一个优化的好地方。如果你通过优化数据传输获得100毫秒,但你的程序等待1秒钟的人为响应,你还没有获得任何东西。考虑到这是一个非常快速的停车标志。无论你的速度如何,你仍然必须停下来。

    如果仍需要性能提升,请在网上搜索“优化c ++”,“数据优化”或“性能优化”。