[性能分析与优化]循环展开(perf + cpp)

循环展开与性能优化分析

循环展开

概念

循环展开的核心思想是减少循环迭代次数,同时在每次迭代中执行更多的操作。

优势

  1. 减少分支预测开销

    1. 分支指令减少:循环条件判断次数显著降低

    2. 分支预测改善:更简单的控制流模式有利于预测器工作

    3. 流水线效率提升:减少流水线清空和气泡

  2. 提高指令级并行(ILP)
  3. 隐藏内存访问延迟
  4. 改善缓存性能

Perf

根据以上分析可知,最主要需要分析的就是branch与branch-misses

perf record -e branches,branch-misses ./benchmark

用例代码

测试以[1024]的向量乘法为例,分别对朴素实现与AVX实现尝试比较循环展开

void vector_mult_basic(const float* a, const float* b, float* result, size_t n) {
    for (size_t i = 0; i < n; ++i) {
        result[i] = a[i] * b[i];
    }
    return ;
}

void vector_mult_unrolled(const float* a, const float* b, float* result, size_t n) {
    size_t i = 0;
    // 主循环处理4的倍数个元素
    for (; i + 3 < n; i += 4) {
        result[i] = a[i] * b[i];
        result[i+1] = a[i+1] * b[i+1];
        result[i+2] = a[i+2] * b[i+2];
        result[i+3] = a[i+3] * b[i+3];
    }
    // 处理剩余元素
    for (; i < n; ++i) {
        result[i] = a[i] * b[i];
    }
    return ;
}

void vector_mult_avx(const float* a, const float* b, float* result, size_t n) {
    size_t i = 0;
    
    // 新增:处理前面未对齐的部分
    for (; (reinterpret_cast<uintptr_t>(a + i) % 32 != 0) && i < n; ++i) {
        result[i] = a[i] * b[i];
    }

    // 主循环:使用对齐加载/存储
    for (; i + 7 < n; i += 8) {
        __m256 avx_a = _mm256_load_ps(a + i);  // 对齐加载
        __m256 avx_b = _mm256_load_ps(b + i);
        __m256 avx_result = _mm256_mul_ps(avx_a, avx_b);
        _mm256_store_ps(result + i, avx_result);  // 对齐存储
    }
    
    for (; i < n; ++i) {
        result[i] = a[i] * b[i];
    }
    return ;
}

void vector_mult_avx_unrolled(const float* a, const float* b, float* result, size_t n) {
    size_t i = 0;
    
    // 新增:处理前面未对齐的部分
    for (; (reinterpret_cast<uintptr_t>(a + i) % 128 != 0) && i < n; ++i) {
        result[i] = a[i] * b[i];
    }

    // 4倍循环展开,交错加载和计算以减少数据依赖
    for (; i + 31 < n; i += 32) {
        // 提前加载所有数据
        __m256 avx_a1 = _mm256_load_ps(a + i);
        __m256 avx_a2 = _mm256_load_ps(a + i + 8);
        __m256 avx_a3 = _mm256_load_ps(a + i + 16);
        __m256 avx_a4 = _mm256_load_ps(a + i + 24);
        
        __m256 avx_b1 = _mm256_load_ps(b + i);
        __m256 avx_b2 = _mm256_load_ps(b + i + 8);
        __m256 avx_b3 = _mm256_load_ps(b + i + 16);
        __m256 avx_b4 = _mm256_load_ps(b + i + 24);
        
        // 执行乘法运算
        __m256 avx_result1 = _mm256_mul_ps(avx_a1, avx_b1);
        __m256 avx_result2 = _mm256_mul_ps(avx_a2, avx_b2);
        __m256 avx_result3 = _mm256_mul_ps(avx_a3, avx_b3);
        __m256 avx_result4 = _mm256_mul_ps(avx_a4, avx_b4);
        
        // 存储结果
        _mm256_store_ps(result + i, avx_result1);
        _mm256_store_ps(result + i + 8, avx_result2);
        _mm256_store_ps(result + i + 16, avx_result3);
        _mm256_store_ps(result + i + 24, avx_result4);
    }
    
    // 剩余处理部分保持不变
    for (; i + 7 < n; i += 8) {
        __m256 avx_a = _mm256_load_ps(a + i);
        __m256 avx_b = _mm256_load_ps(b + i);
        __m256 avx_result = _mm256_mul_ps(avx_a, avx_b);
        _mm256_store_ps(result + i, avx_result);
    }
    
    for (; i < n; ++i) {
        result[i] = a[i] * b[i];
    }
    return ;
}

执行结果

basicbasic_unrolledavxavx_unrolled
branch106650631 5277378 2659714 16490 
branch-misses116481 66915 27262 6884 
time(us)14051019419367
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值