Android-emmc性能测试

在 Android 可以用来测试 emmc io 性能的工具有很多, 比如 fio, iozone, dd 等。 看了大半天的 fio, iozone, 感觉用起来比较复杂,相对来说还是使用 dd 简单方便。接下来我们就以 dd 为主介绍一下如何测试 emmc 的 io 性能。

1. 页面缓存

在开始之前,我们先了解一下页面缓存的概念。简单的说就是系统会把读取过的部分文件缓存到内存中,以此加快热点文件的读取速度,提高磁盘的 IO 速度。
具体的原理见 Linux内核文件Cache机制
为了测试 emmc 的真实读写性能,我们需要先把页面缓存给清理:

1
echo 1 > /proc/sys/vm/drop_caches

我们先看看页面缓存的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
KKHi3751V810:/ # busybox dd if=/dev/block/mmcblk0 of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 5.023993 seconds, 203.8MB/s
KKHi3751V810:/ #
KKHi3751V810:/ # busybox dd if=/dev/block/mmcblk0 of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 0.564027 seconds, 1.8GB/s
KKHi3751V810:/ #
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches
KKHi3751V810:/ # busybox dd if=/dev/block/mmcblk0 of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 5.103213 seconds, 200.7MB/s
KKHi3751V810:/ #

连续执行两次同样参数的 dd 命令, 从 /dev/block/mmcblk0 (也就是我们的 emmc) 块设备中读取内容, 写到 /dev/null 。/dev/null 是一个虚拟设备,写入这个路径并不会保存,我们可以认为这个设备的写入速度无限大, 也就是写入速度不会成为这个命令的瓶颈, 我们这个命令主要是为了测试 emmc 的读取速度。可以看到第一次执行的结果是 203.8MB/s, 第二次执行的结果是 1.8GB/s。从这个数据来看,页面缓存极大的提高了热点文件的读取速度。然后我们用 echo 1 > /proc/sys/vm/drop_caches 命令清除一下页面缓存,再执行同样的 dd 命令,发现速度跟第一次差不多了。

2. 写入性能测试

我们分为两种情况来测试

2.1 写入块设备

cache 分区一般是用来存放 OTA 升级包的,正常状态下挂载失败也不影响系统的正常运行,所以我们拿 cache 分区来作写入测试,先找到 cache 对应的块设备文件

1
2
3
KKHi3751V810:/ #ls -l /dev/block/platform/soc/f9830000.emmc/by-name/cache                         <
lrwxrwxrwx 1 root root 21 1970-01-01 08:00 /dev/block/platform/soc/f9830000.emmc/by-name/cache -> /dev/block/mmcblk0p18
KKHi3751V810:/ #

cache 分区的块设备文件为 /dev/block/mmcblk0p18。
写入测试:

1
2
3
4
5
6
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches                             
KKHi3751V810:/ # busybox dd if=/dev/zero of=/dev/block/mmcblk0p18 bs=1M count=1024 conv=fsync
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 24.122624 seconds, 42.4MB/s
KKHi3751V810:/ #

输入文件为 /dev/zero,是一个虚拟设备,我们可以认为这个设备的读取速度无限大,也就是读取速度不会影响到写入的速度。
bs=1M : 一次写入 1M
count=1024 : 写入 1024 次,也就是写入的数据总量为 1G
conv=fsync : dd 结束前,把数据同步到 emmc,如果没加这个参数的话,数据可能还在缓存之中。为了确保数据准确,一定要加这个参数。

重复测试几次,速度基本在 42M/s 左右。

2.2 写入文件

1
2
3
4
5
6
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches
KKHi3751V810:/ # busybox dd if=/dev/zero of=/data/ddtest.bin bs=1M count=1024 conv=fsync <
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 30.607905 seconds, 33.5MB/s
KKHi3751V810:/ #

重复测试几次,速度基本在 33M/s 左右。相对直接写块设备文件慢了 10M/s 左右。这可能是文件系统带来的影响。

3. 读取测试

3.1 读取块设备

直接用我们上面介绍清除缓存的例子就行,这里就不再重复了。
从上面的例子得到的数据为 203M/s 左右。

3.1 读取文件

1
2
3
4
5
6
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches                             
KKHi3751V810:/ # busybox dd if=/data/ddtest.bin of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.0GB) copied, 4.915286 seconds, 208.3MB/s
KKHi3751V810:/ #

直接拿测试写入速度时生成的文件,重复测试几次,速度基本上在 208MB/s 左右。

4. 对比iozone

Android 系统源码中并没有 iozone,我们得自己人官网上下载编译,我下载时最新版本为 iozone3_489, 这个版本已经有 Android.mk 在代码里面了, 将源码放到 Android 系统源码里面 mm 即可。
随机读写测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches
KKHi3751V810:/ # iozone -azecI -+n -L64 -S32 -r1m -s1024m -i0 -i2 -w -f /data/iozonetest.bin
Iozone: Performance Test of File I/O
Version $Revision: 3.489 $
Compiled for 64 bit mode.
Build: linux-arm

Contributors:William Norcott, Don Capps, Isom Crawford, Kirby Collins
Al Slater, Scott Rhine, Mike Wisner, Ken Goss
Steve Landherr, Brad Smith, Mark Kelly, Dr. Alain CYR,
Randy Dunlap, Mark Montague, Dan Million, Gavin Brebner,
Jean-Marc Zucconi, Jeff Blomberg, Benny Halevy, Dave Boone,
Erik Habbinga, Kris Strecker, Walter Wong, Joshua Root,
Fabrice Bacchella, Zhenghua Xue, Qin Li, Darren Sawyer,
Vangel Bojaxhi, Ben England, Vikentsi Lapa,
Alexey Skidanov, Sudhir Kumar.

Run began: Wed Feb 12 20:47:58 2020

Auto Mode
Cross over of record size disabled.
Include fsync in write timing
Include close in write timing
O_DIRECT feature enabled
No retest option selected
Record Size 1024 kB
File size set to 1048576 kB
Setting no_unlink
Command line used: iozone -azecI -+n -L64 -S32 -r1m -s1024m -i0 -i2 -w -f /data/iozonetest.bin
Output is in kBytes/sec
Time Resolution = 0.000001 seconds.
Processor cache size set to 32 kBytes.
Processor cache line size set to 64 bytes.
File stride size set to 17 * record size.
random random bkwd record stride
kB reclen write rewrite read reread read write read rewrite read fwrite frewrite fread freread
1048576 1024 74782 0 199299 71520

iozone test complete.
KKHi3751V810:/ #

从结果来看,随机读速度为 199299 kB/s , 大概为 200M/s。 随机写速度为 71520 kB/s, 大概为 70M/s。
重复测试几次结果差不多,读的速度基本跟 dd 的一致。写入的比 dd 的快了将近一倍。

5. 对比fio

5.1 写入文件速度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches                             
KKHi3751V810:/ # fio -filename=/dev/block/mmcblk0p18 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=1m -size=1G -numjobs=4 -runtime=60 -group_reporting -name=rand_write_1m
rand_write_1m: (g=0): rw=randwrite, bs=1M-1M/1M-1M/1M-1M, ioengine=psync, iodepth=1
...
fio-2.2.6
Starting 4 threads
Jobs: 3 (f=3): [w(3),_(1)] [98.1% done] [0KB/80734KB/0KB /s] [0/78/0 iops] [eta 00m:01s]
rand_write_1m: (groupid=0, jobs=4): err= 0: pid=8316: Wed Feb 12 21:03:34 2020
write: io=4096.0MB, bw=83067KB/s, iops=81, runt= 50493msec
clat (msec): min=10, max=1361, avg=48.60, stdev=44.45
lat (msec): min=10, max=1361, avg=48.86, stdev=44.44
clat percentiles (msec):
| 1.00th=[ 18], 5.00th=[ 22], 10.00th=[ 23], 20.00th=[ 26],
| 30.00th=[ 34], 40.00th=[ 37], 50.00th=[ 46], 60.00th=[ 48],
| 70.00th=[ 58], 80.00th=[ 65], 90.00th=[ 76], 95.00th=[ 87],
| 99.00th=[ 104], 99.50th=[ 114], 99.90th=[ 758], 99.95th=[ 1123],
| 99.99th=[ 1369]
bw (KB /s): min= 1343, max=41353, per=25.49%, avg=21171.93, stdev=4637.55
lat (msec) : 20=1.51%, 50=60.52%, 100=36.40%, 250=1.37%, 500=0.02%
lat (msec) : 750=0.05%, 1000=0.05%, 2000=0.07%
cpu : usr=0.43%, sys=1.13%, ctx=10620, majf=0, minf=6
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=0/w=4096/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
WRITE: io=4096.0MB, aggrb=83067KB/s, minb=83067KB/s, maxb=83067KB/s, mint=50493msec, maxt=50493msec

Disk stats (read/write):
mmcblk0: ios=54/8332, merge=5/888, ticks=60872/378355, in_queue=439181, util=100.00%
KKHi3751V810:/ #

4个线程的平均写入速度为 bw=83067KB/s,大概是 80M/s, 比 dd 也快了一倍多。

5.2 读取文件速度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
KKHi3751V810:/ # echo 1 > /proc/sys/vm/drop_caches                             
KKHi3751V810:/ # fio -filename=/dev/block/mmcblk0 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=1m -size=1G -numjobs=4 -runtime=60 -group_reporting -name=rand_read_1m
rand_read_1m: (g=0): rw=randread, bs=1M-1M/1M-1M/1M-1M, ioengine=psync, iodepth=1
...
fio-2.2.6
Starting 4 threads
Jobs: 1 (f=1): [_(3),r(1)] [96.2% done] [148.5MB/0KB/0KB /s] [148/0/0 iops] [eta 00m:01s]
rand_read_1m: (groupid=0, jobs=4): err= 0: pid=7889: Wed Feb 12 20:56:21 2020
read : io=4096.0MB, bw=171813KB/s, iops=167, runt= 24412msec
clat (msec): min=4, max=9350, avg=19.50, stdev=215.06
lat (msec): min=4, max=9350, avg=19.50, stdev=215.06
clat percentiles (msec):
| 1.00th=[ 7], 5.00th=[ 8], 10.00th=[ 8], 20.00th=[ 11],
| 30.00th=[ 11], 40.00th=[ 11], 50.00th=[ 11], 60.00th=[ 14],
| 70.00th=[ 14], 80.00th=[ 14], 90.00th=[ 14], 95.00th=[ 14],
| 99.00th=[ 16], 99.50th=[ 30], 99.90th=[ 2638], 99.95th=[ 4113],
| 99.99th=[ 9372]
bw (KB /s): min= 964, max=145420, per=46.41%, avg=79740.53, stdev=25495.41
lat (msec) : 10=13.77%, 20=85.55%, 50=0.29%, 100=0.12%, 500=0.05%
lat (msec) : 750=0.05%, 2000=0.05%, >=2000=0.12%
cpu : usr=0.22%, sys=3.16%, ctx=9195, majf=0, minf=1030
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=4096/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
READ: io=4096.0MB, aggrb=171813KB/s, minb=171813KB/s, maxb=171813KB/s, mint=24412msec, maxt=24412msec

Disk stats (read/write):
mmcblk0: ios=8365/46, merge=15/47, ticks=633927/61332, in_queue=695214, util=99.20%
KKHi3751V810:/ #

4个线程的平均读速度为 bw=171813KB/s, 大概为 170M/s。

综合对比 dd, iozone, fio 这几个工具发现,读的速度基本上差不多,但写速度差距比较大,可能跟设置的参数有关。
为了简单起见,我们只采用 dd 的结果作为参考数据即可。

参考文章:
[IO测试工具之fio详解]:https://www.cnblogs.com/raykuan/p/6914748.html
[emmc读写速度性能分析]:https://blog.csdn.net/jekenzhuang/article/details/81142178
[dd命令的conv=fsync,oflag=sync/dsync]:https://blog.csdn.net/menogen/article/details/38059671
[页面缓存:内存和文件之间的那些事]:https://linux.cn/article-9528-1.html
[在 Linux 上如何清除内存的 Cache、Buffer 和交换空间]:https://linux.cn/article-5627-1.html
[iozone的使用]:http://wowothink.com/b871283/
[eMMC读写性能和稳定性验证]:http://wowothink.com/7ffb6593/