本文主要介绍fio是如何运行的,并且以单线程、单job为例

fio的入口在fio.c中的main函数,下面列出了main函数,此处只出示了一些调用的关键函数

 int main(int argc, char *argv[], char *envp[])
{
parse_options(argc, argv);
fio_backend();
}

在main函数中主要调用了两个关键函数,parse_options,顾名思义,就是分析options,也就是fio的参数,而fio_backend()函数则是fio进程的入口

fio_backend()函数在backend.c文件中

 int fio_backend(void)
{
......
run_threads();
......
}

在fio_backend()函数中,初始化一些数据结构之后,调用了run_threads()(backend.c)函数,该函数是fio用来创建譬如I/O, verify线程等。

 /*
* Main function for kicking off and reaping jobs, as needed.
*/
static void run_threads(void)
{
......
todo = thread_number;
......
while (todo) {
if (td->o.use_thread) {
......
ret = pthread_create(&td->thread, NULL,thread_main, td);
ret = pthread_detach(td->thread);
......
}
......
}

在这个函数中,创建了thread_main线程(backend.c),这个线程功能是,生成I/O,发送并完成I/O,记录数据等。

 /*
* Entry point for the thread based jobs. The process based jobs end up
* here as well, after a little setup.
*/
static void *thread_main(void *data)
{
........
/*
* May alter parameters that init_io_u() will use, so we need to
* do this first.
* 下面两个函数的主要功能是生成读写的参数,offset,len
*/
if (init_iolog(td))
goto err; if (init_io_u(td))
goto err;
......
while (keep_running(td)) {
do_io(td);
do_verify(td, verify_bytes);//如果需要verification的话
}
}

如果不考虑verify的话,下面主要看do_io(backend.c)函数。

 /*
* Main IO worker function. It retrieves io_u's to process and queues
* and reaps them, checking for rate and errors along the way.
*
* Returns number of bytes written and trimmed.
*/
static uint64_t do_io(struct thread_data *td)
{
......
//下面是do_io的主循环,判断条件是,io_log里有生成的pos信息,而且已经iuuse的数据小于总数据,
while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) ||
(!flist_empty(&td->trim_list)) || !io_bytes_exceeded(td) ||
td->o.time_based) {
......
io_u = get_io_u(td);// io_u,是一个io unit,是根据参数生成的io unit
......
ret = td_io_queue(td, io_u); //将io_u提交到队列中
switch (ret) {
case FIO_Q_COMPLETED: //处理错误,以及同步的操作
......
case FIO_Q_QUEUED://成功入队
bytes_issued += io_u->xfer_buflen;
case FIO_Q_BUSY: //队伍满了,重新入队
.......
/*
* See if we need to complete some commands. Note that we
* can get BUSY even without IO queued, if the system is
* resource starved.
*/
full = queue_full(td) || (ret == FIO_Q_BUSY && td->cur_depth);
if (full || !td->o.iodepth_batch_complete) {
min_evts = min(td->o.iodepth_batch_complete,td->cur_depth);
/*
* if the queue is full, we MUST reap at least 1 event
*/
if (full && !min_evts)
min_evts = ;
do {
ret = io_u_queued_complete(td, min_evts, bytes_done);
} while (full && (td->cur_depth > td->o.iodepth_low));
}
}

上面do_io函数的关键入队函数td_io_queue(ioengines.c)

 int td_io_queue(struct thread_data *td, struct io_u *io_u)
{
......
ret = td->io_ops->queue(td, io_u);
......
else if (ret == FIO_Q_QUEUED) {
int r;
if (ddir_rw(io_u->ddir)) {
td->io_u_queued++;
td->ts.total_io_u[io_u->ddir]++;
}
if (td->io_u_queued >= td->o.iodepth_batch) {
r = td_io_commit(td);
if (r < )
return r;
}
}
}
int td_io_commit(struct thread_data *td)
{
......
int ret;
if (td->io_ops->commit) {
ret = td->io_ops->commit(td);
}
......
return ;
}

对于td->iops,它是在各个engines中定义了,以libaio(/engines/libaio.c)为例,调用的函数就是相应engines里对应的函数

 static struct ioengine_ops ioengine = {
.name = "libaio",
.version = FIO_IOOPS_VERSION,
.init = fio_libaio_init,
.prep = fio_libaio_prep,
.queue = fio_libaio_queue,
.commit = fio_libaio_commit,
.cancel = fio_libaio_cancel,
.getevents = fio_libaio_getevents,
.event = fio_libaio_event,
.cleanup = fio_libaio_cleanup,
.open_file = generic_open_file,
.close_file = generic_close_file,
.get_file_size = generic_get_file_size,
.options = options,
.option_struct_size = sizeof(struct libaio_options),
};

对于reap流程里的io_u_queued_complete(io_u.c)函数

 /*
* Called to complete min_events number of io for the async engines.
*/
int io_u_queued_complete(struct thread_data *td, int min_evts,
uint64_t *bytes)
{
...... ret = td_io_getevents(td, min_evts, td->o.iodepth_batch_complete, tvp);
......
} int td_io_getevents(struct thread_data *td, unsigned int min, unsigned int max,
struct timespec *t)
{
int r = ; if (min > && td->io_ops->commit) {
r = td->io_ops->commit(td);
if (r < )
goto out;
}
if (max > td->cur_depth)
max = td->cur_depth;
if (min > max)
max = min; r = ;
if (max && td->io_ops->getevents)
r = td->io_ops->getevents(td, min, max, t);
out:
......
return r;
}
这里调用的getevents也是各个engines里定义的函数

fio是如何运行的?的更多相关文章

  1. ceph--磁盘和rbd、rados性能测试工具和方法

    我在物理机上创建了5台虚拟机,搭建了一个ceph集群,结构如图: 具体的安装步骤参考文档:http://docs.ceph.org.cn/start/ http://www.centoscn.com/ ...

  2. ceph 性能测试

    我在物理机上创建了5台虚拟机,搭建了一个ceph集群,结构如图: 具体的安装步骤参考文档:http://docs.ceph.org.cn/start/ http://www.centoscn.com/ ...

  3. 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境

    本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  4. fio 2种画图方法 fio_generate_plots 和 gfio

    fio 安装fio apt-get install fio 可以把fio的输出数据自动画图的插件gnuplot apt-get install gnuplot 1.输出bw,lat和iops数据并画图 ...

  5. FIO 测试磁盘iops 以及读写

    最近在做mariadb的性能,感觉io 有瓶颈,就使用fio 来测试一下磁盘.下文为转载文章(温馨提示:此命令很伤硬盘,测试前请备份数据,- -我就写坏了一个.) FIO 是测试IOPS的非常好的工具 ...

  6. linux使用FIO测试磁盘的iops

    FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...

  7. 文件操作ofstream,open,close,ifstream,fin,依照行来读取数据, fstream,iosin iosout,fio.seekg(),文件写入和文件读写,文件拷贝和文件

     1.ofstream,open,close 写入文件 #include<iostream> #include<fstream> using namespace std; ...

  8. 【转】FIO使用指南

    原文地址:http://blog.csdn.net/yuesichiu/article/details/8722417 Fio压测工具和io队列深度理解和误区 这个文档是对fio-2.0.9 HOWT ...

  9. linux 磁盘IO测试工具:FIO (同时简要介绍dd工具测试)

    FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证.磁盘IO是检查磁盘性能的重要指标,可以按照负载情况分成照顺序读写,随机读写两大类. 目前主流的第三方IO测试工具有fio.iomete ...

随机推荐

  1. css中单位em和rem的区别

    在css中单位长度用的最多的是px.em.rem,这三个的区别是: px是固定的像素,一旦设置了就无法因为适应页面大小而改变. em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定 ...

  2. PHP中cookie和session的区别

    1.cookie数据存放在客户的浏览器上,session数据放在服务器上. 2.cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session. 3 ...

  3. LeetCode 545----Boundary of Binary Tree

    Given a binary tree, return the values of its boundary in anti-clockwise direction starting from roo ...

  4. Spring Boot—17MongoDB

    在MongoDB中插入如下的数据 db.baike.insert( { _id: 'freemark', desc: '新一代模板语言', tag: [ 'IT', '模板语言' ], comment ...

  5. Ubuntu pydot failed to call GraphViz.Please install GraphViz 解决方法

    如果遇到: OSError: `pydot` failed to call GraphViz.Please install GraphViz (https://www.graphviz.org/) a ...

  6. Android开发使用软件

    开发环境搭建顺序: 1.安装开发工具 1).安装java 2).安装as 3).安装myeclipse 4).安装np++ md 5).安装svn git 2.配置环境变量 1).配置java jav ...

  7. Android app启动是出现白屏或者黑屏如何解决?

    1.为什么 APP 启动时会出现白屏或者黑屏? 当打开一个 Activity 时,如果这个 Activity 所属的应用还没有在运行,系统会为这个 Activity 所属的应用创建一个进程,但进程的创 ...

  8. 如何在前端项目中引用bootstrap less?

    在基于bootstrap css框架的前端项目开发中,如果有grunt build系统,那么工作流是:客制化less,在less中定义自己的 CSS,同时可以随意引用bootstrap中预定义好的cs ...

  9. JSP中forEach和forTokens循环的用法

    <%@page import="java.util.*"%> <%@ page language="java" contentType=&qu ...

  10. Oracle案例13—— OGG-01163 Oracle GoldenGate Delivery for Oracle, reprpt01.prm

    由于虚拟机宿主机重启,导致很多虚拟机服务需要重点关注,其中一个DG的从库和另一个report库有OGG同步,所以这里再系统恢复后检查OGG状态的时候,果然目标端的REPLICAT进程处于abend状态 ...