基于OpenMP的C代码并行计算中,效率大于1是否具有合理性?
我现在在搭载Intel i5-2410M(双核支持超线程,总共4个逻辑核心)的设备上运行带有OpenMP指令的C代码。通过使用#pragma omp parallel for simd,我获得了约1000倍的加速比,代码片段如下:
#pragma omp parallel shared(a,b,c) private(i,j,k) { #pragma omp for simd collapse (3) for (i=0; i<5000; i++){ for (j=0; j<5000; j++){ for (k=0; k<5000; k=k+1){ a[i][j]=(a[i][j])+((b[i][k])*(c[k][j])); } } } }
根据效率计算公式:效率 = 加速比 / 处理器数量,这里处理器数量按4个逻辑核心算的话,效率会远大于1。请问这种情况合理吗?
当然合理!这看起来有点反直觉,但其实是多种优化效果叠加的结果,我来给你拆解清楚:
SIMD指令的核心贡献:你用了
simd子句,这会让编译器生成单指令多数据(SIMD)指令。Intel i5-2410M支持SSE4.2,每条SIMD指令可以同时处理4个单精度浮点数(或者2个双精度)。这相当于每个逻辑核心内部又提供了额外的“指令级并行性”,这部分能力是不算在传统的“处理器数量”(逻辑核心数)统计里的,但它实实在在地成倍提升了计算吞吐量。超线程的利用率提升:你的CPU是双核4线程,超线程技术能让单个物理核心在等待内存加载/存储的空闲周期里,切换处理另一个线程的任务,大幅减少核心的空闲时间,进一步挖掘了硬件的潜力。
缓存优化的隐性加成:你的代码是三重循环的矩阵乘法,原本
c[k][j]的列访问模式会导致缓存命中率极低,但collapse(3)加上SIMD优化后,编译器很可能自动做了循环重排、数据预取或者向量化调整,让缓存的利用率比单线程版本高了很多——单线程版本可能因为缓存频繁失效拖慢了速度,而并行+SIMD版本的缓存效率提升,也会让加速比远超核心数的倍数。基准版本的优化差异:还有一种常见情况,如果你用来对比的单线程版本没有开启高级编译优化(比如没加
-O3),而OpenMP并行版本因为编译选项默认开启了-O3这类优化,就会导致单线程基准本身跑得很慢,加速比被进一步放大。
所以说,效率大于1完全是合理的——传统的效率公式里的“处理器数量”只统计了逻辑核心,但SIMD的指令级并行、缓存利用率的提升、超线程的流水线优化,这些都能让实际的计算效率远超单个核心的基础性能,最终让加速比远超过核心数,效率自然就大于1了。
内容的提问来源于stack exchange,提问作者Claudia White

