在我的程序中的某个时刻,我计算整数除数d.从那时起d,这将是不变的.
稍后在代码中我将除以它d几次 - 执行整数除法,因为值d不是编译时已知常量.
鉴于与其他类型的整数运算相比,整数除法是一个相对较慢的过程,我想优化它.我可以存储一些替代格式d,以便分割过程执行得更快吗?也许是某种形式的倒数?
我不需要d其他任何东西的价值.
值d是任何64位整数,但通常很适合32位.
这与此问题有关,但不一样:x86-64汇编的性能优化 - 对齐和分支预测与我之前的问题略有关系:无符号64位到双倍转换:为什么这个算法来自g ++
以下是一个不真实的测试用例.这种素性测试算法是不明智的.我怀疑任何真实世界的算法都不会执行如此多的小内循环(num大概是2**50的大小).在C++ 11中:
using nt = unsigned long long;
bool is_prime_float(nt num)
{
for (nt n=2; n<=sqrt(num); ++n) {
if ( (num%n)==0 ) { return false; }
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
然后g++ -std=c++11 -O3 -S生成以下内容,包含RCX n和包含XMM6 sqrt(num).请参阅我之前发布的剩余代码(在此示例中从未执行过,因为RCX永远不会变得足够大,不能被视为带符号的否定).
jmp .L20
.p2align 4,,10
.L37:
pxor %xmm0, %xmm0
cvtsi2sdq %rcx, %xmm0
ucomisd %xmm0, %xmm6
jb .L36 // Exit the loop
.L20:
xorl %edx, %edx
movq %rbx, %rax …Run Code Online (Sandbox Code Playgroud) 我想知道各种大小的循环如何在最近的x86处理器上执行,作为uop数的函数.
以下是彼得·科德斯(Peter Cordes)的一句话,他在另一个问题中提出了非多数的问题:
我还发现,如果循环不是4 uop的倍数,则循环缓冲区中的uop带宽不是每个循环的常数4.(即它是abc,abc,......;不是abca,bcab,......).遗憾的是,Agner Fog的microarch doc对循环缓冲区的这种限制并不清楚.
问题是关于循环是否需要是N uop的倍数才能以最大uop吞吐量执行,其中N是处理器的宽度.(即最近的英特尔处理器为4).在谈论"宽度"和计算微动时,有很多复杂因素,但我大多想忽略这些因素.特别是,假设没有微观或宏观融合.
Peter给出了以下一个循环,其中包含7个uop的循环:
一个7-uop循环将发出4 | 3 | 4 | 3 | ...的组我没有测试更大的循环(不适合循环缓冲区),看看是否有可能从下一个指令开始迭代发布在与其分支相同的组中,但我不假设.
更一般地说,声称是x在其体内具有uops 的循环的每次迭代将至少进行ceil(x / 4)迭代,而不是简单地迭代x / 4.
对于部分或全部最新的x86兼容处理器,这是真的吗?
performance x86 assembly cpu-architecture micro-optimization
如果我有一个受Intel jcc erratum约束的芯片,我如何在 gcc 中启用缓解(它调整分支位置以避免有问题的对齐),以及哪些 gcc 版本支持它?
当我使用amd64或x86系统上的最新编译器编译C代码时,函数将对齐到16个字节的倍数.这种对齐在现代处理器上实际上有多重要?调用未对齐函数会产生巨大的性能损失吗?
我运行了以下microbenchmark(call.S):
// benchmarking performance penalty of function alignment.
#include <sys/syscall.h>
#ifndef SKIP
# error "SKIP undefined"
#endif
#define COUNT 1073741824
.globl _start
.type _start,@function
_start: mov $COUNT,%rcx
0: call test
dec %rcx
jnz 0b
mov $SYS_exit,%rax
xor %edi,%edi
syscall
.size _start,.-_start
.align 16
.space SKIP
test: nop
rep
ret
.size test,.-test
Run Code Online (Sandbox Code Playgroud)
使用以下shell脚本:
#!/bin/sh
for i in `seq 0 15` ; do
echo SKIP=$i
cc -c -DSKIP=$i call.S
ld -o call call.o
time -p ./call
done
Run Code Online (Sandbox Code Playgroud)
在自称为 …
我熟悉数据对齐和性能,但对对齐代码相当陌生。我最近开始使用 NASM 在 x86-64 汇编中进行编程,并一直使用代码对齐来比较性能。据我所知,NASM 插入nop指令来实现代码对齐。
这是我一直在 Ivy Bridge 系统上尝试的一个功能
void triad(float *x, float *y, float *z, int n, int repeat) {
float k = 3.14159f;
int(int r=0; r<repeat; r++) {
for(int i=0; i<n; i++) {
z[i] = x[i] + k*y[i];
}
}
}
Run Code Online (Sandbox Code Playgroud)
我为此使用的程序集如下。如果我不指定对齐方式,我的性能与峰值相比仅为 90% 左右。然而,当我将循环之前的代码以及两个内部循环对齐为 16 字节时,性能跃升至 96%。很明显,这种情况下的代码对齐会产生影响。
但这是最奇怪的部分。如果我将最里面的循环对齐到 32 字节,则该函数的性能没有任何差异,但是,在该函数的另一个版本中,在单独的对象文件中使用内部函数,我链接它的性能从 90% 跃升至 95%!
我做了一个对象转储(使用objdump -d -M intel)的版本对齐到16字节(我将结果发布到这个问题的末尾)和32字节,它们是相同的!事实证明,在两个目标文件中,最里面的循环无论如何都与 32 字节对齐。但一定有一些区别。
我对每个目标文件进行了十六进制转储,目标文件中有一个字节不同。与 16 字节对齐的目标文件有一个带有 的字节0x10,与 32 字节对齐的目标文件有一个带有 的字节0x20。到底是怎么回事!为什么一个目标文件中的代码对齐会影响另一个目标文件中函数的性能?我如何知道将我的代码调整到的最佳值是多少?
我唯一的猜测是,当加载程序重新定位代码时,32 字节对齐的对象文件会使用内在函数影响其他对象文件。 …