串行代码导致执行时间过长
现象
应用编码时,串行代码可能存在以下问题:
- 由于A函数执行过长导致B函数调用被阻塞,应用执行效率降低,执行时间变长。
- 循环体内对函数调用时易产生串行调用逻辑,单次调用结束后才进行下一次调用,导致循环体执行时间过长,使应用整体执行效率降低。
调优思路
通过鲲鹏DevKit系统性能分析的HPC应用分析定位耗时较长的函数,对源码进一步分析,将不存在依赖关系的A、B函数进行并行调用,或在循环体内并行调用多个函数,提高执行效率,缩短应用运行时间。
操作步骤
- 准备示例源码serial_time.c并进行编译。
gcc serial_time.c -O3 -o serial_time -fopenmp -lm
- 使用鲲鹏DevKit系统性能分析执行HPC应用分析任务。
表1 任务配置参数说明 参数
说明
分析对象
应用
应用路径
输入程序所在的绝对路径,例如本示例将代码样例放在服务器“/opt/testdemo/serial_time”路径下。
分析类型
HPC应用分析
采集模式
OpenMP模式;本示例主要是对OMP的应用进行分析。
分析模式
统计分析
采样模式
Detail模式
采样时长
默认
- 查看任务结果。分析后观察执行时间,发现串行代码执行时间占比99.89%,严重影响整个应用的执行效率。图1 应用执行时间
- 源码分析。
main函数占比最高,进一步分析源码,源码内main中关键函数SericalTimeBench使用了串行执行。
图2 Hotspotsvoid SericalTimeBench(Point *pointA, Point *pointB, double *pointDis, int n) { assert(pointA != NULL && pointB != NULL && pointDis != NULL); int i; for (i = 0; i < n; i++) { pointDis[i] = ComputPointDistance(&pointA[i], &pointB[i]); } }
- 使用OpenMP并行调用耗时的计算代码。
void SericalTimeBench_OPT(Point *pointA, Point *pointB, double *pointDis, int n) { assert(pointA != NULL && pointB != NULL && pointDis != NULL); int i; #pragma omp parallel for shared (n) private (i) for (i = 0; i < n; i++) { pointDis[i] = ComputPointDistance(&pointA[i], &pointB[i]); } }
- 重新编译后分析。
使用1中的命令重新编译应用并运行,观察运行时间。
优化效果
优化后重新编译应用并运行,应用执行耗时由优化前的299秒变为27秒左右,时间大幅缩短。
图3 优化后分析结果
