io调度策略noop的理解

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 creation of new processes...\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的意思就是直接pci下发到nvme协议层。主要是,nvme真的足够块,绕过了很厚的scsi协议层。

时间: 2024-08-29 17:39:55

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

LINUX IO调度策略

IO调度策略 IO调度策略一般有btrfs cfq,noop, deadline三种 附录: IO调度器的总体目标是希望让磁头能够总是往一个方向移动,移动到底了再往反方向走,这恰恰就是现实生活中的电梯模型,所以IO调度器也被叫做电梯. (elevator)而相应的算法也就被叫做电梯算法.而Linux中IO调度的电梯算法有好几种,一个叫做as(Anticipatory),一个叫做 cfq(Complete Fairness Queueing),一个叫做deadline,还有一个叫做noop(NoO

java基础之IO流及递归理解

一.IO流(简单理解是input/output流,数据流内存到磁盘或者从磁盘到内存等) 二.File类(就是操作文件和文件夹的) 1.FIleFile类构造方法 注意:通过构造方法创建的file对象是在内存里面,而不是在磁盘里面. File(String pathname)  根据指定的路径名创建file对象 File(String parent, String child)  根据 parent 路径名字和 child 路径名创建一个File对象 File(File parent, Strin

FPGA之IO信号类型深入理解

在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用Verilog代码来实现.下面将介绍在Xilinx 7系列FPGA上两种实现方式的差别和注意点. 不管哪种方式实现IO功能,从编译结果看都会调用IOBUF原语,为此,我们先来看一下IOBUF的结构,如下图所示. 1.FPGA原语实现 首先,我们编写的代码如下: 1`define PRIMITIVE 2

深入理解Java中的IO

深入理解Java中的IO 引言:     对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java >   本文的目录视图如下: Java IO概要 a.Java IO中常用的类 b.Java流类的类结构图 1.流的概念和作用 2.Java IO所采用的模型  : 3.IO流的分类 4.Java IO流对象 1.输入字节流InputStream 2.输出字节流OutputStream 3.字符输入流Reader 4.字符输出流Write

linux IO调度

I/O 调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色.他要求请求的次序和时机做最优化的处理,以求得尽可能最好的整体I/O性能.在linux下面列出4种调度算法CFQ (Completely Fair Queuing 完全公平的排队)(elevator=cfq): 这是默认算法,对于通用服务器来说通常是最好的选择.它试图均匀地分布对I/O带宽的访问.在多媒体应用, 总能保证audio.video及时从磁盘读取数据.但对于其他各类应用表现也很好.每个进程一个queue,每个queue按照上

应该选择哪种IO调度算法

写操作通常是在内核有空的时候才将请求提交给磁盘的,写操作完全和提交它的应用程序异步执行试问:内核如果一直忙碌怎么办?是否会最终耗尽高速缓冲区.试问:如何得知当前的内核应用哪中IO调度程序摘自:本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-06/37674.htm查看当前IO cat /sys/block/{DEVICE-NAME}/queue/scheduler cat /sys/bloc

linux的cpu和磁盘io优先级设置

通常linux下限制cpu使用有三种方法: nice/renice:调整进程使用cpu的优先级 cpulimit:不修改进程的nice值,通过暂停进程一段时间,来限制cpu使用 cgroups:内核提供的机制,可以限制.记录.隔离一组进程所使用的cpu.内存.磁盘.网络等资源,是docker等容器的基础技术之一 限制磁盘io : ionice : 调整io调度的优先级 cgroups 这里只说nice和ionice,实际上nice和ionice只是改变优先级,并没有真正的限制 一.nice 1.

Nginx:异步非阻塞IO

在使用socket编程中,经常会看到阻塞.非阻塞.同步.异步,那么它们之间到底有什么关系跟区别呢? 本次将那Nginx的异步非阻塞的事件驱动模型来解释一下它们之间的关系. 阻塞IO 在linux中,默认所有socket都是阻塞的. 这意味着使用该socket调用诸如recv的函数时,在没有数据到达之前,该函数将不会返回,导致线程被阻塞,直到数据到达. 非阻塞IO 我们可以使用fcntl把socket设置为非阻塞的. 这意味着使用该socket调用诸如recv的函数时,该函数将立刻返回,可以根据返

python开发IO模型:阻塞&amp;非阻塞&amp;异步IO&amp;多路复用&amp;selectors

一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西.这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同.所以,