You need to enable JavaScript to run this app. 为何gcc -O3下malloc初始化的数组AVX遍历反而比无优化版慢?
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 15:36:10