嵌入式Linux磁盘(硬盘、SD卡)读写性能测试

背景

在Windows下有一些磁盘基准测试工具,用于测试硬盘/SD卡的读写速度,如ATTO Disk Benchmark(注:单词「benchmark」就是基准检查的意思)。

上一篇文章「市面常见存储卡的读写速度对比测试」,就是用ATTO Disk Benchmark工具在Windows下测试得到的数据。

在PC上测试到的磁盘读写性能数据,是否适用嵌入式设备呢?SD卡的读写速度,受限制于SD卡本身固有的性能之外,还跟读卡器,主CPU性能等有一定的关系。所以,同一张SD卡,想要知道其在嵌入式设备中实际的读写性能,还需要在嵌入式环境中实际测试下才准确。

ATTO Disk Benchmark工具在测试SD卡读写性能时,会依次以512B、1K、2K、4K……1M、2M等作为一次读写的包大小来进行测试,这样的测试会得知以多大的包去读写SD卡,才能发挥出其性能的极限。以下介绍dd时,不会做这么多的测试,本文的重点是讲解如何使用dd命令来测试磁盘读写速度,至于要像ATTO Disk Benchmark工具这样自动化测试,可以使用shell脚本调用dd命令去实现。

dd使用指定的输入和输出块大小来拷贝文件,它每次从输入读取指定大小的一个块写到独立的输出块去,通过这种方法来测试读写速度。

测试环境

  • 硬件:嵌入式ARM
  • 系统:

    # cat /proc/version
    Linux version 3.0.8 (root@Ubuntu10) (gcc version 4.4.1 (Hisilicon_v100(gcc4.4-290+uclibc_0.9.32.1+eabi+linuxpthread)) ) #252 Mon Aug 17 11:33:23 CST 2015

  • 内存:512M

  • SD卡:如果没有特殊说明,本文都是使用以下SD卡进行测试,其class 4理论标称写速度为4M/s,如下图所示,同时附上在PC上使用ATTO Disk Benchmark工具的测试结果图:

    这里写图片描述

内核缓存

在开始测试之前,必须先弄明白“内核缓存”的概念,否则很容易测出错误的数据。有关“内核缓存”的详细概念,可参考「附录一 linux内核缓存」。以下摘选重点:

向文件中写入数据时,数据会先缓存在Page Cache中,内存中的这部分数据被标注为Dirty Page,linux系统上的pdflush守护进程会跟进系统设置将将这部分Dirty Page刷到磁盘上,也可以通过fsync系统调用在数据写入后强制刷到磁盘上。将写入的数据刷入磁盘时,是以Buffer Cache为单位,每次回写若干个Buffer Cache。

读取文件内容时,系统会一次性连续读取包括所请求页面在内的多个页面(如预读页面个数为n)。如果请求的页面在page cache中命中的话,会从缓存中返回页面内容,增加读取的页面数量,异步读取2n个页面;如果请求的页面没有在page cache中命中,也会增加读取页面数量,同步读取2n个页面。

为了避免内核缓存对测试带来影响,在每条测试语句之前,都要先清除linux内核缓存,命令如下(详情可参考「附录二 如何清除linux内核缓存」):

# sync; echo 3 > /proc/sys/vm/drop_caches

测试磁盘写能力

正确的命令

# sync; echo 3 > /proc/sys/vm/drop_caches
#
# dd bs=1M count=500 if=/dev/zero of=/mnt/sdisk/ftp/outfile 
500+0 records in
500+0 records out
524288000 bytes (500.0MB) copied, 122.160615 seconds, 4.1MB/s
# 
# sync; echo 3 > /proc/sys/vm/drop_caches
#
# dd bs=20k count=25600 if=/dev/zero of=/mnt/sdisk/ftp/outfile
25600+0 records in
25600+0 records out
524288000 bytes (500.0MB) copied, 123.208135 seconds, 4.1MB/s
# 

因为/dev/zero是一个伪设备,它只产生空字符流,对它不会产生IO,所以,IO都会集中在of文件中,of文件只用于写,所以这个命令相当于测试磁盘的写能力。

以上dd命令结束的时候,数据其实还没有真正写到磁盘上去,而是写到内核缓存就返回了,究竟有多少数据写入磁盘了是由内核控制的。有两种方法可以让内核缓存数据写入磁盘:

  • 方法一:使用conv=fsync选项,明确要求dd命令每写一次数据,都强制将内核缓存写入磁盘中。如果count设置很大的值(N),会触发N次的强制写入磁盘,这不符合实际的使用情况,除非像数据库插入这种写动作,否则一般的应用程序都不会频繁要求系统缓存数据强制刷入磁盘,这样反而不能发挥出写速度的最佳性能,而是让内核自己控制。

  • 方法二:写入的数据量要足够大,越大越好,超过内存值为佳,让内核缓存放不小,间接的逼迫内核将数据写到磁盘中,以此测试出更接近实际的速度值,越大越能测出接近真实的速度值。这种方法dd命令返回,虽然有可能还是有数据残留在内核缓存中未写入磁盘,但只要写入的数据足够大,这点缓存带来的影响是可以忽略不计的,以上测试就是采用本方法。

错误的命令

# sync; echo 3 > /proc/sys/vm/drop_caches
# dd bs=20M count=1 if=/dev/zero of=/mnt/sdisk/ftp/outfile
20+0 records in
20+0 records out
20971520 bytes (20.0MB) copied, 0.258525 seconds, 77.4MB/s
# 

77.4M/s,严重超出SD卡的标称值,肯定不可信。以上dd命令结束的时候,数据其实还没有真正写到磁盘上去,而是写到内核缓存就返回了,由于数据量太小,很快就写入内核缓存了,都没有触发写入磁盘,当然速度快到离谱。

# sync; echo 3 > /proc/sys/vm/drop_caches
# dd bs=20M count=1 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
1+0 records in
1+0 records out
20971520 bytes (20.0MB) copied, 5.810785 seconds, 3.4MB/s
# 

加上conv=fsync选项,强制dd命令每次写数据都写入磁盘,如此数据会更真实,但conv=fsync和count搭配是有陷阱的,往下看:

# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=40k count=512 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
512+0 records in
512+0 records out
20971520 bytes (20.0MB) copied, 7.742188 seconds, 2.6MB/s
# 
# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=20k count=1024 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
1024+0 records in
1024+0 records out
20971520 bytes (20.0MB) copied, 13.830230 seconds, 1.4MB/s
# 
# sync; echo 3 > /proc/sys/vm/drop_caches
#
# dd bs=10k count=2048 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
2048+0 records in
2048+0 records out
20971520 bytes (20.0MB) copied, 21.752566 seconds, 941.5KB/s
# 

同样是写入20M数据,使用了conv=fsync选项,但count设置为N多次,这样会触发N次的强制写入磁盘(每次写入的数据bs都很小),如此也会降低写入速度。这种方式也不符合实际情况。

似是而非的命令

conv=fsync选项搭配count=1,同时bs设置很大,让dd命令返回前保证数据已经被刷入磁盘,岂不是更能测试SD卡的写速度值。如:

# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=100M count=1 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
1+0 records in
1+0 records out
104857600 bytes (100.0MB) copied, 25.407060 seconds, 3.9MB/s
# 

理论上这么说是对的,但仔细想想,不太对劲。第一,应用程序(或者内核缓存),数据不会缓存到那么大(如上100M)才触发写一次,这样丢失数据的风险太大。第二受限制于物理内存大小,bs能设置的上限值有限,超过可用的内存大小就会报错,如下所示:

# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=500M count=1 conv=fsync if=/dev/zero of=/mnt/sdisk/ftp/outfile
dd: memory exhausted
# 

测试磁盘读能力

正确的命令

# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null 
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 5.119588 seconds, 15.6MB/s
#

因为/dev/sdb1是一个物理分区,对它的读取会产生IO,/dev/null是伪设备,相当于黑洞,of到该设备不会产生IO,所以,这个命令的IO只发生在/dev/sdb1上,也相当于测试磁盘的读能力。

错误的命令

不清理内核缓存,对同一个文件连续进行多次读速度测试,如下所示:

# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null 
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 5.119588 seconds, 15.6MB/s
#
# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 0.307665 seconds, 260.0MB/s
# 
# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 0.290451 seconds, 275.4MB/s
# 
# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 0.237559 seconds, 336.8MB/s
# 

你会发现,对同一个文件(在linux中“一切皆文件”,设备也是文件)进行多次读速度测试,第一次读速度是15MB/s,第二次之后竟然都飙升到260MB/s,远远超出SD卡的标称值,不科学啊。这其实是linux内核缓存I/O中的“文件Cache”在作祟,什么是文件Cache可参考「附录一 linux内核缓存」。

我对这种现象简单粗暴的理解:第一次读文件,是从磁盘卡中读取,是真实的读速度,读完之后该文件被内核缓存在内存中,第二次读时,只是从内存中获取文件数据(专业名词是cache命中),并没有真正的从磁盘读,所以速度贼快。

非要对同一文件进行多次的读测试,我们需要先清除linux内核的缓存,可以使用如下命令

# sync; echo 3 > /proc/sys/vm/drop_caches

来清除内核缓存,关于该命令的详细说明,可参考「附录二 如何清除linux内核缓存」。最后测试结果如下所示:

# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 5.136499 seconds, 15.6MB/s
# 
# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=20k count=4096 if=/dev/sda1 of=/dev/null
4096+0 records in
4096+0 records out
83886080 bytes (80.0MB) copied, 5.189734 seconds, 15.4MB/s
# 

测试同时读写能力

# sync; echo 3 > /proc/sys/vm/drop_caches
# 
# dd bs=20k count=25600 if=/dev/sda1 of=/mnt/sdisk/ftp/outfile
25600+0 records in
25600+0 records out
524288000 bytes (500.0MB) copied, 151.556191 seconds, 3.3MB/s
#

这个命令下,一个是物理分区,一个是实际的文件,对它们的读写都会产生IO(对/dev/sdb1是读,对mnt/sdisk/ftp/outfile写),假设他们都在一个磁盘中,这个命令就相当于测试磁盘的同时读写能力。

同样的,同一命令连续多次测试时,要记得清除内核缓存。

附录一 linux内核缓存

什么是缓存 I/O (Buffered I/O)

缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。缓存 I/O 有以下这些优点:

  • 缓存 I/O 使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的物理设备。

  • 缓存 I/O 可以减少读盘的次数,从而提高性能。

当应用程序尝试读取某块数据的时候,如果这块数据已经存放在了页缓存中,那么这块数据就可以立即返回给应用程序,而不需要经过实际的物理读盘操作。当然,如果数据在应用程序读取之前并未被存放在页缓存中,那么就需要先将数据从磁盘读到页缓存中去。对于写操作来说,应用程序也会将数据先写到页缓存中去,数据是否被立即写到磁盘上去取决于应用程序所采用的写操作机制:如果用户采用的是同步写机制( synchronous writes ), 那么数据会立即被写回到磁盘上,应用程序会一直等到数据被写完为止;如果用户采用的是延迟写机制( deferred writes ),那么应用程序就完全不需要等到数据全部被写回到磁盘,数据只要被写到页缓存中去就可以了。在延迟写机制的情况下,操作系统会定期地将放在页缓存中的数据刷到磁盘上。与异步写机制( asynchronous writes )不同的是,延迟写机制在数据完全写到磁盘上的时候不会通知应用程序,而异步写机制在数据完全写到磁盘上的时候是会返回给应用程序的。所以延迟写机制本身是存在数据丢失的风险的,而异步写机制则不会有这方面的担心。

文件 Cache

文件 Cache 是文件数据在内存中的副本,因此文件 Cache 管理与内存管理系统和文件系统都相关:一方面文件 Cache 作为物理内存的一部分,需要参与物理内存的分配回收过程,另一方面文件 Cache 中的数据来源于存储设备上的文件,需要通过文件系统与存储设备进行读写交互。从操作系统的角度考虑,文件 Cache 可以看做是内存管理系统与文件系统之间的联系纽带。因此,文件 Cache 管理是操作系统的一个重要组成部分,它的性能直接影响着文件系统和内存管理系统的性能。

为了提升磁盘设备的IO性能,操作系统会使用内存作为磁盘设备的cache,并使用memory map方式在访问时建立与文件系统的缓存映射。文件系统的缓存,是以Page Cache为单位,一个Page Cache包含多个Buffer Cache。

向文件中写入数据时,数据会先缓存在Page Cache中,内存中的这部分数据被标注为Dirty Page,linux系统上的pdflush守护进程会跟进系统设置将将这部分Dirty Page刷到磁盘上,也可以通过fsync系统调用在数据写入后强制刷到磁盘上。将写入的数据刷入磁盘时,是以Buffer Cache为单位,每次回写若干个Buffer Cache。

读取文件内容时,系统会一次性连续读取包括所请求页面在内的多个页面(如预读页面个数为n)。如果请求的页面在page cache中命中的话,会从缓存中返回页面内容,增加读取的页面数量,异步读取2n个页面;如果请求的页面没有在page cache中命中,也会增加读取页面数量,同步读取2n个页面。

文件 Cache 管理指的就是对这些由操作系统分配,并用来存储文件数据的内存的管理。 Cache 管理的优劣通过两个指标衡量:一是 Cache 命中率,Cache 命中时数据可以直接从内存中获取,不再需要访问低速外设,因而可以显著提高性能;二是有效 Cache 的比率,有效 Cache 是指真正会被访问到的 Cache 项,如果有效 Cache 的比率偏低,则相当部分磁盘带宽会被浪费到读取无用 Cache 上,而且无用 Cache 会间接导致系统内存紧张,最后可能会严重影响性能。

附录二 如何清除linux内核缓存

在 Linux 上如何清除内核缓存?

1.仅清除页面缓存(PageCache)

# sync; echo 1 > /proc/sys/vm/drop_caches

2.清除目录项和inode

# sync; echo 2 > /proc/sys/vm/drop_caches

3.清除页面缓存,目录项和inode

# sync; echo 3 > /proc/sys/vm/drop_caches 

上述命令的说明:

sync 将刷新文件系统缓冲区(buffer),命令通过“;”分隔,顺序执行,shell在执行序列中的下一个命令之前会等待命令的终止。正如内核文档中提到的,写入到drop_cache将清空缓存而不会杀死任何应用程序/服务,echo命令做写入文件的工作。

有关drop_caches文件的详细说明,可参考官方文档(以关键词drop_caches搜索).

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SD卡测试工具 更新说明: ================================================ V1.68 1.增加导出重要扇区功能,供改进软件用 ================================================ V1.67 1.支持多合一读卡器的制作,能找到读卡器的有卡插槽 2.在多处增加了数据可能丢失的警告 ================================================ V1.66 1.增加写保护跳过对话框,允许用户跳过写保护提示 2.增加备份和恢复磁盘的功能,类似克隆 3.可自定制启动文件包 ================================================ V1.65 1.增加写保护检测功能 2.提示拔盘时首先软件弹出U盘 3.在WMI不能使用时枚举磁盘 ================================================ V1.64 1.在C盘根目录生成日志文件,以调查打不开磁盘的问题 ================================================ V1.63 1.对设备名太长不予列出 2.提示文字考虑其长度,以免超出提示框 3.对不支持的方式不禁用 4.增加TIP提示完整信息 5.增加了多语言支持功能 ================================================ V1.62 1.解决了ZIP模式兼容性问题 2.增加了“固定磁盘”和“移动磁盘”的图标提示 3.对HDD/ZIP/FDD模式的应用范围做了限制 4.向磁盘中增加MSDOS.SYS以避免启动时出现WINDOWS菜单 ================================================ V1.61 1.解决了取消格式化后无法操作的问题 2.编写了使用说明 ================================================ V1.6 1.解决了磁盘容量问题,现在可以准确计算出U盘的容量 了,已在多种U盘上进行试验 2.增设了“引导处理”功能,可以不损伤原有数据使其 能够引导,类似DOS的SYS.COM命令 3.读取U盘的名称 4.根据接口类型判断U盘,而不是根据容量或者移动属性 判断,这样USB硬盘盒也可处理,而IDE硬盘不会被误操作 5.更新了引导区启动代码,USB-FDD模式可用了,在SIS630 主板上验证通过(AMI BIOS,仅支持USB-FDD) ================================================ V1.5 1.解决了“磁盘未格式化”的问题,凡是使用USBoot后 提示说磁盘未格式化的朋友请重新试用。 ================================================ V1.4 各位热心网友,请试用新的ZIP方式和FDD方式,HDD方 式未作变更,不必试验了。 1.增加了“重置”功能,如果发现USBOOT设置的参数不对 可以使用此功能将U盘的引导扇清空,然后用原配工具重 新格式化; 2.将原来的ZIP方式更名为FDD方式,增加了ZIP方式,ZIP 方式和HDD方式均有分区表,但ZIP方式参数和HDD方式不 同;从一些热心网友反馈的数据看,各种不同U盘之间参 数差别很大,大体分为32扇和63扇两类。 3.增加了自动停止U盘功能,不用等待U盘灯灭,只要提示 拔盘即可动手了; 其实和ZIP或HDD并无实质区别,一些PC根本就不设置 USB-ZIP还是USB-HDD,只有一个USB-STORAGE启动; U盘启动和PC关系很大,有的PC无论用什么参数都可以 启动,有的则很挑;同样的U盘在这台机器可以,在另 一台试遍FDD/ZIP/HDD都不行;筹划采用一种统一的方式, 彻底解决这个问题; ================================================ V1.3 由于暂时无法获得磁盘“剩余扇”,因此做了一个 额外处理,将用柱面数弥补剩余扇,这样可以减少磁盘 空间减少的情况,但是请大家注意,磁盘空间可能会多 计算!对于16M的盘误差很小,对于32M的盘误差在4M左 右,对于128M的盘误差在8M左右。后果是当磁盘接近满 时,会提示找不到对应扇区,但是不会浪费U盘的空间了! ================================================ V1.2 有部分用户反映U盘无法启动,
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值