为何gcc -O3下malloc初始化的数组AVX遍历反而比无优化版慢?
Haswell架构下AVX程序编译优化后性能倒挂问题
测试背景
此前相关已关闭的提问更新测试细节后重新发起验证,本次测试目标为量化AVX指令在Haswell架构下的实际性能提升幅度,测试覆盖的内存规模为1ul << 30个double类型元素(总计4GB内存空间),测试逻辑分为两个分支:
- 纯标量循环分支:逐元素遍历数组完成值计算与赋值
- 手动AVX内联代码分支:按每4个double的粒度完成批量加载、计算、写回操作
核心测试代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <cstdlib> #include <algorithm> #include <immintrin.h> #include <chrono> #include <complex> using Type = double; int main() { size_t b_size = 1; b_size = (1ul << 30) * b_size; Type *d_ptr = (Type*)malloc(sizeof(Type)*b_size); // 初始化数组为全0 for(int i = 0; i < b_size; i++) { d_ptr[i] = 0; } std::cout << "malloc finishes!" << std::endl; #ifndef AVX512 // 纯标量测试分支 auto a = std::chrono::high_resolution_clock::now(); for (int i = 0; i < b_size; i ++) { d_ptr[i] = i*0.1; } std::cout << d_ptr[b_size-1] << std::endl; auto b = std::chrono::high_resolution_clock::now(); long long diff = std::chrono::duration_cast<std::chrono::microseconds>(b-a).count(); std::cout << "No avx takes " << diff << std::endl; #else // 手动AVX测试分支 auto a = std::chrono::high_resolution_clock::now(); // 版本1:逐组计算元素值 for (int i = 0; i < b_size; i += 4) { __m256d tmp1 = _mm256_loadu_pd(reinterpret_cast<double*>(&d_ptr[i])); __m256d tmp2 = _mm256_set_pd(0.1*(i+3),0.1*(i+2),0.1*(i+1),0.1*i); __m256d tmp3 = _mm256_add_pd(tmp1,tmp2); _mm256_storeu_pd(reinterpret_cast<double*>(&d_ptr[i]),tmp3); } // 版本2:递推逻辑向量化(参考成熟向量化实现改写) // auto a = std::chrono::high_resolution_clock::now(); // __m256d tmp2 = _mm256_set1_pd(0.1); // __m256d base = _mm256_set_pd(-1.0,-2.0,-3.0,-4.0); // __m256d tmp3 = _mm256_set1_pd(4.0); // for (int i = 0; i < b_size; i += 4) // { // __m256d tmp1 = _mm256_loadu_pd(reinterpret_cast<double*>(&d_ptr[i])); // base = _mm256_add_pd(base,tmp3); // __m256d tmp5 = _mm256_mul_pd(base,tmp2); // tmp1 = _mm256_add_pd(tmp1,tmp5); // _mm256_storeu_pd(reinterpret_cast<double*>(&d_ptr[i]),tmp1); // } std::cout << d_ptr[b_size-1] << std::endl; auto b = std::chrono::high_resolution_clock::now(); long long diff = std::chrono::duration_cast<std::chrono::microseconds>(b-a).count(); std::cout << "avx takes " << diff << std::endl; #endif }
异常实测结果
不同编译配置下的程序运行耗时完全违背常规性能认知:
- 纯标量代码、
-O3编译版本:总耗时3824740微秒 - 手动AVX代码、无任何编译优化参数版本:总耗时2121917微秒
- 手动AVX代码、
-O3编译版本:总耗时6307190微秒
切换为递推逻辑的第二版AVX实现后,相同的性能倒挂现象依然复现:
- 手动AVX代码、无任何编译优化参数版本:总耗时2151390微秒
- 手动AVX代码、
-O3编译版本:总耗时5965288微秒
核心疑问
为何开启-O3优化后,手动AVX实现的程序运行耗时会达到无优化版本的3倍左右,完全背离编译优化提升执行效率的基本预期,当前无法定位性能异常的根因。
编译配置说明
- 测试可执行文件名中的
_avx512_标识,对应编译时传入的-march=native参数;当前测试使用的Haswell架构仅支持AVX2指令集,不具备AVX512硬件执行能力。 - 测试可执行文件名中的
_manual与_auto标识,用于区分是否通过-DAVX512宏参数启用手动编写的AVX内联代码;其中_auto版本为纯标量赋值代码,由编译器自动执行向量化流程,和手动编写内联函数实现累加逻辑的版本做对照。
内容的提问来源于stack exchange,提问作者flyree
相关产品推荐
相关产品推荐

