本文主要介绍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. JS将秒换成时分秒实现代码 [mark]

    将秒换成时分秒的方法有很多,在本文将为大家介绍下,使用js的具体的实现思路,有需要的朋友可以参考下,希望对大家有所帮助 http://www.jb51.net/article/41098.htm fu ...

  2. Android开发各种Utils收集库

    为方便查找,已进行大致归类,其目录如下所示: Activity相关→ActivityUtils.java→Demo isActivityExists : 判断是否存在Activity launchAc ...

  3. 对layoutInflater的理解

    参考该博客:http://www.cnblogs.com/top5/archive/2012/05/04/2482328.html LayoutInflater是一个抽象类,通过调用其实例方法infl ...

  4. 传递命令行参数示例代码 (C 和 Python)

    C语言 在 C 语言中, 使用 main 函数的输入参数 argc 和 argv 传入命令行参数. argc 为 int 类型, 表示传入命令行参数的个数 (argument count); argv ...

  5. 在 Linux 上创建虚拟机规模集和部署高度可用的应用

    利用虚拟机规模集,可以部署和管理一组相同的.自动缩放的虚拟机. 可以手动缩放规模集中的 VM 数,也可以定义规则,以便根据资源使用情况(如 CPU 使用率.内存需求或网络流量)进行自动缩放. 在本教程 ...

  6. 纲举目张:打通MySQL架构和业务的任督二脉

    目前,在很多OLTP场景中,MySQL数据库都有着广泛的应用,也有很多不同的使用方式.从数据库的业务需求.架构设计.运营维护.再到扩容迁移,不同的MySQL架构有不同的特点,适应一定的业务场景,或者解 ...

  7. UIButton的两种block传值方式

    UIButton的两种block传值方式 方式1 - 作为属性来传值 BlockView.h 与 BlockView.m // // BlockView.h // Block // // Create ...

  8. Linux strace命令详解

    Linux抓取TCP的命令: tcpdump ps -ef 参数命令详解: Linux下一切皆文件,我们打开一个socket,实际上也是打开了一个文件 我们打开一个网卡,实际上也是调用Linux系统的 ...

  9. 为什么mysql要做主从复制?

    为什么MySQL要做主从复制(读写分离)? 通俗来讲,如果对数据库的读和写都在同一个数据库服务器中操作,业务系统性能会降低. 为了提升业务系统性能,优化用户体验,可以通过做主从复制(读写分离)来减轻主 ...

  10. tkinter入门,canvas实现百度,抖音,加载

    对于tkinter的各个控件,可以参看  : https://blog.csdn.net/weixin_38532159/article/details/78379523 这个已经比较全面了 今天利用 ...