androbench跑分对应IO特性分析
在博文:手机IO workload解析里面已经指出androbench测试时,产生的IO都是direct IO。
因为对手机反复androbench测试多次,根据测试log和代码分析,结论是:
Android跑分测试时,direct io对应的内核路径只有__blockdev_direct_IO里面会submit 大量bio的,该路径下其他函数仅仅submit了很少量的bio,这些很少量的bio不影响跑分测试结果的.
支撑上面结论的原因是:
1) androbench在进行跑分测试时, direct io路径对应的文件读写数据都是通过__blockdev_direct_IO下发到磁盘上的,该路径其他函数也会下发数据到磁盘上,
但是要么下发的是元数据,比如vfs_fsync_range这个函数(因为带O_SYNC进行IO测试了),要么是异常情况下,下发的少量同步脏数据,比如这个filemap_write_and_wait_range函数。
这些脏数据不会算到文件总的读写测试数据里面(即我的另外一篇文档:手机IO workload解析里面提到的androbench顺序读写产生的1536MB数据),
因为androbench在进行跑分测试之前已经fsync了待测试文件,所以只有很小概率异常情况下,会走到filemap_write_and_wait_range函数里去同步文件脏数据。
2) direct io对应的都是文件覆盖写,不会在__blockdev_direct_IO里面或者其他地方触发文件系统层的new 物理块分配工作。
3) androbench测试时,属于静态存储性能测评。即测试时,是会关闭wiki,清空后台app,所以androbench测试时,不会有多的其他IO(非跑分测试产生的)的干扰。
androbench跑分性能排查方法
首先从块设备层排查
1 顺序读写排查方法:
androbench IO性能调查时,可以根据directio_analysis工具产生的log去计算出顺序读写性能数据,该性能数据大多数情况下都会非常接近于androbench测试出的性能数据。
如果比较明显地好于androbench测试出的性能(顺序读写差距大于5MB/s),那么性能问题应该主要出在文件系统层。
如果基本接近androbench测试出的性能,那么性能问题或者瓶颈出在block层和存储bsp层,大概率出在存储bsp层。因为进行androbench测试时,整个android系统都空闲下来了,不会怎么出现块设备层拥塞之类的问题。
肯定不会出现差于androbench测试出的性能,因为测试数据下发到磁盘上都是通过__blockdev_direct_IO进行下发的。
2 随机读写排查方法:
见下面
其次进行其他层面排查
文件系统层面排查可以用工具ioworkload_analysis去排查。
排查是存储bsp层还是block层出问题的,可以用工具biosnoop。具体排查方法,见下面。
androbench跑分性能排查实践操作
以e1-q为例,进行androbench的性能排查实践操作介绍。
顺序读写性能排查
块设备层排查
androbench跑分时,执行下面命令:
adeb shell directio_analysis 0 2>&1 | tee directio_analysis.log
对directio_analysis.log的分析如下:
1 顺序读
1) cat directioslower.log | awk '{if($5=="R" && $3=="8818")print}' | awk '{sum += $7};END {print sum}'
1610612736 即为1536MB。
(8818为androbench进行顺序读写测试的线程ID)
正好等于androbench跑分顺序读产生的文件数据量,所以说明direct IO路径正是全部通过__blockdev_direct_IO来下发跑分产生的所有文件数据的。
2) cat directioslower.log | awk '{if($5=="R" && $3=="8818")print}' | awk '{sum += $8};END {print sum}'
2074.63 (单位:ms)
上面数据为顺序读测试在block层和bsp层耗费的时间。
3)根据上面两步,算出顺序读性能为:
1536MB / 2074.63 = 740.37298217 (单位:MB/s),
该读速度跟androbench app显示的顺序读速度:738MB/s相比,是比较接近的。
2 顺序写
1)
cat directioslower.log | awk '{if($5=="W" && $3=="8818")print}' | awk '{sum += $7};END {print sum}'
1610612736 也为1536MB
cat directioslower.log | awk '{if($5=="W" && $3=="8818")print}' | awk '{sum += $8};END {print sum}'
7315.01 (顺序写测试在block层和bsp层耗费的时间,单位:ms)
2)
算出顺序写性能为:209.979207137(单位:MB/s),
该写速度跟androbench app显示的顺序读速度:209.52MB/s相比,也是比较接近的。
3 顺序读写分析及结论
androbench的顺序读写测试项目,在内核栈里面,依次经过文件系统层 + block层 + bsp层。
无论怎么测试,用上面方法计算,从block层 + bsp层得到顺序读写速度应该是好于androbench app显示的顺序读写速度的。
如果明显好于app显示的顺序读写性能的话,说明性能问题出在文件系统层,肯定是文件系统层哪个地方有延迟,造成app显示的性能数据比较差。
如果稍微好于或者说接近于app显示的顺序读写性能的话,说明性能问题或者性能瓶颈出在block层 + bsp层。
所以上面顺序读写数据计算显示,性能问题或者说性能瓶颈出在block层 + bsp层。
随机读写性能排查
块设备层排查
随机读写和顺序读写对应的log都是directioslower.log,对该log的分析如下:
1 随机读
1) 每笔随机读在块设备层的累加总耗时
cat directioslower.log | awk '{if($5=="R" && $3!="8818")print}' | awk '{sum += $8};END {print sum}'
11326.5
2) 总共完成了多少随机读
cat directioslower.log | awk '{if($5=="R" && $3!="8818")print}' | wc -l
47838
3) 多少个随机读
cat directioslower.log | awk '{if($5=="R" && $3!="8818")print}' | wc -l
47838
4) 随机读总共进行了多长时间
从 directioslower.log 里面看到发起时间是21.723 ,结束时间是23.228。
进行了23.228 - 21.723 = 1.505 (单位:s)
5) 做随机读工作的8进程总共耗时1.51 × 8 = 12.08s.
由此可以得出另外一个重要指标:12.08 - 11.33(上面的随机读累加总耗时) = 0.65s. 这个差值即为8进程除了 块设备层+bsp层之外的总耗时.
6) 随机读的性能(iops指标)
47838 / 1.505 = 31786.046511628 (单位:iops)
该值跟androbench app显示的31912.82也基本上接近了。
2 随机写
1) 总共完成了多少随机写
cat directioslower.log | awk '{if($5=="W" && $3!="8818")print}' | wc -l
47930
2) 随机写测试总共进行了25.013 - 23.240 = 1.773 s时间
3) 47930 / 1.773 = 27033.276931754 (单位:iops)
该值跟androbench app显示的27314.86也基本上接近了。
3 随机读写分析及结论
根据上面计算的数据,已经得知在块设备层的IO 性能状况跟androbench显示的IO性能是比较一致的,块设备层的IO性能已经能够比较准确地反应androbench跑分性能了。
说明我们可以根据上面的log来定位排查跑分中随机读写性能问题了。
androbench的随机读写是8线程并发进行不断地每4k数据读写的。并发读写状况下,可以按照上面计算8进程块设备层+bsp层耗时,还有其他层面耗时对比,来排查性能。
实际进一步进行性能排查工作时,可以根据随机读写的IO workload特点(详见:手机IO workload解析),biosnoop工具和其他bcc工具进行具体性能排查。
特别是用biosnoop工具(见下面的)是能够排查出是否出是存储bsp层导致的性能问题的。
块设备+bsp层IO性能评估
利用biosnoop工具,在androbench跑分时,可以准确地评估块设备层+存储bsp层应对跑分场景的IO处理性能。
存储bsp层IO处理性能评估
androbench跑分时,执行下面命令:
adeb shell biosnoop 2>&1 | tee biosnoop.log
对biosnoop.log分析如下:
1) log最后一列即为:每个IO请求从block_req_issue开始,block_req_complete结束所花费的时间。
对biosnoop 加-Q选项测试时,log最后一列为:每个IO请求从block_req_insert开始,block_req_complete结束所花费的时间。
2) 从log里面第3,5和7列能够区分出是IO请求性能数据是出自androbench顺序读 or 顺序写 or 随机读 or 随机写测试项产生的。
单进程非4096大小字节的IO测试,即为顺序读写测试。然后可以再根据是r or w,来区分是顺序读还是顺序写。
多进程并发4096大小字节的IO测试,即为随机读写测试。然后可以再根据是r or w,来区分是随机读还是随机写。
所以根据上面的分析,可以方便用shell命令提取出随机读写和顺序读写每个测试项跑分时对应的IO请求性能数据。
比如可以提取出IO请求从发起到完成的平均耗时,最大和最小耗时。
这样可以在做不同存储硬件,不同Android版本的androbench跑分性能对比时,可以很方便地看出IO请求在存储bsp层的耗时性能。