3

我只是在尝试[[unlikely/likely]]使用/std:c++latest.

为此,我在底部使用http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html提供的代码的修改版本Appendix A

#include <array>
#include <cstdint>
#include <random>
#include <chrono>

std::uint16_t clamp(int i) {
    if (i < 0) [[unlikely]] {
        return 0;
    }
    else if (i > 0xFFFF) {
        return 0xFFFFu;
    }

    return i;
}

int main() {
    std::mt19937 gen(42);
    std::bernoulli_distribution d(.001), up_down(.5);

    std::vector<int> data;
    for (std::size_t i = 0; i != 1000000; ++i) {
        if (d(gen)) {
            data.push_back(up_down(gen) ? -1 : 0xFFFFF);
        }
        else {
            data.push_back(1);
        }
    }

    auto Prev = std::chrono::high_resolution_clock::now();

    std::uint32_t result = 0;
    for (int i = 0; i != 10000; ++i) {
        for (auto val : data) {
            result += clamp(val);
        }
    }

    auto After = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> Elapsed = After - Prev;
    std::chrono::milliseconds Time = std::chrono::duration_cast<std::chrono::milliseconds>(Elapsed);
    std::cout << (Time.count()) << '\n';

    return result > 5 ? 1 : 2;
}

请注意,所有编译都是在 x64 发布模式下使用/O2最新版本的 Visual Studio 2019 (16.10.3) 和 Intel(R) Core(TM) i7-7700HQ 2.8Ghz CPU 完成的。

然后我测试了 using [[unlikely]][[likely]]并且没有属性会影响所花费的时间。

首先测试[[unlikely]]]我发现在我的系统上运行大约需要 6750 毫秒。然后我进行了测试[[likely]],它也需要大约 6750 毫秒才能运行。起初我认为这可能只是因为属性是提示,因此编译器可以忽略它们。然后我进行了测试no attribute(只是不使用[[unlikely/likely]]),代码运行时间约为 9000 毫秒。如果编译器之前忽略了属性,那么它应该给出相同的 6750ms 时间,对吧?

然后我回去测试[[likely]],发现它现在运行在 ~9000 毫秒???在这一点上,我真的很困惑,所以回去检查[[unlikely]],发现它在 ~6750ms 内运行。再次检查[[likely]]它现在运行在 ~6750 毫秒。

这太奇怪了,经过一些挖掘查看生成的程序集后,我发现有时生成的程序集会超过 6000 行,有时会低于 2000 行,随后编译???对于相同代码的后续编译也是如此。经过一番谷歌搜索后,我发现了一个奇怪的评论:

为什么 Godbolt 生成的 asm 输出与我在 Visual Studio 中的实际 asm 代码不同?

而现在我更加困惑了,为什么 MSVC 会生成不同的代码?

回到我的实验,我根据编译顺序发现了这些结果:

  • No attribute=> [[unlikely]]=>[[likely]]

    〜9000ms =>〜6750ms =>〜6750ms并继续〜6750ms以进行后续[[likely]]编译并切换回[[unlikely]]获得相同的结果,而切换回No attribute获得〜9000ms。

  • No attribute=> [[likely]]=>[[unlikely]]

    ~9000ms => ~9000ms => ~9000ms 和后续[[unlikely]]编译得到相同的 ~9000ms 结果,这在切换到时是相同的,[[likely]]并且仅在编译后编译时表现出第一个序列中显示的行为No attribute

为了确保这不是一些随机的怪癖,我多次运行这些测试而不在每一步编译(只需运行从文件资源管理器生成的 .exe 文件)并获得一致的结果。我什至从每个不同的编译序列中保存了每个不同的 .exe 文件,然后再次运行它们,得到了同样奇怪的结果。

我还没有比较 .exe 字节,但我想避免这样做,因为我不太精通该领域“^-^

我错过了什么,这是一个错误吗?一切都如此不一致,这一切似乎都如此奇怪。

4

0 回答 0