

新闻资讯
技术教程必须手动设置编译选项为-O2或-O3(推荐-O2 -march=native),启用Show compilation output并禁用Demangle symbols,才能通过汇编密度与模式识别内联、循环展开和向量化效果。
Compiler Explorer(Godbolt)开箱即用,但新手常误以为“点了编译就完事”——g++ 或 clang++ 默认启用 -O0,生成的汇编充斥着栈帧操作、冗余寄存器搬运,完全看不出性能瓶颈在哪。真正用于性能分析,必须手动改编译选项。
Compilation options 输入框里,
把 -O0 换成 -O2 或 -O3(推荐 -O2 -march=native 模拟本地环境)Show compilation output,确认没有报错或警告(比如未定义行为会触发 UBSan 干预,导致汇编失真)Filters → Demangle symbols:开启后函数名被还原成 C++ 符号(如 _Z3fooi → foo(int)),反而干扰你观察内联和模板实例化痕迹性能优化的核心判断依据,不在代码行数,而在汇编指令的“密度”与“模式”。Godbolt 的左侧源码和右侧汇编是逐行映射的(鼠标悬停某行 C++,右侧高亮对应指令),但需主动找信号:
bar(x) 没有对应 call bar,而是直接看到 add eax, 1 等原函数体指令for (int i=0; i,汇编里连续四组相同计算指令,无 jmp 回跳
vpaddd、vmovdqu 等以 v 开头的指令 → AVX/SSE 向量化成功(前提是数据对齐且无依赖)mov eax, DWORD PTR [rdi] 单字节加载 → 检查数组是否指针别名(加 restrict)、或循环是否有条件分支打断向量友好性Clang 和 GCC 对同一段代码的优化策略常不同,尤其在模板推导、constexpr 展开、内存模型处理上。Godbolt 的多编译器并排视图是性能调优的关键工具:
Add new…,添加 clang 17.0.1 和 gcc 13.2,保持编译选项一致(如都用 -O2 -std=c++20)std::span 的边界检查,Clang 可能完全删掉,GCC 可能保留 cmp + jae
lea rax, [rdi + rsi*4] 一条指令完成地址计算,GCC 拆成 shl rsi, 2 + add rax, rdi —— 前者更优Godbolt 默认链接标准库,std::vector::push_back 这类函数会展开成几十行汇编,掩盖你关心的核心逻辑。要聚焦纯算法部分:
立即学习“C++免费学习笔记(深入)”;
static 或 [[gnu::noinline]] 标记待分析函数,防止被外联到其他上下文中#include 或 std::cout:它们引入大量初始化代码和锁操作,污染汇编主体std::string:其 small-string optimization 实现因编译器而异,汇编差异大且与性能无关;改用 const char* 或 std::array
__attribute__((used)) 强制保留函数符号,再在右侧汇编中搜索该函数名(如 my_hot_loop),跳过所有启动代码int my_hot_loop(const int* a, const int* b, int n) {
int sum = 0;
for (int i = 0; i < n; ++i) {
sum += a[i] * b[i];
}
return sum;
}这段代码在 clang++ -O3 -mavx2 下大概率生成带 vpmulld 和 vpaddd 的向量化循环,在 gcc -O2 下可能仍是标量循环——差异不是 bug,而是优化器对数据依赖的不同建模。盯住那几行核心计算指令,比纠结“为什么没向量化”更有价值。