微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 [[unlikely/likely]] 属性时,MSVC C++ 编译器在相同代码的不同版本上提供不一致的性能

如何解决使用 [[unlikely/likely]] 属性时,MSVC C++ 编译器在相同代码的不同版本上提供不一致的性能

我只是在尝试使用 [[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 上完成的。

然后我测试了如何使用 [[unlikely]][[likely]] 并且没有属性会影响所用的时间。

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

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

这太奇怪了,在对生成的程序集进行一些挖掘之后,我发现有时生成的程序集会超过 6000 行,有时会在 2000 行以下加上后续编译???对于相同代码的后续编译也是如此。在谷歌搜索之后,我发现了一条奇怪的评论

Why godbolt generate different asm output than my actual asm code in Visual Studio?

现在我更困惑了,为什么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 字节,但我想避免这样做,因为我不是很精通那个领域"^-^

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。