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. this与base关键字

    this关键字 this关键字代表当前对象,通过this关键字可以访问当前对象的成员.(当前对象的成员:自己本身的成员+从父类继承过来的所有的成员.) this关键字可以访问:本类的所有成员和父类的非 ...

  2. iOS开发系列

    因为最近面试了一些人,校招.初中级.高级.架构师,各种级别的,发现大家水平差异很大,有的高级的工程师很多问题都回答不上来,所以想梳理下iOS的知识点,写成一个系列,如果时间允许的话,会录制成视频放到网 ...

  3. 【读书笔记与思考】《python数据分析与挖掘实战》-张良均

    [读书笔记与思考]<python数据分析与挖掘实战>-张良均 最近看一些机器学习相关书籍,主要是为了拓宽视野.在阅读这本书前最吸引我的地方是实战篇,我通读全书后给我印象最深的还是实战篇.基 ...

  4. golang其实也可以优先调度

    线上一个服务有个严重问题,处理消息数1k/s提升不上去,经过查看是阻塞在了一个新加的函数上,这个函数负责收集信息,送到一个channel上,再由某个函数处理,这个处理函数很简单,看不出任何问题,最大的 ...

  5. boltdb的实现

    整个代码不是很复杂,可以从代码中理解如何实现. 特点:btree,很小巧,但实现了完整事务机制,稳定,即使丢电也不会导致数据库错误. 整个结构如下: meta page (前两页) --- > ...

  6. ACSA Associate -- 01 Introduction To The Course

    1. 为什么要学习AWS认证? 2. AWS认证的考试是如何组织的? 3. 你需要做些什么? 4. 关于ACSA和ACSA BETA的信息 5. 其他链接 15 Top Paying IT Certi ...

  7. Ubuntu设置程序开机自启或者开机禁止加载

    先说说ubuntu,它有运行级别这个概念 0:停机 1:单用户形式,只root进行维护 2:多用户,不能使用net file system 3:完全多用户 5:图形化 6:重启 例子:按指定顺序.在指 ...

  8. JAVA读取和写入properties文件

    1.读取 Properties prop = new Properties(); try { //这个getResourceAsStream方法就是把文件转为inputStream的方式 prop.l ...

  9. Canvas-图片旋转

    Canvas-图片旋转 众所周知canvas是位图,你可以在里面渲染你要的东西,不过你只能操作canvas的属性来进行编辑.就是说你并不能操作画进canvas的东西,例如我在canvas里添加一幅画, ...

  10. VSCode好用的Python插件及配置

    MS Python插件. 这是微软官方的Python插件,已经自带很多功能.下面是插件功能描述,其中部分内容我做了翻译. a)        Linting (Prospector, Pylint,  ...