分支预测和 UB(未定义行为)

Joe*_*oel 1 c c++ cpu-architecture undefined-behavior branch-prediction

我对分支预测了解一些。这发生在 CPU 上,与编译无关。尽管您可能能够告诉编译器一个分支是否比另一个分支更有可能,例如在 C++20 中,通过[[likely]]and [[unlikely]](请参阅cppreference)这与 CPU 执行的分支预测是分开的(请参阅我可以使用我的代码改进分支预测吗? ?)。

据我所知,当我有一个循环(带有退出条件)时,CPU 会预测退出条件不会得到满足,并尝试在循环内执行一些操作,即使条件尚未检查。如果 CPU 预测正确,它会节省一些时间,一切都会好起来。然而,如果它无法正确预测会发生什么?我知道这会对性能造成影响,但我不知道一些已经完成的操作是否被丢弃或逆转,或者只是如何处理。

现在我想出了两个简单的例子。第一个(如果我们忽略编译器可能只是在编译时计算总和并且我假设没有发生优化)对于 CPU 来说应该很容易预测。循环条件始终相同,并且循环中的条件仅切换一次。这意味着预测将为我们带来很好的性能提升,即使它失败了几次,添加一个数字也可以很容易地逆转。

在第二个示例中,退出条件也很容易预测。在循环体中,我int通过分配一个新数组malloc。请注意,我不是故意释放它的,因为我希望分配能够长期成功,以便 CPU 预测到这一成功。有时,当我用完内存(我没有计算总内存消耗并假设内存不会移动到磁盘)或发生其他错误时,分配会失败。这意味着ptrwill beNULL并且取消引用它是UB。没有定义会发生什么,它可能只是一个空操作,使我的程序崩溃或导致我的电脑飞走。因此我得出结论,CPU 不能简单地撤消这一点,我想知道会发生什么。

#include <stdlib.h>

#define VERSION 1

#if VERSION == 1
int main() {
    size_t sum = 0ull;

    for (size_t i = 0ull, max = 1'000ull; i < max;  ++i) {
        if (i < (max / 2)) {
            sum += 2 * i;
        }
        else {
            sum += i;
        }
    }

    return 0;
}

#else
int main() {
    int* ptr = NULL;

    for (size_t i = 0ull, max = 1'000'000ull; i < max; ++i) {
        ptr = (int*)malloc((sizeof * ptr) * 1'000ull);

        if (ptr) {
            *ptr = 1234;
        }

        // free(ptr)
    }

    return 0;
}
#endif
Run Code Online (Sandbox Code Playgroud)

分支预测是 CPU 的任务,而 UB 显然存在于 C 和 C++ 中,所以我认为这个问题的答案不需要一种特定的语言,我的代码应该适用于两种语言。然而,如果所选语言有所不同,我对 C++ 比 C 更感兴趣,但会很高兴得到任何答案。

P__*_*J__ 6

分支预测与UB没有任何关系

UB是从实际实现中抽象出来的C或C++语言概念。只能从源码层面进行分析。如果你的代码中有 UB,那么编译器基本上可以自由地按照标准做它想做的事情指定在这种情况下应该发生什么

如果您的源代码不调用 UB,则编译器必须发出代码(执行时)在所有平台上具有相同的可观察行为

在 C++20 中通过 [[likely]] 和 [[unlikely]] (参见首选项)这与 CPU 执行的分支预测是分开的

它早在 C++20 之前就已作为编译器扩展(例如 GCC __builtin_expect)存在,并且只是一个提示对编译器的在“正常”编程中,这是一个很少使用的功能,您应该仅在非常特定的情况下使用它,当它可以显着提高性能时(例如编写操作系统内核的低级部分或快速设备驱动程序)

我宁愿建议关注语言本身(理解概念)而不是深奥的实现细节。

  • @MarekR:[“强制反馈\[否决票\]将*极大地*阻碍Stack Exchange当前的工作方式”](https://meta.stackexchange.com/a/325417)。[不鼓励在评论中询问投反对票的原因。](https://meta.stackexchange.com/questions/74559/is-it-now-discouraged-to-ask-for-reasons-for-downvotes-as- a-评论)(我尚未对此答案进行投票。) (2认同)