fio简介

文/xanpeng 2015-01-27 05:00:00

本文简要介绍fio的代码结构和原理,希望能有助于大家更深地理解fio这一强大、灵活的性能测试工具。

fio是Jens Axboe大神编写的性能测试工具,可以用来测试CPU、网络以及存储等多种设备的性能数据,目前开源在github上(https://github.com/axboe/fio)。 fio的来由是axboe大神在日常性能测试工作中,发现很多重复、繁琐的工作,于是程序员的“惰性”大发,开发了fio这一测试工具——也可称之为框架,因为你可以编写自己的插件。

fio架构简介

fio主要分为job管理、ioengine和数据收集等模块,其中ioengine是fio的核心。 fio ioengine采用类似于vfs的架构,即定义一组公共的操作方法(ioengineops),具体的ioengine可以通过实现ioengineops等指定接口,插入到fio框架中,并得以成功执行。 这一框架可通过下图得以简示: fio-ioengine-arch

下面以fio 2.1.1版本和以下配置文件(example.conf)为例,来看fio的主要流程:

[global]
group_reporting=1
iodepth=4
bsrange=4k-16k
ioengine=libaio
nrfiles=20
size=250G
filesize=1m-256m
numjobs=32
runtime=1000
create_serialize=1

[random-read]
name=random-read
rw=randread
directory=/tmp/fiotest

基于这一配置文件,fio example.conf的大执行流程为:

  1. 解析配置文件。
  2. 准备测试文件,创建nrfiles个文件,命名为“$jobname.$[1~numjobs].$[1~nrfiles]”,总共会创建nrfiles*numjobs个文件。如果create_serialize=0,文件的创建会在各个进程中进行,于是文件创建动作相互交织,文件的分布更为随机。
  3. 创建numjobs个进程或者线程(thread=0/1参数可控),执行fio任务。
  4. 在每个fio任务中,tdioinit()会钓鱼ioengine的init()函数,进行ioengine的初始化,随后执行其他一些初始化工作,比如设置计时器等。
  5. 每个fio任务中,代码执行到do_io(),开始执行真正的IO工作。

fio输出解析

以loop块设备的fio输出结果为例,图示各个部分的含义:

fio-output-explanation

fio如何测量IOPS

使用fio测量存储设备或系统的IOPS值,使fio的常用使用场景之一。 那么fio使如何测量IOPS的?

在job开始之前的initiou()中,fio初始化三个队列,分别是iourequeues、ioufreelist和iouall。前者大小被初始化为iodepth最近的2^x,后二者大小被初始化为iodepth。 iourequeues实际上被实现为环,初始状态为head=tail=0。 ioufreelist和iouall都是FIFO,初始状态为nr=0;然后在initiou()的后面部分,fio通过iouqpush()往二者中放入相同的iodepth个新建的iou,flags均为IOUFFREE,并且会调用ioengine的iouinit()。 并且对于ioufreelist,在iou完成等情况发生时,fio通过putiou()回收iou,可被用来重复使用。

在doio时,会实现getiou,先检查如果iourequeues非空,则从其中取;如果ioufreelist非空,则从其中取。当然开始时一定是从后者成功取出iou。 tdioqueue(td, iou),调用ioengine的排队函数,以libaio ioengine为例,libaio的排队函数会将iou放入事先初始化的iocbs[]和ious[]数组,数组的大小也是iodepth。 当然如果libaio的队列已满,libaio的排队函数返回FIOQBUSY;如果iou操作是sync类型或trim,则返回FIOQCOMPLETED;否则排入队列并返回FIOQQUEUED。 实际上IOPS的计数是由td->ts.totaliou变量表示的。在返回FIOQCOMPLETED、FIOQQUEUED时,totaliou++。这就是fio的IOPS是如何被记录的

以上是对fio的简单介绍。

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

最新文章 全部