"逃生"和" Clobber"相当于MSVC

时间:2015-11-28 19:25:22

标签: visual-c++ benchmarking microbenchmark

Chandler Carruth's CppCon 2015 talk中,他引入了两个神奇的函数来击败优化器而不会有任何额外的性能损失。

供参考,以下是函数(使用GNU样式的内联汇编):

void escape(void* p)
{
    asm volatile("" : : "g"(p) : "memory");
}

void clobber()
{
    asm volatile("" : : : "memory");
}

它适用于任何支持GNU样式内联汇编的编译器(GCC,Clang,Intel编译器,可能还有其他编译器)。但是,他提到它在MSVC中不起作用。

检查Google Benchmark's implementation,似乎他们使用重新解释转换为volatile const char&并将其传递给隐藏在非gcc / clang编译器上的不同翻译单元中的函数。

template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
    internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
}

// some other translation unit
void UseCharPointer(char const volatile*) {}

然而,我对此有两个顾虑:

  1. 我可能会招致一个函数调用
  2. 有可能&#34;聪明&#34;链接时优化器可能会识别出UseCharPointer很小,内联它,然后丢弃我想要保留的所有代码,或者&#34;聪明的&#34;可能会允许优化器执行其他我不想要的重新排序。
  3. MSVC中是否有与GNU样式的汇编函数有较低级别的等价物?或者这是MSVC上最好的?

2 个答案:

答案 0 :(得分:4)

虽然我不知道MSVC的等效组装技巧,但Facebook在其Folly基准库中使用以下内容:

/**
 * Call doNotOptimizeAway(var) against variables that you use for
 * benchmarking but otherwise are useless. The compiler tends to do a
 * good job at eliminating unused variables, and this function fools
 * it into thinking var is in fact needed.
 */
#ifdef _MSC_VER

#pragma optimize("", off)

template <class T>
void doNotOptimizeAway(T&& datum) {
  datum = datum;
}

#pragma optimize("", on)

#elif defined(__clang__)

template <class T>
__attribute__((__optnone__)) void doNotOptimizeAway(T&& /* datum */) {}

#else

template <class T>
void doNotOptimizeAway(T&& datum) {
  asm volatile("" : "+r" (datum));
}

#endif

Here is a link to code on GitHub.

答案 1 :(得分:1)

我一直在寻找一种方法来在我自己的小型基准测试库中实现完全相同的目标。 关于MSVC的令人沮丧的事情是,针对x64的目标不允许__asm技巧,而x86允许它!

经过几次尝试,我重用了google的解决方案,而没有产生额外的电话! 令人高兴的是,该解决方案可与MSVC(/ Ox)和GCC(-O3)一起使用。

template <class T>
inline auto doNotOptimizeAway(T const& datum) {
    return reinterpret_cast<char const volatile&>(datum);
}

在呼叫站点,我根本不使用返回的volatile!

int main()
{
    int a{10};
    doNotOptimizeAway(a);
    return 0;
}

生成的ASM(Compiler Explorer

a$ = 8
main    PROC
        mov     DWORD PTR a$[rsp], 10
        movzx   eax, BYTE PTR a$[rsp]
        xor     eax, eax
        ret     0
main    ENDP