io电梯算法,网上一堆,在此不再赘述。

手上有几块厂商提供的sas的ssd,做如下实验。

考虑到没有磁头移动,ssd一般采用noop的io调度策略,结果看到如下的iostat测试数据:

Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
dm-0 84.00 0.00 600.00 0.00 342.00 0.00 1167.36 1.15 1.92 1.92 0.00 0.78 46.90
dm-1 87.00 0.00 560.00 0.00 323.00 0.00 1181.26 1.04 1.86 1.86 0.00 0.79 44.50
dm-2 88.00 0.00 576.00 0.00 332.00 0.00 1180.44 1.19 2.06 2.06 0.00 0.79 45.40
dm-3 94.00 0.00 553.00 0.00 323.50 0.00 1198.06 0.98 1.78 1.78 0.00 0.82 45.60
dm-4 98.00 0.00 576.00 0.00 337.00 0.00 1198.22 1.12 1.95 1.95 0.00 0.81 46.80
dm-5 83.00 0.00 536.00 0.00 309.00 0.00 1180.66 0.93 1.73 1.73 0.00 0.81 43.50
dm-6 101.00 0.00 572.00 0.00 337.00 0.00 1206.60 1.06 1.86 1.86 0.00 0.81 46.50
dm-7 98.00 0.00 607.00 0.00 353.00 0.00 1191.01 1.13 1.87 1.87 0.00 0.82 49.60

第一列的数据表明,read进行了merge,这个与我之前预想的不一致,我一直以为固态硬盘颗粒不会进行合并,后来想,可能跟调度算法有关系,而不是跟具体物理介质有关系,如果该驱动注册了这个调度策略,那么就可能进行merge,而不管这个merge对硬件介质是否管用。根据查看iostat的源码以及内核中genhd.c的diskstats_show,确认了这个合并就是我们理解的io merge。

我们知道对于cfq和deadline这两种调度策略,是会进行合并的,noop 的合并需要单独看noop的实现。

查看内核中noop的初始化函数指针:

static struct elevator_type elevator_noop = {
.ops = {
.elevator_merge_req_fn = noop_merged_requests,
.elevator_dispatch_fn = noop_dispatch,
.elevator_add_req_fn = noop_add_request,
.elevator_queue_empty_fn = noop_queue_empty,
.elevator_former_req_fn = noop_former_request,
.elevator_latter_req_fn = noop_latter_request,
.elevator_init_fn = noop_init_queue,
.elevator_exit_fn = noop_exit_queue,
},
.elevator_name = "noop",
.elevator_owner = THIS_MODULE,
};

从初始化函数指针可以看出:

elevator_allow_merge_fn 没有初始化,为NULL,注意这个函数的意思不是说永远是否允许merge,而是当前这次请求是否允许。

elevator_merge_fn 函数指针没有初始化,那应该为NULL,说明没有单独的合并回调。

1 noop(实现简单的FIFO),

首先来看下调用链:

Returning to : 0xffffffff812cd03b : blk_queue_bio+0x8b/0x3a0 [kernel]
0xffffffff812c8452 : generic_make_request+0xe2/0x130 [kernel]
0xffffffff812c8511 : submit_bio+0x71/0x150 [kernel]

blk_queue_bio里面有两处尝试merge,一处是blk_attempt_plug_merge,一处是elv_merge,前者不需要自旋锁,后者需要,所以前者的消耗较小。

背景知识:

bio 代表一个IO 请求,可以准确描述os提交给block层的请求。

request 是bio 提交给IO调度器产生的数据,一个request 中放着顺序排列的bio

当设备提交bio 给IO调度器时,IO调度器可能会插入bio,或者生成新的request

request_queue代表着一个物理设备,顺序的放着request

写一个stap打点脚本如下:

probe begin {
print("Started monitoring noop\n")
}
probe kernel.function("blk_attempt_plug_merge").return {
printf("\tCurr: %s(%d), Parent: %s(%d), Cmdline: %s\n", execname(), pid(), pexecname(), ppid(), cmdline_str());
aaa = kernel_string(($q)->elevator->type->elevator_name);
if(aaa=="noop")
{
    printf("Paras: blk_attempt_plug_merge bio=(%u),(%s),return is (%d)\n",$bio,aaa, $return);
    print_backtrace();
}
}

probe kernel.function("elv_merge").return {
bbb = kernel_string(($q)->elevator->type->elevator_name);
if(bbb=="noop")
{
    printf("Paras: elv_merge bio=(%u),(%s),return is (%d)\n",$bio,bbb, $return);
    print_backtrace();
}
}

先看看 blk_attempt_plug_merge 函数中,是怎么处理的。

Curr: nginx(12008), Parent: nginx(24824), Cmdline: nginx: worker process "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
Paras: blk_attempt_plug_merge bio=(18446612139773339904),(noop),return is (1)---------return 为1,则不会进行elv_merge。

Returning from: 0xffffffff812cc590 : blk_attempt_plug_merge+0x0/0x100 [kernel]
Returning to : 0xffffffff812cd12e : blk_queue_bio+0x17e/0x3a0 [kernel]
0xffffffff812c8452 : generic_make_request+0xe2/0x130 [kernel]
0xffffffff812c8511 : submit_bio+0x71/0x150 [kernel]
0xffffffff81220790 : do_mpage_readpage+0x2e0/0x6e0 [kernel]
0xffffffff81220c7b : mpage_readpages+0xeb/0x160 [kernel]
0xffffffffa089ba7d [xfs]
0xffffffff8117691c : __do_page_cache_readahead+0x1cc/0x250 [kernel] (inexact)
0xffffffff81176b16 : ondemand_readahead+0x116/0x230 [kernel] (inexact)
0xffffffff81176f21 : page_cache_sync_readahead+0x31/0x50 [kernel] (inexact)
0xffffffff8120f226 : __generic_file_splice_read+0x556/0x5e0 [kernel] (inexact)
0xffffffff81589a23 : tcp_v4_md5_lookup+0x13/0x20 [kernel] (inexact)
0xffffffff8120dac0 : spd_release_page+0x0/0x20 [kernel] (inexact)
0xffffffff81577bb5 : tcp_sendpage+0xe5/0x5a0 [kernel] (inexact)
0xffffffff8120da00 : pipe_to_sendpage+0x0/0xa0 [kernel] (inexact)
0xffffffff815a326e : inet_sendpage+0x6e/0xe0 [kernel] (inexact)
0xffffffff81510e8b : kernel_sendpage+0x1b/0x30 [kernel] (inexact)
0xffffffff81510ec7 : sock_sendpage+0x27/0x30 [kernel] (inexact)
0xffffffff8120dab5 : page_cache_pipe_buf_release+0x15/0x20 [kernel] (inexact)
0xffffffff8120d9a1 : splice_from_pipe_feed+0xc1/0x120 [kernel] (inexact)
0xffffffff8120da00 : pipe_to_sendpage+0x0/0xa0 [kernel] (inexact)

另外一种情况是blk_attempt_plug_merge返回0,则会调用 elv_merge

Paras: blk_attempt_plug_merge bio=(18446612139773339136),(noop),return is (0)-------------可以对比下面的bio,两者相等
Returning from: 0xffffffff812cc590 : blk_attempt_plug_merge+0x0/0x100 [kernel]
Returning to : 0xffffffff812cd12e : blk_queue_bio+0x17e/0x3a0 [kernel]
0xffffffff812c8452 : generic_make_request+0xe2/0x130 [kernel]
0xffffffff812c8511 : submit_bio+0x71/0x150 [kernel]
0xffffffff81220cb4 : mpage_readpages+0x124/0x160 [kernel]
0xffffffffa089ba7d [xfs]
0xffffffff8117691c : __do_page_cache_readahead+0x1cc/0x250 [kernel] (inexact)
0xffffffff81176b16 : ondemand_readahead+0x116/0x230 [kernel] (inexact)
0xffffffff81176f21 : page_cache_sync_readahead+0x31/0x50 [kernel] (inexact)
0xffffffff8120f226 : __generic_file_splice_read+0x556/0x5e0 [kernel] (inexact)
0xffffffff81589a23 : tcp_v4_md5_lookup+0x13/0x20 [kernel] (inexact)
0xffffffff8120dac0 : spd_release_page+0x0/0x20 [kernel] (inexact)
0xffffffff81577bb5 : tcp_sendpage+0xe5/0x5a0 [kernel] (inexact)
0xffffffff8120da00 : pipe_to_sendpage+0x0/0xa0 [kernel] (inexact)
0xffffffff815a326e : inet_sendpage+0x6e/0xe0 [kernel] (inexact)
0xffffffff81510e8b : kernel_sendpage+0x1b/0x30 [kernel] (inexact)
0xffffffff81510ec7 : sock_sendpage+0x27/0x30 [kernel] (inexact)
0xffffffff8120dab5 : page_cache_pipe_buf_release+0x15/0x20 [kernel] (inexact)
0xffffffff8120d9a1 : splice_from_pipe_feed+0xc1/0x120 [kernel] (inexact)
0xffffffff8120da00 : pipe_to_sendpage+0x0/0xa0 [kernel] (inexact)
0xffffffff8120f2ee : generic_file_splice_read+0x3e/0x80 [kernel] (inexact)
Paras: elv_merge bio=(18446612139773339136),(noop),return is (0)-------------------可以对比上面的bio,两者相等
Returning from: 0xffffffff812c4b50 : elv_merge+0x0/0xe0 [kernel]
Returning to : 0xffffffff812cd03b : blk_queue_bio+0x8b/0x3a0 [kernel]

综上所述,在noop的调度策略中,io还是正常合并的,虽然叫先来先服务,但是合并还是正常进行,除非一种情况,那就是采用none调度策略。

cat /sys/block/nvme0n1/queue/scheduler

none

Nvme调度策略就是none。

noop还是会尝试在block层合并,但是none的意思是不是说就不合并了呢?也不是,我们查看nvme的驱动,发现nvme的queue有一个合并的flag,当开启的时候,也会尝试合并,但是,nvme真的足够快,查看iostat统计发现,没看到过合并的记录打印。

io调度策略noop的理解的更多相关文章

  1. linux io的cfq代码理解

    内核版本: 3.10内核. CFQ,即Completely Fair Queueing绝对公平调度器,原理是基于时间片的角度去保证公平,其实如果一台设备既有单队列,又有多队列,既有快速的NVME,又有 ...

  2. java基础之IO流及递归理解

    一.IO流(简单理解是input/output流,数据流内存到磁盘或者从磁盘到内存等) 二.File类(就是操作文件和文件夹的) 1.FIleFile类构造方法 注意:通过构造方法创建的file对象是 ...

  3. 对于IO流的个人理解

    Samuel 2018-04-21 在这之前,我给你们构造这样一个生活用水的场景: 人们日常生活需要生活用水,那么,水从哪里来呢? 大家都学过初中的物理常识,水在地表,通过蒸发,变成水蒸气去到空中,在 ...

  4. Java的IO操作,个人理解。

    先看一段代码: import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import ...

  5. 关于Blocking IO,non-Blokcing IO,async IO的区别和理解

    来源:http://shmilyaw-hotmail-com.iteye.com/blog/1896683 概括来说,一个IO操作可以分为两个部分:发出请求.结果完成.如果从发出请求到结果返回,一直B ...

  6. IO口输入输出模式理解

    1.IO输入输出模式 2.有上拉,下拉,弱上拉,推挽,开漏输出:不同的单片机有不同的输出模式 3.以最简单的51单片机为例 P0:开漏型双向IO口,通常需要添加外部上拉电阻 P1~P3:准双向IO口, ...

  7. 【代码笔记】Java文件的输入输出(1)——Java.io包的初步理解

    Java里面文件的输入输出全部在java.io包里面. Java.io包里面所有的类都需要掌握. java.io包里面所有的东西都在上面了. 包里面的相关类.异常等树关系如下 类分层结构 java.l ...

  8. IO多路复用?我所理解的IO模式

    1:IO的过程 当我们调用系统函数read时,一般会经历两个阶段: 1:等待数据准备(waiting for the data be ready) 2:将数组从内核拷贝到进程(从内核态到用户态)(co ...

  9. FPGA之IO信号类型深入理解

    在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...

随机推荐

  1. JavaScript、ES5和ES6的介绍和区别

    JavaScript由三部分组成: ECMAScript(核心) DOM(文档对象模型) BOM (浏览器对象模型) ES5(ECMAScript第五个版本) strict模式 严格模式,限制一些用法 ...

  2. SSH实战OA 11:BBS模块

    <SSH实战OA>系列博客的系统管理.权限管理等内容后面再补上吧,先继续第三个模块:网上交流模块.网上交流主要做两个需求:论坛管理和论坛. BBS的一些基本术语: 板块:也叫做" ...

  3. IDEA第六章----快捷键

    第一节:解决快捷键冲突 idea支持很多快捷键,这样就导致了很多快捷键和其他应用冲突,所以需要把其他应用的快捷键去掉,下面以输入法和QQ为例. QQ我就留下了提取消息和截图,这个是个人习惯问题. 第二 ...

  4. kotlin学习-初次见面

    第一次相识 最近看了很多介绍kotlin的文章.怀着好奇心改造了之前用java写的一个工具jar包.功能不是很复杂,类也只有几个,却足足写3个小时.期间一边看教程,一边写,有一种找回原来第一次写代码的 ...

  5. grpc 入门(一)--hello world

    一,从rpc接口的定义说起,下面给一个最简单的grpc示例--hello world 在这个rpc横行的世界里,实现一个rpc很重要的一件事就是定义一个好接口,一个好的接口定义会让你省去很多麻烦.熟悉 ...

  6. tomcat 发布简单的html网站

    1.建立一个文件夹D:\Demo 2.在Demo目录下,建立一个WEB-INF的文件夹并将web.xml放在里面,D:\Demo\WEB-INF\web.xml 3.将index.html文件放在De ...

  7. python3之装饰器

    1.装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处 ...

  8. JavaScript(五)语句

    js 的语句有 表达式语句,  复合语句{}, 空语句, 声明语句 if 默认不写大括号 可以执行 紧接着的一行 do-while do{}while() while for(初始化:判断:更新){执 ...

  9. flask-日料网站搭建

    引言:想使用python的flask框架搭建一个日料网站,主要包含web架构,静态页面,后台系统,交互. 本节知识:搭建web目录,目前正在copy网站. python环境:python2.7,fla ...

  10. SQLAlchemy表操作和增删改查

    一.SQLAlchemy介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数 ...