1. 目标
对数组求和,对比ARM(neon)向量化优化(SIMD)和循环展开,还有 O0 O1优化的效率对比。
2. 测试代码
| #include <arm_neon.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <time.h> |
| |
| |
| #define N 1024000 |
| |
| |
| int32_t neonSum(int32_t *arr,int n) |
| { |
| |
| int32x4_t vec={0}; |
| |
| int32x4_t tempSum={0}; |
| |
| int32_t sum=0; |
| for(int i=0;i<n/4*4;i+=4) |
| { |
| |
| vec = vld1q_s32(&arr[i]); |
| |
| |
| tempSum = vaddq_s32(tempSum,vec); |
| } |
| |
| for(int i=n/4*4;i<n;i++) |
| sum += arr[i]; |
| |
| tempSum = vpaddq_s32(tempSum,tempSum); |
| |
| tempSum = vpaddq_s32(tempSum,tempSum); |
| |
| sum += vgetq_lane_s32(tempSum,0); |
| return sum; |
| } |
| |
| void main() |
| { |
| clock_t start,end; |
| int32_t arr[N] = {0}; |
| int32_t sum=0; |
| |
| |
| for(int i=0;i<N;i++) |
| arr[i] = (int32_t)(rand()%11); |
| |
| start = clock(); |
| #if 1 |
| sum = neonSum(arr,N); |
| #elif 0 |
| for(int i=0;i<N;i++) |
| sum+=arr[i]; |
| #else |
| for(int i=0;i<N;i+=4) |
| { |
| sum+=arr[i]; |
| sum+=arr[i+1]; |
| sum+=arr[i+2]; |
| sum+=arr[i+3]; |
| } |
| #endif |
| end = clock(); |
| |
| |
| |
| printf("sum %d useSec %f\n",sum,(double)(end-start)/CLOCKS_PER_SEC); |
| } |
3. 编译命令
-fopt-info-all :显示编译优化信息;
O1 O2 默认不开启向量化优化,需要参数指定;O3默认开启向量化优化。
| gcc sum_simd.c -o sum_simd_0 -O0 -fopt-info-all |
| gcc sum_simd.c -o sum_simd_1 -O1 -ftree-vectorize -fopt-info-all |
| gcc sum_simd.c -o sum_simd_2 -O2 -ftree-vectorize -fopt-info-all |
| gcc sum_simd.c -o sum_simd_3 -O3 -fopt-info-all |
测试脚本
| #!/bin/bash |
| |
| dir=out |
| |
| > "$dir" |
| |
| echo "start $(date)" >> out |
| |
| |
| opt=(0 1 2 3) |
| |
| func=(0 1 2) |
| |
| for lev in "${opt[@]}"; do |
| for f in "${func[@]}"; do |
| for((i=0;i<4;i++)); do |
| yhrun -N1 -n1 -pthcp1 ./sum_simd_"$lev" "$f" | tee -a "$dir" |
| |
| done |
| done |
| done |
| |
| echo "end $(date)" >> out |
4. 测试数据
优化函数\优化参数 |
O0 |
O1 向量化 |
O2 向量化 |
O3 |
源码 |
0.004388 |
0.001618 |
0.001641 |
0.001591 |
循环展开 |
0.003876 |
0.001675 |
0.001610 |
0.001642 |
NEON Intrinsic SIMD |
0.002840 |
0.001667 |
0.001596 |
0.001593 |
5. 结果分析
(1) O0 优化:neon > 循环展开 > 源码。只有NEON Intrinsic函数在开启了向量化,所以效率最高;循环展开减少了for循环次数效率次之。neon比源码效率提升了 54% ;
(2) O1/O2/O3 编译器向量化优时,源码、循环展开、neon效率差不多;
(3) 向量化优化可以通过 NEON Intrinsic 函数实现,或者使用编译优化选项;但是复杂的循环结构,需要自己手动实现向量化优化代码。
备注:当前数据规模为1024000,预计数据规模的变化几乎没有影响。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库