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. Python新手需要掌握的知识点

    一.基础语法 1 变量 2 逻辑判断 3 循环 4 函数 二.数据结构 1 数字(加减乘除) 2 字符串(一串字符) 3 布尔 (真假) 4 元组 (不能修改的列表) 5 列表(Python的苦力,最 ...

  2. Web服务器(Apache)与Servlet容器(Tomcat)

    之前一直比较迷惑Apache与Tomcat的关系,通过查询资料,有所了解,现记录于此. Apache与Tomcat 两者定位:Apache是HTTP Web服务器,Tomcat是Web容器. 有一个非 ...

  3. 强化学习之Q-learning ^_^

    许久没有更新重新拾起,献于小白 这次介绍的是强化学习 Q-learning,Q-learning也是离线学习的一种 关于Q-learning的算法详情看 传送门 下文中我们会用openai gym来做 ...

  4. 代码审计之XiaoCms(后台任意文件上传至getshell,任意目录删除,会话固定漏洞)

    0x00 前言 这段时间就一直在搞代码审计了.针对自己的审计方法做一下总结,记录一下步骤. 审计没他,基础要牢,思路要清晰,姿势要多且正. 下面是自己审计的步骤,正在逐步调整,寻求效率最高. 0x01 ...

  5. Send Email in .NET Core 2.0

    在.NET Core 1.0 中,SMTP Client代码并没有被移植,直到.NET Core 2.0的发布.使用下面的代码: static void Main(string[] args) { S ...

  6. Coursera课程 Programming Languages, Part C 总结

    碎言碎语 和前面的 ML 和 Racket 感觉明显不一样了,一边学着一边觉得这真是一门奇怪的语言,有着各种奇怪的语法,不过真的算是一个奇妙的体验(相比前面的两门语言,Ruby 的学习资源多了不少). ...

  7. Python3.5下安装&测试Scrapy

    1.引言 Scrapy框架结构清晰,基于twisted的异步架构可以充分利用计算机资源,是做爬虫必备基础,本文将对Scrapy的安装作介绍. 2.安装lxml 2.1  下载地址:https://ww ...

  8. mysql一些函数的记录

    今天瞎搞还是弄不出报名程序,偶尔记住了几个mysql函数 mysql_connect()连接数据库 mysql_error()输出文本报错 mysql_select_db()函数设置活动的MySQL  ...

  9. Redux入门示例-TodoList

    Tip 前端技术真是日新月异,搞完 React 不搭配个数据流都不好意思了.满怀期待的心去翻了翻 flux,简直被官方那意识流的文档折服了,真是又臭又长还是我智商问题?

  10. SpringBoot(四)之thymeleaf的使用

    这篇文章将更加全面详细的介绍thymeleaf的使用.thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎. thymeleaf介绍 简单说, Th ...