我只是在尝试[[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 字节,但我想避免这样做,因为我不太精通该领域“^-^
我错过了什么,这是一个错误吗?一切都如此不一致,这一切似乎都如此奇怪。