《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试

HACK #20 使用fio进行I/O的基准测试

本节介绍使用fio进行模拟各种情况的I/O基准测试的操作方法。
I/O的基准测试中有无数需要考虑的因素。是I/O依次访问还是随机访问?是通过read/write的I/O?还是通过访问mmap的空间的I/O?是单一进程发出的I/O?还是多个进程同时发出的I/O?进程是受I/O限制还是受CPU限制?等等。
如果使用fio,就不需要每次都根据不同情况来编写用于性能评估的程序,就可以模拟这些情况的I/O。
安装fio
Fedora、Ubuntu等主流发布版中都备有fio的二进制文件包。请使用yum、apt等安装fio工具包。
这里按照Fedora 13中包含的fio版本1.36来进行说明。
想要使用最新版时,请先从下列网页下载fio的源代码,再进行安装。
程序页
http://freshmeat.net/projects/fio
Git仓库
git://git.kernel.org/pub/scm/linux/kernel/git/axboe/fio.git
基本执行方法
指定记载了I/O操作模式的设置文件,然后启动fio命令,这就是fio最基本的执行方法。大多数的项目可以不使用配置文件而通过命令行选项来指定。首先举出两种分别使用命令行选项的方法和配置文件的方法的简单例子,了解基本执行方法和命令行/设置文件的对应情况。
第一个示例执行的是下列操作。
进行10MB的顺序读入。
同时,其他进程随机进行5MB的写入。
使用read(2)和write(2)进行读写。
使用Direct I/O。
在fio命令行进行这些设置时的操作如下。在当前目录下会生成读写用的文件,因此要在可以写入的目录下执行。

$ fio --name=global --direct=1 --name=read --rw=read --size=10m --name=write --rw=randwrite --size=5m

与上述命令行选项具有相同意义的配置文件如下所示。

# cat fio_exam.fio

[global]
direct=1

[readjob]
size=10m
rw=read

[writejob]
size=5m
rw=randwrite

使用这个配置文件执行fio命令如下。

$ fio simple_read.fio

命令行选项与配置文件的各项之间的关系非常明显。这里简单介绍配置文件的各项的意义。
以#开头的是注释(comment)。内容直到行尾都被忽略。
方括号表示[]作业(job)定义选项的开始。方括号内是作业的名称。作业可以任意命名。但是global这个名称是内部使用的。作业global是用来定义所有作业共同的设置项。
fio按照每个作业生成进程,生成的进程根据设置进行实际的I/O操作。因此,fio的配置文件中除了global选项以外,必须要定义多个作业。
global选项中设置了direct=1。将direct设置为1时,使用的就Direct I/O。未指定时,就等同于direct=0(经由一般页面缓存进行I/O)。
接下来定义名为readjob的作业。
readjob作业中使用size设置I/O操作的大小(字节数)。后缀m表示兆字节。后缀可以使用k、m、g、t、p。readjob作业的进程在进行了size所设置的大小的I/O后就会结束。
rw用来设置I/O模式。readjob作业中指定的是表示顺序读出的read。其他的将在下一节中介绍。
最后再定义一个名称为writejob的作业。
writejob作业将进行I/O的大小设置为5MB,I/O模式设置为随机写入(randwrite)。
按照这个设置执行fio时,首先会在当前目录下生成用于I/O的文件,进行同步处理,取消页面缓存。然后,生成与readjob作业相对应的进程和与writejob作业相对应的进程,进行各自设置的I/O操作。各作业在完成size所设置的字节数的I/O后,就会结束。所有作业结束后,结果就会显示在控制台上。
输出结果包括很多信息。这些内容将在下一节中详细介绍。
模拟实验的例子和输出的意义
现在已经掌握了基本执行方法,就可以尝试生成并执行模拟某种情况的配置文件,然后对输出进行分析。
先生成符合下列情况的配置文件。
在文件数据的基础上执行查询(query)并返回发出请求的进程有两个正在执行。每隔10毫秒接受查询的请求并执行,从接受请求到返回结果的演算过程花费5毫秒。
1个正在运行的进程,它用来将访问记录写入磁盘。记录每1秒通过direct I/O写入。通过AIO实现I/O复用(multiplexing)。
与此同时,执行文件系统备份处理。
模拟这种情况的配置文件以及其中使用的各种配置项的意义如表3-7所示。另外,模拟时间设置为执行30秒后结束。

# server_sim.fio

[global]
directory=/mnt/sdb
runtime=30
time_based

[query]
size=100m
rw=randread
ioengine=mmap
thinktime=10k
thinktime_spin=5k
filename=query.dat
numjobs=2

[log]
size=10m
rw=randrw
ioengine=libaio
iodepth=32
thinktime=1m
thinktime_blocks=2
blocksize=1k,4k
direct=1

[backup]
size=100m
rw=randrw
thinktime=1k

表3-7 fio的配置项

然后实际执行,并详细查看输出结果。

$ fio server_sim.fio

query: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=mmap, iodepth=1
query: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=mmap, iodepth=1
log: (g=0): rw=randrw, bs=1K-1K/4K-4K, ioengine=libaio, iodepth=32
backup: (g=0): rw=randrw, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
Starting 4 processes
query: Laying out IO file(s) (1 file(s) / 100MB)
log: Laying out IO file(s) (1 file(s) / 10MB)
backup: Laying out IO file(s) (1 file(s) / 100MB)

query: (groupid=0, jobs=1): err= 0: pid=3158
  read : io=6,740KB, bw=225KB/s, iops=56, runt= 30006msec
    clat (usec): min=6, max=124K, avg=7553.49, stdev=5995.06
    bw (KB/s) : min=  162, max=  254, per=25.31%, avg=225.24, stdev=15.52
  cpu          : usr=28.83%, sys=0.24%, ctx=3544, majf=1639, minf=75
  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 r/w: total=1685/0, short=0/0
     lat (usec): 10=2.67%, 20=0.06%, 500=0.18%, 750=0.65%, 1000=0.36%
     lat (msec): 2=1.54%, 4=15.73%, 10=58.16%, 20=17.69%, 50=2.79%
     lat (msec): 100=0.12%, 250=0.06%

query: (groupid=0, jobs=1): err= 0: pid=3159
  read : io=6,772KB, bw=226KB/s, iops=56, runt= 30008msec
    clat (usec): min=6, max=128K, avg=7470.76, stdev=6163.17
    bw (KB/s) : min=  181, max=  260, per=25.45%, avg=226.47, stdev=14.27
  cpu          : usr=28.99%, sys=0.20%, ctx=3622, majf=1630, minf=88
  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 r/w: total=1693/0, short=0/0
     lat (usec): 10=3.66%, 20=0.06%, 500=0.35%, 750=0.77%, 1000=0.06%
     lat (msec): 2=1.24%, 4=16.42%, 10=55.64%, 20=19.31%, 50=2.30%
     lat (msec): 100=0.12%, 250=0.06%

log: (groupid=0, jobs=1): err= 0: pid=3160
  read : io=39,936B, bw=1,311B/s, iops=1, runt= 30449msec
    slat (usec): min=8, max=63, avg=27.92, stdev=19.38
    clat (msec): min=36, max=16,815, avg=10042.82, stdev=5584.03
    bw (KB/s) : min=    0, max=    1, per=0.01%, avg= 0.06, stdev= 0.24
  write: io=197KB, bw=6,625B/s, iops=1, runt= 30449msec
    slat (usec): min=10, max=89, avg=33.40, stdev=22.97
    clat (msec): min=33, max=16,778, avg=11045.30, stdev=5371.05
    bw (KB/s) : min=    0, max=    7, per=0.56%, avg= 2.62, stdev= 2.59
  cpu          : usr=0.00%, sys=0.01%, ctx=31, majf=0, minf=21
  IO depths    : 1=1.1%, 2=2.2%, 4=4.5%, 8=9.0%, 16=18.0%, 32=65.2%, >=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=98.3%, 8=0.0%, 16=0.0%, 32=1.7%, 64=0.0%, >=64=0.0%
     issued r/w: total=39/50, short=0/0
     lat (msec): 50=2.25%, 2000=4.49%, >=2000=93.26%

backup: (groupid=0, jobs=1): err= 0: pid=3161
  read : io=13,556KB, bw=452KB/s, iops=112, runt= 30005msec
    clat (usec): min=419, max=104K, avg=6669.29, stdev=4584.93
    bw (KB/s) : min=  341, max=  525, per=50.82%, avg=452.29, stdev=40.41
  write: io=14,072KB, bw=469KB/s, iops=117, runt= 30005msec
    clat (usec): min=10, max=98,704, avg=79.48, stdev=2190.03
    bw (KB/s) : min=  321, max=  632, per=100.32%, avg=469.52, stdev=72.87
  cpu          : usr=0.38%, sys=0.74%, ctx=10302, majf=0, minf=28
  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 r/w: total=3389/3518, short=0/0
     lat (usec): 20=38.63%, 50=12.25%, 500=0.51%, 750=0.61%, 1000=0.04%
     lat (msec): 2=1.61%, 4=9.64%, 10=28.99%, 20=7.37%, 50=0.25%
     lat (msec): 100=0.10%, 250=0.01%

Run status group 0 (all jobs):
   READ: io=27,107KB, aggrb=890KB/s, minb=1KB/s, maxb=462KB/s, mint=30005msec, maxt=30449msec
  WRITE: io=14,269KB, aggrb=468KB/s, minb=6KB/s, maxb=480KB/s, mint=30005msec, maxt=30449msec

Disk stats (read/write):
  sdb: ios=6698/2302, merge=0/26478, ticks=48982/1143531, in_queue=1207586, util=93.27%

第一部分输出的是已执行进程的信息,分别输出了名称、I/O模式、块的大小等设置。有两个query是因为指定为numjob=2,所以要执行两个进程。
接下来第一行为query的两个段落是query作业两个进程的结果,其后显示的分别是log作业和backup作业的结果。下面对比各部分的内容,看一下各输出表示的意义。
从read:和write:开始的3行或4行表示的是关于读入和写入的数据量、平均带宽、延迟。平均带宽是将总数据量除以作业执行时间得出的值,因此在thinktime较长的作业中值较低。clat(completion latency)的行为延迟,是作业进程开始向内核发出I/O请要到完成为止的时间,即从调出read(2)等直到返回的时间。log作业由于使用的是AIO,因此多输出一个slat(submitting latency)延迟。这表示I/O发出要求滞留在作业进程内部的queue时间。
从query作业的延迟来看,平均花费7.5毫秒左右,最多花费130毫秒左右。10毫秒的查询间隔中大部分时间都耗费在等待I/O上。log作业中出现了最长16秒的延迟。这时应当重新设计系统,分散I/O负载。
小贴士:clat在read(2)或Direct I/O的write(2)中I/O实际花费的时间,而在常用的经由页面缓存的write(2)中只是将数据存放到页面缓存所需的时间。上例中backup作业的write就相当于这种情况,因此其值平均为79微秒,比其他情况短得多。
I/O depths的行表示通过AIO实现复用的I/O数与时间之间的关系。例如,log作业的IO depths中的“8=9.0%,16=18.0%”,就表示9~16个I/O同时执行的时间相当于所有执行时间的18.0%。由于I/O复用只存在于AIO的情况下,因此在log以外的作业都是“1=100%”。
从log作业的IO depths可以看出,65.2%的时间都达到复用上限值附近的19~32。这也显示I/O负载仍然过高。
最后两个段落是关于所有进程总共的统计值。输出所有I/O的数据量的合计结果等。
小结
本节使用fio进行实际使用情况的I/O模拟实验,介绍了输出的结果。fio有非常多的选项,可以进行更加精确和详细的设置,由于数量庞大,这里无法一一列举。源代码包含的文档和man中有详细的记载,但都是英文。参考这些内容并熟练使用I/O操作,I/O基准测试就能成为强有力的工具。
—Munehiro IKEDA

时间: 2024-07-30 18:16:48

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试的相关文章

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #1 如何获取Linux内核

HACK #1 如何获取Linux内核 本节介绍获取Linux内核源代码的各种方法. "获取内核"这个说法看似简单,其实Linux内核有很多种衍生版本.要找出自己想要的源代码到底是哪一个,必须首先理解各种衍生版本的意义. 接下来将简单介绍Linux内核的开发模式,并分析各种衍生版本在其中所处的地位,然后介绍获取这些衍生版本的源代码的方法. 内核的种类 想要获取正确的Linux内核源代码,首先必须了解Linux内核的开发模式. Linux内核是由多个开发者以分散型的模式进行开发的.这里出

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #15 ramzswap

HACK #15 ramzswap 本节介绍将一部分内存作为交换设备使用的ramzswap. ramzswap是将一部分内存空间作为交换设备使用的基于RAM的块设备.对要换出(swapout)的页面进行压缩后,不是写入磁盘,而是写入内存.可以使用的内存仅为完成压缩的部分.压缩处理使用的是LZO注1. ramzswap是从Linux 2.6.33合并到Staging驱动程序的.Staging驱动程序是指尚未达到某种程度的质量的试验性驱动程序. 通过使用ramzswap,运转速度可以比换出到一般磁盘

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #3 如何编写内核模块

HACK #3 如何编写内核模块 本节将介绍向Linux内核中动态添加功能的结构-内核模块的编写方法. 内核模块 Linux内核是单内核(monolithic kernel),也就是所有的内核功能都集成在一个内核空间内.但是内核具有模块功能,可以将磁盘驱动程序.文件系统等独立的内核功能制作成模块,并动态添加到内核空间或者删除. 内核模块是可以动态添加到Linux内核空间的二进制文件,文件扩展名为ko. 内核模块的编写方法大致有两种.一种是将内核源码树带有的功能编写为模块的方法(参考Hack #2

《Linux内核精髓:精通Linux内核必会的75个绝技》一导读

前 言 内核是操作系统的核心,操作系统的基本功能都是由内核提供的.文件生成和数据包传输等也是通过内核的功能实现的.但这些都不是简单的任务.平时可能意识不到,但这其中确实包含了很多先进技术.例如,在文件系统方面,配置文件时尽量减少磁盘扫描,在网络方面,由于路由表的入口数量庞大,因此设计时尽量保证对系统整体影响较小的设计.在内存管理.进程管理方面也作出了很多努力.解读这种先进技术也是内核构建的魅力之一. 然而,最近的Linux所提供的并不只有基本功能.随着功能的不断发展,现在已经出现了很多特定领域的

《Linux内核精髓:精通Linux内核必会的75个绝技》一第1章 内核入门

第1章 内核入门 一提起内核包,总会让人感觉似乎困难至极.如临深渊一般.但其基本的操作与其他开放源代码软件包并没有什么不一样,都是首先获取源代码,进行解读,然后修改或者添加新功能对应的代码,并编译.测试.本章将介绍这些内核包操作中最基础的知识,以及Linux内核特有的方法.

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #8 调度策略

HACK #8 调度策略 本节介绍Linux的调度策略(scheduling policy). Linux调度策略的类别大致可以分为TSS(Time Sharing System,分时系统)和实时系统这两种. 一方面,一般的进程是通过分时运行的.也就是说,使用CPU的时间达到分配给进程的时间(时间片)时,就会切换到其他进程.这种分时运行的调度策略称为TSS. 另一方面,在实时制约较严格且要求保证实时的处理中,就需要指定静态的执行优先级,并严格按照执行优先级进行调度.对这种对应答性有要求的进程,可

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #4 如何使用Git

HACK #4 如何使用Git 本节介绍Git的使用方法. Git是Linux内核等众多OSS(Open Source Software,开源软件)开发中所使用的SCM(Source Code Management,源码管理)系统.在2005年以前,在Linux内核开发中一直使用一个叫做BitKeeper的SCM.但是由于后来BitKeeper的许可证被更改,可能会对开发造成障碍,因此Linux不得不改用新的SCM进行开发.在这种情况下,Linux内核的创始人Linus Torvalds就开发了

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #2 如何编译Linux内核

HACK #2 如何编译Linux内核 本节介绍编译Linux内核的方法. 当发现bug而修改源代码或者添加新功能时,就需要对内核进行重新编译,生成二进制映像文件.另外,如果想要使用发布版内核中无效的功能或者驱动程序时,或者相反地,想要删除不需要的功能从而使内核更精简.更快时,或者想使用最新版的上游内核时,也需要对内核进行编译. 下面主要介绍对上游内核进行设置.编译以及安装的方法.当使用发布版内核的源码包管理系统来管理内核映像文件时,需要将内核映像文件打包.接下来以两个具有代表性的发布版Fedo

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #17 如何使用ext4

HACK #17 如何使用ext4 本节介绍ext4的编写和挂载方法.开发版ext4的使用方法. ext4是ext3的后续文件系统,从Linux 2.6.19开始使用.现在主要的发布版中多数都是采用ext4作为标准文件系统. 除了间接参照块管理以外,ext4还以扩展形式支持块的管理,使其能够处理更大的文件.文件系统.另外,还增加了确保多块(multiblock)注1.确保延迟块.提高fsck速度.碎片整理等新的功能.在ext3中,时间戳(time stamp)的单位为毫秒,而ext4中变成了纳秒