fio是如何运行的?
本文主要介绍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是如何运行的?的更多相关文章
- ceph--磁盘和rbd、rados性能测试工具和方法
我在物理机上创建了5台虚拟机,搭建了一个ceph集群,结构如图: 具体的安装步骤参考文档:http://docs.ceph.org.cn/start/ http://www.centoscn.com/ ...
- ceph 性能测试
我在物理机上创建了5台虚拟机,搭建了一个ceph集群,结构如图: 具体的安装步骤参考文档:http://docs.ceph.org.cn/start/ http://www.centoscn.com/ ...
- 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境
本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...
- fio 2种画图方法 fio_generate_plots 和 gfio
fio 安装fio apt-get install fio 可以把fio的输出数据自动画图的插件gnuplot apt-get install gnuplot 1.输出bw,lat和iops数据并画图 ...
- FIO 测试磁盘iops 以及读写
最近在做mariadb的性能,感觉io 有瓶颈,就使用fio 来测试一下磁盘.下文为转载文章(温馨提示:此命令很伤硬盘,测试前请备份数据,- -我就写坏了一个.) FIO 是测试IOPS的非常好的工具 ...
- linux使用FIO测试磁盘的iops
FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...
- 文件操作ofstream,open,close,ifstream,fin,依照行来读取数据, fstream,iosin iosout,fio.seekg(),文件写入和文件读写,文件拷贝和文件
1.ofstream,open,close 写入文件 #include<iostream> #include<fstream> using namespace std; ...
- 【转】FIO使用指南
原文地址:http://blog.csdn.net/yuesichiu/article/details/8722417 Fio压测工具和io队列深度理解和误区 这个文档是对fio-2.0.9 HOWT ...
- linux 磁盘IO测试工具:FIO (同时简要介绍dd工具测试)
FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证.磁盘IO是检查磁盘性能的重要指标,可以按照负载情况分成照顺序读写,随机读写两大类. 目前主流的第三方IO测试工具有fio.iomete ...
随机推荐
- JS将秒换成时分秒实现代码 [mark]
将秒换成时分秒的方法有很多,在本文将为大家介绍下,使用js的具体的实现思路,有需要的朋友可以参考下,希望对大家有所帮助 http://www.jb51.net/article/41098.htm fu ...
- Android开发各种Utils收集库
为方便查找,已进行大致归类,其目录如下所示: Activity相关→ActivityUtils.java→Demo isActivityExists : 判断是否存在Activity launchAc ...
- 对layoutInflater的理解
参考该博客:http://www.cnblogs.com/top5/archive/2012/05/04/2482328.html LayoutInflater是一个抽象类,通过调用其实例方法infl ...
- 传递命令行参数示例代码 (C 和 Python)
C语言 在 C 语言中, 使用 main 函数的输入参数 argc 和 argv 传入命令行参数. argc 为 int 类型, 表示传入命令行参数的个数 (argument count); argv ...
- 在 Linux 上创建虚拟机规模集和部署高度可用的应用
利用虚拟机规模集,可以部署和管理一组相同的.自动缩放的虚拟机. 可以手动缩放规模集中的 VM 数,也可以定义规则,以便根据资源使用情况(如 CPU 使用率.内存需求或网络流量)进行自动缩放. 在本教程 ...
- 纲举目张:打通MySQL架构和业务的任督二脉
目前,在很多OLTP场景中,MySQL数据库都有着广泛的应用,也有很多不同的使用方式.从数据库的业务需求.架构设计.运营维护.再到扩容迁移,不同的MySQL架构有不同的特点,适应一定的业务场景,或者解 ...
- UIButton的两种block传值方式
UIButton的两种block传值方式 方式1 - 作为属性来传值 BlockView.h 与 BlockView.m // // BlockView.h // Block // // Create ...
- Linux strace命令详解
Linux抓取TCP的命令: tcpdump ps -ef 参数命令详解: Linux下一切皆文件,我们打开一个socket,实际上也是打开了一个文件 我们打开一个网卡,实际上也是调用Linux系统的 ...
- 为什么mysql要做主从复制?
为什么MySQL要做主从复制(读写分离)? 通俗来讲,如果对数据库的读和写都在同一个数据库服务器中操作,业务系统性能会降低. 为了提升业务系统性能,优化用户体验,可以通过做主从复制(读写分离)来减轻主 ...
- tkinter入门,canvas实现百度,抖音,加载
对于tkinter的各个控件,可以参看 : https://blog.csdn.net/weixin_38532159/article/details/78379523 这个已经比较全面了 今天利用 ...