在今天的现代处理器中,分支条件的大于或大于或等于比较之间是否有任何性能差异?如果我有可能很容易被任何条件,没有任何轻微的优势,选择>了>=或反之亦然?(这适用于Intel或AMD硬件上的编译语言)
假设我想在循环中迭代所有整数for.为了便于讨论,假设我f(unsigned x)为每个整数调用一些未知函数:
for (unsigned i = 0; i < UINT_MAX; i++) {
f(i);
}
Run Code Online (Sandbox Code Playgroud)
当然,上面的代码无法遍历所有整数,因为它错过了一个:UINT_MAX.将条件更改为i <= UINT_MAX仅导致无限循环,因为这是一个重言式.
你可以用do-while循环来完成它,但是你会失去for语法的所有细节.
我可以吃蛋糕(for循环)并吃掉它(迭代所有整数)吗?
想象一下我有一个程序需要检查变量是否i大于零。i总是积极的,所以说 thati > 0相当于说i != 0。
这两个表达式之间是否存在性能差异?为什么?
我知道没有明显的性能差异,这更多的是一个哲学问题。
是否<比<=(和>更快)更便宜(更快)>=?
免责声明:我知道我可以测量,但这只会在我的机器上,我不确定答案是否可能是"特定于实现"或类似的东西.
我在SO上找到了一些关于<和<=的性能比较的问题(这个问题非常简单),我总能找到相同的答案,即两者之间没有性能差异.
我写了一个比较程序(不是那么工作小提琴......复制到你的机器上运行它),我在其中创建了两个循环for (int i = 0; i <= 1000000000; i++ )和for (int i = 0; i < 1000000001; i++ )两种不同的方法.
我跑了100次方法; 取平均经过的时间,发现<=运算符循环比运算符运行慢<.
我多次运行程序并且<=总是花费更多时间来完成.我的结果(im ms)是:
3018.73,2772.22
2816.87,2760.62
2859.02,2797.05
我的问题是:如果没有一个更快,为什么我看到结果的差异?我的程序有什么问题吗?
这可能是一个愚蠢的问题,但这种优化有时会提高应用程序的性能.在这里我要专门讨论C++,因为C++编译代码的方式与c#或Java有很大不同.
问题是哪一个表现更好,如果变量i是int.
i > -1i >= 0我正在寻找所需的内存块或寄存器性能以及两种条件所需的CPU周期.
提前致谢.
我刚刚查看了彼得·科德斯(Peter Cordes)的回答,他说,
如果读取标志,则部分标志停顿会发生,如果它们确实发生的话。P4永远不会有部分标志停顿,因为它们永远不需要合并。相反,它具有错误的依赖关系。几个答案/评论混淆了术语。它们描述了一个错误的依赖关系,但随后将其称为部分标志停顿。这是由于仅写入一些标志而导致的速度下降,但是术语“部分标志停顿”是指必须合并部分标志写入时在SnB之前的Intel硬件上发生的情况。英特尔SnB系列CPU插入一个额外的uop来合并标志而不会停顿。Nehalem和更早的失速约7个周期。我不确定AMD CPU会受到多大的损失。
我感觉我还不明白什么是“部分国旗摊位”。我怎么知道一个人发生了?除了读取标志的某些时间之外,什么触发事件?合并标志是什么意思?在什么情况下会“写一些标志”,但不会发生部分标志合并?我需要了解哪些有关旗位的知识才能理解它们?
首先是一个微不足道的数学事实:给定整数n和m,我们有n < m当且仅当n <= m - 1。
GCC 似乎更喜欢较小绝对值的即时值。因此,当m已知并且满足其他条件时,编译器在等效比较表达式中选择最小化绝对值的表达式。例如,它喜欢n <= 1000在n < 1001和GCC 9.2将这种
bool f(uint32_t n) {
return n < 1001;
}
Run Code Online (Sandbox Code Playgroud)
进入这个x86汇编代码
f(unsigned int):
cmpl $1000, %edi
setbe %al
ret
Run Code Online (Sandbox Code Playgroud)
这可能有很好的性能原因,但这不是我的问题。我想知道的是:有没有办法强制 GCC 保持原始比较?更具体地说,我不担心可移植性,因此,GCC 细节(选项、编译指示、属性等)对我来说是可以的。但是,我正在寻找一个constexpr友好的解决方案,它似乎排除了 inline asm。最后,我的目标是 C++17,它不包括std::is_constant_evaluated. (话虽如此,请尽管不顾我的限制自由地提供答案,因为它可能对其他人仍然有用。)
你可能会问我为什么要做这样的事情。开始了。据我所知(如果我错了,请纠正我)这种行为可能是x86_64以下示例中的“悲观化” :
bool g(uint64_t n) {
n *= 5000000001;
return n …Run Code Online (Sandbox Code Playgroud) 考虑两个for循环声明:
for (int i = 0; i < 70; ++i)
Run Code Online (Sandbox Code Playgroud)
和
for (int i = 0; i <= 69; ++i)
Run Code Online (Sandbox Code Playgroud)
我假设第二个将进行139次总比较而不是69次.我的假设是否正确?我不是电气工程师,所以我不知道ALU实际上是如何工作的,无论是一次性的"小于或等于"的东西,还是什么.
你能举例说明何时使用<=是合理的?
顺便说一下,我正试图成为像你们这样的"硬核"程序员.
(如果是这样的话,我会自己做的.)
我的问题:
为方便起见,我倾向于避免间接/索引寻址模式.
作为替代,我经常使用立即,绝对或寄存器寻址.
代码:
; %esi has the array address. Say we iterate a doubleword (4bytes) array.
; %ecx is the array elements count
(0x98767) myloop:
... ;do whatever with %esi
add $4, %esi
dec %ecx
jnz 0x98767;
Run Code Online (Sandbox Code Playgroud)
在这里,我们有一个序列化的组合(dec和jnz),它可以防止正常的乱序执行(依赖).
有没有办法避免/破坏dep?(我不是装配专家).