【发布时间】:2019-06-04 01:34:26
【问题描述】:
我使用 llvm-mca 来计算一段代码的总周期,认为它们会预测其运行时间。然而,动态测量运行时间几乎没有相关性。那么:为什么 llvm-mca 计算的总周期不能准确预测运行时间?我可以使用 llvm-mca 以更好的方式预测运行时间吗?
详情:
我想知道以下代码对于不同类型的begin(和end)迭代器的运行时间,因为startValue 是0.0 或0ULL:
std::accumulate(begin, end, starValue)
为了预测运行时,我使用了 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;
}
但是,我发现 llvm-mca 的计算机总周期与运行相应 std::accumulate 的挂钟时间之间没有相关性。例如,在上面的代码中,Total Cycles 是 2806,运行时间是 14ms。当我切换到 startValue 0ULL 时,Total Cycles 是 2357,但运行时间是 117ms。
【问题讨论】:
-
总 CPU 周期已经停止,直接对应于 1990 年代左右的 CPU 时间。现在有更多的事情会影响实际运行一段代码的时间,例如缓存、分支预测、外部影响等。这样的静态分析不仅需要代码,还需要代码将要运行的确切 CPU 模型,甚至有可能准确。
-
好吧,好吧,在这种情况下,它可能与编译器必须进行大量转换的事实有关;似乎
ull版本实际上是在那里挑选的。 Those two calls to double conversion seem particularly bad,但这只是一个猜测。你用什么编译器构建这个来进行基准测试? -
如果您查看 godbolt.org/z/tTCyRW 的 llvm-mca 输出的底部,您会看到
error: invalid instruction mnemonic 'cvtsi2sdq'和call instructions are not correctly modeled. Assume a latency of 100cy。也许这会导致错误的测量结果。但是,在我的原始示例中,测量的程序集中没有调用指令。我会将这个问题转发给 LLVM-MCA 的某个人... -
@BartekBanachewicz:连续数组(如
std::vector或数组)对于数据布局来说是最好的。根据循环,对齐 SIMD 的数据会有所帮助。至于现代 x86 上循环的static analysis of performance 的资源,stackoverflow.com/tags/x86/info 有很多好东西的链接,尤其是 Agner Fog 的微架构指南 (agner.org/optimize),它确实详细介绍了英特尔和 AMD 的管道/OoO exec CPU 足够详细,可以准确预测很多情况下的性能。 -
如果 CPU 以恒定频率运行,则总周期和时间呈线性相关。对于超标量/乱序流水线 CPU,其他事情,例如总(动态)指令是非常可变的,尤其是当缓存未命中可能会使流水线停滞数百个周期时。动态 CPU 频率(用于在空闲/低工作负载下省电)在 2000 年代成为了一件事情,而不是早在 90 年代。如果您的测试没有“预热”CPU 以使其首先达到最大涡轮增压,那么微基准测试可能会出现问题,但这不是问题所在。 (LLVM-MCA 正在分析循环外的代码。)
标签: c++ c performance assembly llvm-mca