https://godbolt.org/z/dK9v7En5v
对于以下C++代码
#include <stdint.h>
#include <cstdlib>
void Send(uint32_t);
void SendBuffer(uint32_t* __restrict__ buff, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
Send(buff[0]);
Send(buff[1]);
for (size_t j = 0; j < i; ++j) {
Send(buff[j]);
}
}
}
我们有以下汇编程序清单
SendBuffer(unsigned int*, unsigned long):
test rsi, rsi
je .L15
push r13
mov r13, rsi
push r12
mov r12, rdi
push rbp
xor ebp, ebp
push rbx
sub rsp, 8
.L5:
mov edi, DWORD PTR [r12]
call Send(unsigned int)
mov edi, DWORD PTR [r12+4]
call Send(unsigned int)
test rbp, rbp
je .L3
xor ebx, ebx
.L4:
mov edi, DWORD PTR [r12+rbx*4]
add rbx, 1
call Send(unsigned int)
cmp rbx, rbp
jne .L4
.L3:
add rbp, 1
cmp r13, rbp
jne .L5
add rsp, 8
pop rbx
pop rbp
pop r12
pop r13
ret
.L15:
ret
在每次循环迭代时,从存储器中读取,而值可以在寄存器中存储一次。
不管我们有没有内部循环,编译器不会优化它的构造,我添加循环是为了证明编译器不能依赖处理器缓存
编译器根据C++标准在循环之前从寄存器加载内存一次是否有效(如果我们有或没有__restrict__
关键字)?如果有效,为什么编译器不做优化?如果现在没有,我怎么能告诉编译器没有人会改变内存,它是有效的?
1条答案
按热度按时间c6ubokkw1#
您可以通过重新排列代码来帮助编译器,以便可以看到RAM优化的影响。
在上面的代码中,瓶颈是对
Send
的调用。访问buff
数组要快得多。而且,循环中的分支求值比访问数组花费更多的时间。这里真正的优化应该是修改
Send
,使其传输块而不是字。大多数设备通信都有块传输功能。否则,您可以尝试展开循环。(* 编译器可能会在更高的优化级别上展开循环 *)
检查汇编语言应该显示更好的组织和优化的代码。
**编辑1:**包括外部循环,更正索引变量用法。