性能分析过程
前提条件
- 服务器和操作系统正常运行。
- PC端已经安装SSH远程登录工具。
- 目标环境上鲲鹏性能定界工具、系统性能分析工具已经安装完成,并正常运行。
操作步骤
- 从GitHub下载hotspot_io_before.cc文件,上传到“/home/demo”目录,执行如下命令切换至源码目录。
cd /home/demo
- 编译源码文件。
g++ -g -O2 -std=c++17 /home/demo/hotspot_io_before.cc -o /home/demo/hotspot_io_before
- 使用随机数生成大文件。
dd if=/dev/urandom of=tmp.txt bs=1M count=4096
在当前目录下生成tmp.txt文件。
- 查看应用运行时间。
time ./hotspot_io_before tmp.txt
执行命令后,发现应用整体运行时间为16.3秒(4.1秒+12.2秒),读取数据时间为4.1秒,处理数据时间为12.2秒。根据运行时间可以判断,读取数据时间占整体运行时间的25.15%,当前是一个文件驱动的数据装载的应用,因此初步认为I/O部分存在瓶颈。
图1 运行时间
- 使用鲲鹏性能定界工具定位问题。进入鲲鹏性能定界工具安装目录,xxx指版本号,请根据实际情况替换。
cd /home/ksys-x.x.x-Linux-aarch64
- 针对热点函数的分析,需先配置config.yaml文件。
- 打开config.yaml文件。
vim config.yaml
- 按“i”进入编辑模式。
- 将“hotspot”字段的“enabled”的默认值“false”修改为“true”。
- 按“Esc”,输入:wq!,按“Enter”保存并退出。
- 打开config.yaml文件。
- 采集应用的性能数据。
./ksys collect -d 10 /home/demo/hotspot_io_before /home/demo/tmp.txt
- -d 10:指定采集时间为10秒。
- /home/demo/hotspot_io_before /home/demo/tmp.txt:指定采集的应用以及应用依赖的文件参数。
图2 热点统计数据
在热点统计数据部分,主要的用户态process_buffer功能函数占整体程序的比例并不高(51%),与此同时内核态__arch_copy_to_user(通过函数调用栈可以发现:对应用户态应用中的read_file_to_buffer函数)函数占比却较高(29%)。考虑到__arch_copy_to_user调用栈中符合Arm平台中的read系统调用特征。因此认为用户态应用中read_file_to_buffer函数存在频繁的系统调用,导致应用的用户态时间在一定的情况下,内核态开销较大,存在优化空间。
对于比例不合适的函数调用,可以使用系统性能分析工具的热点函数分析中的火焰图功能来直观查看函数调用的特征,再进一步确定是否存在可以优化的函数调用栈。
- 使用系统性能分析工具进一步分析程序。切换至系统性能分析工具安装目录,xxx为指版本号,请根据实际情况替换。
cd /home/DevKit-Tuner-CLI-x.x.x-Linux-Kunpeng
- 使用系统性能分析工具对应用进行热点函数分析。
./devkit tuner hotspot --package -g -d 10 /home/demo/hotspot_io_before /home/demo/tmp.txt
- --package:设置生成报告数据压缩包,不指定压缩包名称和路径时默认在当前所在目录生成hotspot-时间戳.tar。
- -g:显示调用堆栈信息,将生成火焰图html文件,默认在当前目录下生成Flamegraph-时间戳.html文件。
- -d 10:指定采集时间为10秒。
- /home/demo/hotspot_io_before /home/demo/tmp.txt:指定采集的应用以及应用依赖的文件参数。
查看热点函数分析报告,发现热点函数占比为61%和17% ,确定I/O系统调用多问题确实存在。
图3 热点函数分析报告
- 进一步查看生成的火焰图文件。
报告最后显示在/home/DevKit-Tuner-CLI-x.x.x-Linux-Kunpeng目录下生成Flamegraph开头的火焰图文件,查看火焰图文件发现其中左侧有62%是完全用户态的计算函数process_buffer,另外38%涉及到系统调用。其中38%部分又可以区分左半部分read的系统调用和右半部分内存相关的系统调用。分析可以从两个角度来优化:
- read系统调用优化。
- 内存相关系统调用优化。
具体选择的优化方案,需要结合实际的源代码进行选取。
图4 火焰图
- 查看源码文件,确定源码问题。
vim /home/demo/hotspot_io_before.cc
图5 源码文件
源码中read_file_to_buffer函数功能为读取数据,且采用传统的read/write方式,在处理大型文件时,易出现I/O处理占比较高的问题,而process_buffer函数功能为处理数据,所以主要优化读取数据的方式。