Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:为什么这会加速我的代码?_C++_Performance_Gcc - Fatal编程技术网

C++ C++;:为什么这会加速我的代码?

C++ C++;:为什么这会加速我的代码?,c++,performance,gcc,C++,Performance,Gcc,我有以下功能 double single_channel_add(int patch_top_left_row, int patch_top_left_col, int image_hash_key, Mat* preloaded_images, int* random_values){ int first_pixel_row = patch_top_left_row + random_values[0]; int first

我有以下功能

double single_channel_add(int patch_top_left_row, int patch_top_left_col, 
        int image_hash_key, 
        Mat* preloaded_images,
        int* random_values){

    int first_pixel_row = patch_top_left_row + random_values[0];
    int first_pixel_col = patch_top_left_col + random_values[1];
    int second_pixel_row = patch_top_left_row + random_values[2];
    int second_pixel_col = patch_top_left_col + random_values[3];

    int channel = random_values[4];

    Vec3b* first_pixel_bgr = preloaded_images[image_hash_key].ptr<Vec3b>(first_pixel_row, first_pixel_col);
    Vec3b* second_pixel_bgr = preloaded_images[image_hash_key].ptr<Vec3b>(second_pixel_row, second_pixel_col);

    return (*first_pixel_bgr)[channel] + (*second_pixel_bgr)[channel];
}
编辑:

我已经从函数的两个版本粘贴了程序集 使用参数: 使用常量:

编辑:

使用-O3编译后,我得到以下时钟信号和速度:

使用参数:1990000个刻度和1.99秒 使用常数:330000个刻度和0.33秒

编辑: 将argumenst与-03编译一起使用:
将常量与-03编译一起使用:

好吧,
立即常量与内存
格式的二进制算术运算预计会比
内存与内存
格式的二进制算术运算生成更快的代码,但您观察到的时间效应似乎过于极端,特别是考虑到该函数中还有其他操作

是否编译器决定内联您的函数?内联将允许编译器轻松消除与第二版本中未使用的
patch\u top\u left\u row
patch\u top\u left\u col
参数相关的所有内容,包括在调用代码中准备/计算这些参数的任何步骤


从技术上讲,即使函数不是内联的,也可以这样做,但它通常更复杂。

在x86平台上,有一些指令可以非常快速地将小整数添加到寄存器中。这些指令是
lea
(又称“加载有效地址”)指令,用于计算结构等的地址偏移量。正在添加的小整数实际上是指令的一部分。智能编译器知道这些指令非常快,即使不涉及地址,也可以使用它们进行添加

我敢打赌,如果你将常数更改为至少24位长的随机值,你会看到大部分加速消失

其次,这些常数是已知值。编译器可以尽可能高效地安排这些值在寄存器中结束。对于参数,除非参数在寄存器中传递(我认为您的函数有太多的参数用于调用约定),否则编译器别无选择,只能使用堆栈偏移量加载指令从内存中获取数字。这不是一个特别慢的指令或任何东西,但是对于常量,编译器可以自由地做一些比从指令本身获取数字快得多的事情。
lea
指令就是最极端的例子

编辑:既然你已经粘贴了组件,事情就清楚多了

在非常量代码中,以下是如何进行添加:

addl    -68(%rbp), %eax
addl    $5, %eax
这将从堆栈中获取偏移量
-68(%rpb)
的值,并将其添加到
%eax%
寄存器中

在常量代码中,以下是如何进行添加:

addl    -68(%rbp), %eax
addl    $5, %eax
如果你看一下实际的数字,你会发现:

0138 83C005
很明显,被添加的常量作为一个小值直接编码到指令中。这将比从堆栈偏移量获取值快得多,原因有很多。首先它比较小。其次,它是没有分支的指令流的一部分。因此,它将被预取和管道化,不可能出现任何类型的缓存暂停

因此,虽然我对
lea
指令的猜测不正确,但我仍然走在正确的轨道上。常量版本使用一条专门用于向寄存器中添加小整数的小指令。非常量版本必须从堆栈偏移量中获取一个可能大小不确定的整数(因此它必须获取所有位,而不仅仅是低位位)(这将添加一个额外的add,以根据偏移量和堆栈基址计算实际地址)

编辑2:现在您已经发布了
-O3
结果

现在更让人困惑了。它显然是内联函数,在内联函数的代码和调用函数的代码之间跳了一整吨。我需要查看整个文件的原始代码,以便进行适当的分析

但我强烈怀疑现在正在发生的是,从
get\u range
中获取的值的不可预测性严重限制了编译器可用的优化选项。事实上,在常量版本中,它甚至不需要调用
get\u range\u random\u number\u
,因为该值被抛出,从未使用过


我假设
patch\u top\u left\u row
patch\u top\u left\u col
的值在某个地方的循环中生成。我将把这个循环推到这个函数中。如果编译器知道这些值是作为循环的一部分生成的,那么有很多优化选项可供选择。在极端情况下,它可以使用各种SSE或3dnow中的一些SIMD指令!指令套件使事情比使用常量的版本快一整吨


另一个选项是将此函数内联,这将提示编译器应该尝试将其插入调用它的循环中。如果编译器接受这个提示(这个函数有点大,所以编译器可能不会),它将产生与将循环填充到函数中几乎相同的效果。

gcc
具有可用于查看汇编语言输出的命令行选项。为什么不获取此处显示的两个代码段的程序集,
diff
并在问题中发布生成的diff?您不能将其复制为一个,可以吗?请查看生成的程序集代码。在第二种情况下,编译器可能会使用一些SSE指令。另外,这两个实现似乎做的事情并不相同。为什么第二个示例5、6、8和10中的值