我介绍了我的代码,发现一个内联函数大约需要8%的样本。该功能是将矩阵订阅转换为指数。它就像MATLAB函数sub2ind
。
inline int sub2ind(const int sub_height, const int sub_width, const int width) {
return sub_height * width + sub_width;
}
我想编译器不会执行内联扩展,但我不知道该如何检查。
有什么方法可以改善这一点?还是明确让编译器执行内联扩展?
您是否记得对优化进行编译?有些编译器具有强制内部属性,即使编译器不想:查看此问题。
。,但它可能已经存在;您可以尝试让编译器输出汇编代码,并尝试确保以这种方式检查。
索引计算可能是您时间的很大一部分,例如如果您的算法是从矩阵读取的,一点点计算,然后回信,则索引计算确实是您计算时间的很大一部分。
或者,您已经以编译器无法证明width
在整个循环中保持恒定*的方式编写代码,因此,它必须每次都从内存中重新读取它,以确保。尝试将width
复制到本地变量并在您的内部循环中使用。
现在,您已经说过这需要您的8%的时间 - 这意味着您不太可能可能 可以比您的运行时间提高8%较少的。如果那是真的值得,那么要做的事情可能是从根本上改变您的迭代方式。
,例如
- 如果您倾向于以线性方式访问矩阵,则可以编写某种二维迭代器类,您可以向上,向下,向左或右推进,并且它将在任何地方使用添加剂而不是乘法
- 同一件事,但是写一个"索引"类,该类仅容纳数字,而不是假装是指针
- 如果
width
是一个编译时常数,则可以明确地使其如此,例如作为模板参数,您的编译器可能能够使用乘法来做更多聪明的事情
*:您可能会做一些愚蠢的事情,例如将矩阵的数据结构放在存储矩阵条目的位置中!因此,当您更新矩阵时,您可能会更改宽度。编译器必须防止这些漏洞,因此它不能进行"显然应该"的优化。有时,在一个上下文中漏洞的一种事情很可能是程序员在另一种情况下的明显意图。一般来说,这些循环孔往往遍布整个地方,并且编译器比人类注意到这些漏洞更好。
如 @user3528438所述,您可以查看汇编输出。考虑以下示例:
inline int sub2ind(const int sub_height, const int sub_width, const int width) {
return sub_height * width + sub_width;
}
int main() {
volatile int n[] = {1, 2, 3};
return sub2ind(n[0], n[1], n[2]);
}
在没有优化的情况下对其进行编译(g++ -S test.cc
)在以下代码中使用sub2ind
未划分的代码:
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl $1, -16(%rbp)
movl $2, -12(%rbp)
movl $3, -8(%rbp)
movq -16(%rbp), %rax
movq %rax, -32(%rbp)
movl -8(%rbp), %eax
movl %eax, -24(%rbp)
movl -24(%rbp), %edx
movl -28(%rbp), %ecx
movl -32(%rbp), %eax
movl %ecx, %esi
movl %eax, %edi
call _Z7sub2indiii ; call to sub2ind
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
在使用优化(g++ -S -O3 test.cc
)进行编译时会导致sub2ind
被内衬并大部分优化:
main:
.LFB1:
.cfi_startproc
movl $1, -24(%rsp)
movl $2, -20(%rsp)
movq -24(%rsp), %rax
movl $3, -16(%rsp)
movq %rax, -40(%rsp)
movl $3, -32(%rsp)
movl -32(%rsp), %eax
movl -36(%rsp), %edx
movl -40(%rsp), %ecx
imull %ecx, %eax
addl %edx, %eax
ret
.cfi_endproc
因此,如果您确信您的函数没有被列入列表,请首先确保您在编译器选项中启用优化。