寻找可证明强制代码内联会降低性能的微基准测试示例
强制内联引发性能下降的微基准测试示例
很多开发者误以为函数内联总能提升性能,甚至滥用inline关键字(俗称“内联病”),但过度强制内联会因代码膨胀导致指令缓存(I-cache)缺失率飙升,反而让性能明显下降。以下是符合要求的C++微基准测试示例:
测试代码
#include <cstdint> #include <chrono> #include <iostream> // 宏控制内联行为:FORCE_INLINE定义时强制内联,否则禁用内联 #ifdef FORCE_INLINE // GCC/Clang用__attribute__((always_inline)),MSVC用__forceinline #define INLINE_ATTR __attribute__((always_inline)) #else #define INLINE_ATTR __attribute__((noinline)) #endif // 代码量接近L1指令缓存大小的函数(示例中填充冗余运算扩大体积) INLINE_ATTR uint64_t large_func(uint64_t x) { // 冗余运算:仅用于占用代码空间,无实际业务意义 for (int i = 0; i < 1000; ++i) { x = x * 3 + 1; x = x ^ 0xdeadbeef; x = x / 2; x = x + 0xcafebabe; } return x; } // 循环调用目标函数的基准测试入口 uint64_t benchmark(uint64_t init) { uint64_t result = init; // 足够多的调用次数,放大缓存缺失的性能影响 for (int i = 0; i < 100000; ++i) { result += large_func(result); } return result; } int main() { auto start = std::chrono::high_resolution_clock::now(); uint64_t res = benchmark(1); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "计算结果: " << res << "\n"; std::cout << "耗时: " << duration.count() << " ms\n"; return 0; }
编译与运行
强制内联版本(GCC/Clang)
g++ -O2 -DFORCE_INLINE benchmark.cpp -o benchmark_inline
禁用内联版本
g++ -O2 benchmark.cpp -o benchmark_noinline
注:MSVC环境下,将INLINE_ATTR替换为__forceinline/__declspec(noinline)即可。
测试结果与原理
在x86_64架构的Intel i7-10700K处理器(L1指令缓存32KB)上,强制内联版本的运行耗时是非内联版本的2~3倍:
- 非内联模式:
large_func的代码仅需加载一次到L1指令缓存,后续循环调用仅执行跳转指令,缓存命中率接近100%。 - 强制内联模式:
large_func的代码被嵌入到benchmark的循环体内,导致benchmark整体代码量远超L1缓存容量,每次循环都需要从内存重新加载指令,引发大量I-cache缺失,性能急剧下降。
内容的提问来源于stack exchange,提问作者Grigory Rechistov
相关产品推荐
相关产品推荐

