(如何)使用LLVM机器码分析器预测代码片段的运行时间?

Dav*_*Far 5 c c++ performance assembly llvm-mca

我使用llvm-mca来计算一堆代码的总周期,认为它们会预测它的运行时间.但是,动态测量运行时几乎没有相关性.那么:为什么由llvm-mca计算的总周期不能准确预测运行时?我可以用llvm-mca以更好的方式预测运行时吗?


细节:

我想知道,对于不同类型的下面的代码的运行时间begin(和end)迭代器,对startValue正在0.00ULL:

std::accumulate(begin, end, starValue)
Run Code Online (Sandbox Code Playgroud)

为了预测运行时,我使用Compiler Explorer(https://godbolt.org/z/5HDzSF)及其LLVM机器码分析器(llvm-mca)插件,因为llvm-mca是"一个使用可用信息的性能分析工具"在LLVM(例如调度模型)中静态测量性能".我使用了以下代码:

using vec_t = std::vector<double>;

vec_t generateRandomVector(vec_t::size_type size)
{
    std::random_device rnd_device;
    std::mt19937 mersenne_engine {rnd_device()};
    std::uniform_real_distribution dist{0.0,1.1};
    auto gen = [&dist, &mersenne_engine](){
        return dist(mersenne_engine);
    };
    vec_t result(size);
    std::generate(result.begin(), result.end(), gen);
    return result;
}

double start()
{
    vec_t vec = generateRandomVector(30000000);
    vec_t::iterator vectorBegin = vec.begin();
    vec_t::iterator vectorEnd = vec.end();
    __asm volatile("# LLVM-MCA-BEGIN stopwatchedAccumulate");
    double result = std::accumulate(vectorBegin, vectorEnd, 0.0);
    __asm volatile("# LLVM-MCA-END");    
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但是,我看到llvm-mca计算机的总周期与运行相应的std :: accumulate的挂钟时间之间没有相关性.例如,在上面的代码中,Total Cycles是2806,运行时间是14ms.当我切换到startValue时0ULL,Total Cycles是2357,但运行时间是117ms.

Had*_*ais 5

TL:DR:LLVM-MCA 分析了这些注释之间的整个代码块,就好像它是循环的主体一样,并向您展示了所有这些指令的 100 次迭代的循环计数。

但是除了实际的(微小的)循环外,大多数指令都是循环设置和循环后的 SIMD 水平总和,实际上只运行一次。(这就是为什么周期数是数千,而不是 400 = 100 倍vaddpdSkylake 上0.0带有double累加器的版本的 4 周期延迟。)

如果您取消选中 Godbolt 编译器资源管理器上的“//”框,或修改 asm 语句以添加 nop like "nop # LLVM-MCA-END",您将能够在 asm 窗口中找到这些行并查看 LLVM-MCA 正在查看的内容“环形”。


LLVM MCA 模拟指定的汇编指令序列,并计算在指定的目标架构上执行每次迭代估计需要的周期数。LLVM MCA 进行了许多简化,例如(在我的脑海中):(1)它假设所有条件分支都通过,(2)它假设所有内存访问都是写回内存类型,并且全部命中L1 缓存,(3) 它假设前端工作在最佳状态,以及 (4)call指令没有跟随到被调用的过程中,它们只是失败。还有其他假设我现在想不起来了。

本质上,LLVM MCA(如 Intel IACA)仅对后端计算绑定的简单循环准确。在 IACA 中,虽然支持大多数指令,但有一些指令没有详细建模。例如,假设预取指令仅消耗微体系结构资源,但基本为零延迟,并且对存储器层次结构的状态没有影响。然而,在我看来,MCA 完全忽略了这些指令。无论如何,这与您的问题并不是特别相关。

现在回到你的代码。在您提供的编译器资源管理器链接中,您没有将任何选项传递给 LLVM MCA。因此默认目标架构生效,即工具运行的任何架构。这恰好是SKX。您提到的循环总数是针对 SKX 的,但不清楚您是否在 SKX 上运行代码。您应该使用该-mcpu选项来指定架构。这与-march您传递给 gcc 的无关。另请注意,将核心周期与毫秒进行比较是没有意义的。您可以使用该RDTSC指令以核心周期来衡量执行时间。

请注意编译器如何内联对std::accumulate. 显然,这段代码从405行开始,最后一条指令std::accumulate在444行,一共38条指令。LLVM MCA 估计与实际性能不匹配的原因现在已经很清楚了。该工具假设所有这些指令都在循环中执行大量迭代。显然,情况并非如此。从 420-424 只有一个循环:

.L75:
        vaddpd  ymm0, ymm0, YMMWORD PTR [rax]
        add     rax, 32
        cmp     rax, rcx
        jne     .L75
Run Code Online (Sandbox Code Playgroud)

只有此代码应该是 MCA 的输入。在源代码层面,真的没有办法告诉 MCA 只分析这段代码。您必须手动内联std::accumulate并将LLVM-MCA-BEGINLLVM-MCA-END标记放置在其中的某个位置。

当传递0ULL而不是0.0to 时std::accumulate,LLVM MCA 的输入将从汇编指令 402 开始并在 441 结束。请注意,MCA 不支持的任何指令(例如vcvtsi2sdq)将完全从分析中省略。实际上处于循环中的代码部分是:

.L78:
        vxorpd  xmm0, xmm0, xmm0
        vcvtsi2sdq      xmm0, xmm0, rax
        test    rax, rax
        jns     .L75
        mov     rcx, rax
        and     eax, 1
        vxorpd  xmm0, xmm0, xmm0
        shr     rcx
        or      rcx, rax
        vcvtsi2sdq      xmm0, xmm0, rcx
        vaddsd  xmm0, xmm0, xmm0
.L75:
        vaddsd  xmm0, xmm0, QWORD PTR [rdx]
        vcomisd xmm0, xmm1
        vcvttsd2si      rax, xmm0
        jb      .L77
        vsubsd  xmm0, xmm0, xmm1
        vcvttsd2si      rax, xmm0
        xor     rax, rdi
.L77:
        add     rdx, 8
        cmp     rsi, rdx
        jne     .L78
Run Code Online (Sandbox Code Playgroud)

请注意,jns目标地址在块中某处的代码中有一个条件跳转,。MCA 只会假设跳跃会失败。如果在实际运行代码时情况并非如此,MCA 将不必要地增加 7 条指令的开销。还有另一个跳跃,jb但我认为这个跳跃对于大向量并不重要,并且大部分时间都会失败。最后一个跳转,jne,也是最后一条指令,所以 MCA 会假设下一条指令又是最上面的一条。对于足够多的迭代,这个假设是完全正确的。

总的来说,很明显第一个代码比第二个代码小得多,所以它可能要快得多。您的测量确实证实了这一点。您也不需要使用微架构分析工具来了解原因。第二个代码只是做了更多的计算。因此,您可以很快得出结论,0.0就所有架构的性能和代码大小而言,传递都更好。

  • @BartekBanachewicz 请注意,`-ffast-math` 已传递给 gcc 以生成代码。请参阅 [gcc 的 ffast-math 实际上是做什么的?](/sf/ask/519446581/)。我没有彻底检查代码,但我确实希望两个版本在 `-ffast-math` 方面都是正确的(是的,当使用 `-ffast-math` 时,它们可能不会产生相同的结果,没关系)。 (2认同)

归档时间:

查看次数:

215 次

最近记录:

6 年,11 月 前