wanghenshui / wanghenshui.github.io

my blog, please do not fork
https://wanghenshui.github.io
Other
4 stars 1 forks source link

cmov #121

Closed wanghenshui closed 2 months ago

wanghenshui commented 4 months ago

https://github.com/marcin-osowski/cmov/

https://kristerw.github.io/2022/05/24/branchless/

https://www.agner.org/optimize/optimizing_assembly.pdf

我发现agner这哥们的手册基本高手都知道,但是大家都不怎么传播

wanghenshui commented 4 months ago

cmov在哪些场景下不如jmp

cmov(条件移动)指令和jmp(跳转)指令在处理器中服务于不同的目的,各有其优势和适用场景。cmov是一种条件执行指令,用于在满足特定条件时将一个值移动到寄存器中,而不需要执行跳转,从而避免分支预测失败带来的性能损失。jmp是一种控制流指令,用于无条件或条件性地改变程序的执行流程。在某些场景下,cmov不如jmp有效,主要包括以下几点:

数据依赖性

执行路径长度

分支预测的准确性

代码的可读性和维护性

总结

cmov指令适用于执行路径中有条件性数据移动且不希望引入分支预测失败开销的场景。然而,当存在强数据依赖、代码块非常小、分支预测准确性高或需要优化代码可读性和维护性时,使用jmp指令实现的分支可能更为合适。在实际开发中,最佳选择取决于具体的应用场景、性能需求以及维护考虑。

wanghenshui commented 4 months ago

https://llvm.org/docs/SpeculativeLoadHardening.html

Speculative问题会影响cmov速度吗

是的,speculative execution(推测执行)问题可能会影响cmov(条件移动指令)的执行速度,以及其他类型指令的执行性能。推测执行是现代处理器用来提高执行速度的一种技术,它允许CPU在等待分支指令最终解析的同时,预先执行接下来可能的指令。这种方式可以显著提高处理器的效率,因为它减少了等待分支决策的时间。

然而,推测执行也引入了潜在的安全漏洞(如Spectre和Meltdown),因为它可能允许恶意程序推断出在推测执行路径中访问的敏感数据。为了缓解这些安全问题,处理器制造商和操作系统开发者实施了各种补丁和更新,这些更新可能会影响CPU指令的性能,包括cmov

cmov与推测执行的关系

cmov指令的性能可能受到推测执行机制的影响,原因如下:

总结

虽然cmov指令本身是为了提高在条件分支情况下的执行效率而设计的,推测执行引入的安全修复可能会对其性能造成一定影响。不过,这种影响的实际程度会根据具体的处理器模型、操作系统补丁和应用场景而有所不同。在大多数情况下,现代处理器和编译器的优化足以减轻这些影响,但在性能敏感的应用中,开发者可能需要密切关注这些因素,以及可能的性能变化。

wanghenshui commented 4 months ago

https://go-review.googlesource.com/c/go/+/145717

https://github.com/golang/go/issues/26306

wanghenshui commented 4 months ago

https://yarchive.net/comp/linux/cmov.html

#include <stdio.h>

/* How many iterations? */
#define ITERATIONS (100000000)

/* Which bit of the counter to test? */
#define BIT 1

#ifdef CMOV

#define choose(i, a, b) ({          \
    unsigned long result;           \
    asm("testl %1,%2 ; cmovne %3,%0"    \
        :"=r" (result)          \
        :"i" (BIT),         \
         "g" (i),           \
         "rm" (a),          \
         "0" (b));          \
    result; })

#else

#define choose(i, a, b) ({          \
    unsigned long result;           \
    asm("testl %1,%2 ; je 1f ; mov %3,%0\n1:"   \
        :"=r" (result)          \
        :"i" (BIT),         \
         "g" (i),           \
         "g" (a),           \
         "0" (b));          \
    result; })

#endif

int main(int argc, char **argv)
{
    int i;
    unsigned long sum = 0;

    for (i = 0; i < ITERATIONS; i++) {
        unsigned long a = 5, b = 7;
        sum += choose(i, a, b);
    }
    printf("%lu\n", sum);
    return 0;
}

gcc -Wall -O2 cmov.c

time ./a.out 600000000

real 0m0.540s user 0m0.065s sys 0m0.001s

gcc -Wall -O2 -DCMOV cmov.c time ./a.out

600000000

real 0m0.522s user 0m0.055s sys 0m0.000s

linus这个结论过时了,毕竟07年。

新机器cmov是快的。这个测试比较简单没有引入cacheline的影响

改成godbolt