ImageVerifierCode 换一换
你正在下载:

IO系统.docx

[预览]
格式:DOCX , 页数:25 ,大小:309.72KB ,
资源ID:1748404      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-1748404.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(IO系统.docx)为本站会员(b****2)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

IO系统.docx

1、IO系统I/O系统第1节 I/O的基本概念 1第2节 磁盘结构 12.1 磁盘布局 12.2 影响磁盘读写速度的因素 32.3 磁盘的低级格式化 3第3节 磁盘I/O 43.1 BIO结构 43.2 前置合并(front merge)和后置合并(back merge) 4第4节 调度算法 44.1 noop调度器 54.2 deadline调度器 54.2.1 设计和实现 54.2.2 调优参数 64.3 as 64.4 cfq 74.4.1 简要原理和工作流程 74.4.2 调优参数 74.4.3 ionice命令 84.5 I/O调度方法的查看与设置 8第5节 I/O编程模型 85.1 同

2、步和异步 85.2 阻塞和非阻塞 85.3 同步阻塞I/O 95.4 同步非阻塞I/O 95.5 异步阻塞I/O 115.5.1 select 115.5.2 epoll 125.5.3 edge-triggered and level-triggered 145.6 异步非阻塞I/O 145.7 各种实现方法的优缺点 15第1节 I/O的基本概念与外设的通讯通常称之为输入输出,简称I/O。第2节 磁盘结构2.1 磁盘布局每个磁道有几百个扇区,每个扇区是512字节恒定角速度好处在于每块数据可以由磁道和扇区直接定位,缺点在于浪费了外圈的存储空间。多区记录,将磁盘表面划分为多个同心的区域,一般为1

3、6个,每个外层区域比内层区域的扇区数大约多出4%(现代操作系统第三版)。在一个区域内,每个磁道的扇区数是一样的。因此这种方法的优点在于比较充分的利用了存储空间,代价是更复杂的旋转控制。2.2 影响磁盘读写速度的因素寻道时间:磁头移动到特定磁道所需要的时间 普通SATA硬盘在10ms左右。服务器硬盘在2ms4ms或更多旋转延迟:读取的扇区转到磁头下方所需要的时间7200rpm,60000ms/7200=8.33ms,8.33ms/2=4.17ms15000rpm,2ms2.3 磁盘的低级格式化设定磁道、扇区。柱面斜进扇区交错 无交错 单交错 双交错第3节 磁盘I/O3.1 BIO结构磁盘的读写并

4、不是以数据块或磁盘扇区为单位的,而是以BIO结构为基本的读写单位。一个BIO结构包含传输的起始扇区号、一个包含需要传输的内存页的数组(一般为属于同一个inode的多个页面),以及相关联的其它BIO实例。对I/O读写是以请求队列来实现,一个请求结构可以包含多个BIO,多个请求连在一起形成队列。为了减少磁盘寻道时间,减少磁头移动,并在一次旋转中尽可能多的进行读写,因此当一个新的BIO被提交过来,并不是放在队列的尾部,内核会分析这个BIO,并尝试将这个BIO合并进已有的请求中,如果无法合并,则将其放在尾部。3.2 前置合并(front merge)和后置合并(back merge)Linux的I/O

5、调度器维护一个以每个请求最后一个扇区号为索引的哈希表,当有新的请求加入时,会检查这个新请求的起始扇区号是否与已有请求的最后扇区号相连,发现的后就执行合并,这就是后置合并。若检查新请求的最后扇区号,看是否和已有请求的首扇区号相连,有的话就执行合并,这是前置合并。在通常情况下,后置合并的可能性远远大于前置合并,因为读写通常都是前向的。除非某用户进程倾向于从后向前读写数据,此时前置合并的几率才会高。第4节 调度算法内核采用的各种用于调度和重排I/O的算法,称为I/O调度器。I/O调度时,遵循电梯算法。1)当向设备写入数据块或是从设备读出数据块时,请求都被安置在一个队列中等待完成.2)每个块设备都有它

6、自己的队列.3)I/O调度程序负责维护这些队列的顺序,以更有效地利用介质.I/O调度程序将无序的I/O操作变为有序的I/O操作.4)内核必须首先确定队列中一共有多少个请求,然后才开始进行调度.4.1 noop调度器NOOP调度器维护一个先进先出(FIFO)的I/O队列,这个队列不能重排,但新提交的请求可以和现有请求执行后置合并。noop调度器的设计思路是:对I/O性能的优化已经被I/O路径上的某个层实现了,因此它的设计要尽可能简单,减少对CPU的消耗。智能的Serial Attached SCSI (SAS) RAID控制器和Storage Area Network网络存储都具有I/O优化功能

7、;固态磁盘没有机械装置,因此没有寻道和旋转延迟,它也不需要I/O调度优化;某些嵌入式系统I/O操作很少,也会采用NOOP调度器来减少CPU功耗。NOOP调度器有利于写而不利于读。因为写操作一般都是异步的,即写操作先写进写缓存中,然后定时将写缓存中的内容写进磁盘。而读操作一般都是同步的,当数据不在缓存中,就要向磁盘发出读请求。在这种情况下,到达调度器时,读操作是单个的请求,而写操作是多个,因此某些写操作更容易和前面的请求合并,而读操作一般只能乖乖排队。4.2 deadline调度器4.2.1 设计和实现deadline调度器规定了一个期限,如果一个请求超过了这个期限,则它就会被调度。这个期限是软

8、限制,超过它,这个请求就会离开调度队列,进入到块设备的请求队列等待驱动去执行它,而不是这个请求立刻就实际发起。deadline调度器考虑了批量执行、写饥饿、请求超时这三个因素。deadline调度器下,一共有5个队列,一个是块设备的请求队列,调度器的任务是从其它四个队列中挑出一个请求放进块设备的请求队列。读请求有两个队列,一个FIFO链表fifo_list,一个是按扇区编号排序的红黑树sort_list,写请求也是如此。为了提高性能,定义了以静态常量fifo_batch,值为16,即一次传递给块设备的请求队列16个读或写请求(过去的实现是检查每一个请求是否和上一个请求的扇区号相连,不相连则中断

9、传递),然后再做下一次选择。请求的规则如下,1 首先判断是否已经传递过去16个请求,如果还没到16个,则从sort_list中按扇区号继续调出下一个请求。注意,这16个请求必须是同方向的,即要么是读,要么是写。2 若这批请求已经到了16个,则要选择下一批传送的请求是读还是写。deadline倾向于优先考虑读请求,因为发起应用程序发起读请求后会阻塞,而写一般都是异步写。因此定义了全局静态常量writes_starved,值为2。即调度两批读请求之后才会调度一批写请求。因此这一步会检查writes_starved的值,若大于等于2,则决定下一批调度的是写请求。3 决定好是读还是写之后,就检查相应的

10、fifo队列的队首:3.1 若这个请求已超时,则调度它(rq_a),下一个请求是sort_list队列中的扇区编号大于rq_a且与之相邻的请求。3.2 若这个请求未超时,则从上一批结束的位置(sort_list中的位置)继续向下调度。3.3 若这个请求未超时,但上一批请求已经到了sort_list的队尾,则调度fifo队首那个请求。总结:1 deadline考虑了性能,体现在有一个按扇区号排序的sort_list队列,在其中一次提交16个连续的请求.2 deadline优先考虑了读请求,因为读请求会阻塞进程,而写一般不会。3 deadline通过设置writes_starved考虑了写饥饿4

11、deadline通过设置最后服务时间避免了请求被饿死。读请求超时是500ms,写请求是5s。不足(待验证):在写请求与读请求调度切换时,有一次磁头的随机寻道。在调度一批读请求之后,指针指向了读请求sort_list中下一个请求rq_r,然后调度一批写请求,写请求调度完成之后,另外一个指针指向了写请求的sort_list的下一个请求rq_w,再次调度读请求,若符合3.2中叙述的情况,则调度rq_r,而上批写请求中最后一个请求的扇区号与rq_r的扇区号没有任何关系,因此极有可能发生一次随机寻道。从读请求切换至写请求也是如此。解决办法是当符合3.2的情况时,考虑是否是发生了读写切换,如果是,则根据上

12、一个请求的扇区号从新选择要调度的请求。按提交时间排序4.2.2 调优参数fifo_batch:一批请求的最大数目,默认是16front_merges:是否执行扇区前置合并,默认为1,即执行read_expire:读请求的超时时间,默认为500mswrite_expire:写请求的超时时间,默认为5swrites_starved:写请求队列的调度频率,默认是2。即发送两批读请求之后,发送1批写请求。4.3 asAnticipatory scheduling 是算法最复杂的I/O调度器,是2.6.0 至 2.6.18的默认调度器,在2.6.33中被删掉。4.4 cfq从2.6.19内核开始,CFQ

13、做为默认的I/O调度器。CFQ试图将I/O带宽均匀分配给各个进程,但同时考虑了优先级、deadline和anticipatory。CFQ适用于通用服务器、多媒体应用(video,audio)和桌面系统。4.4.1 简要原理和工作流程1. 进程的I/O优先级分为3类:RT(real-time)、BE(best-effort)、Idle。RT和BE各有8个等级,0的优先级最高、7的优先级最低。具有RT优先级的请求优先被执行,没有RT之后才执行BE,没有BE之后才执行Idle。同一优先级类的进程通过时间片长短来体现优先级的高低。2. I/O请求被分为同步和异步两种。3. 异步队列是系统范围内的,即没

14、有进程的区别,共有17个异步队列,分别对应3类17个优先级。4. 每一个进程的同步请求都单独成队列,每个进程的同步请求队列分为两列,分别是按扇区排序和fifo队列,当调度此进程I/O请求时,和deadline算法相同。5. 各个进程的同步请求队列被轮流调度,异步队列也在此轮转当中。6. 当一个进程的同步I/O请求被调度时,一次发送4个请求至驱动,这表明对磁盘的访问是独占的。当4个请求已完成而时间片尚未用完,则继续调度此进程的请求。若此进程没有更多的请求,则等待8ms(称为Idling),看此进程是否会产生新的请求。若没有新请求产生则调度下一队列。此算法借鉴了Anticipatory sched

15、uling调度器思想。即基于局部性原理的考虑,同一个进程发出的I/O请求很有可能是按磁盘块号顺序的。4个请求和8ms都是默认设置,可通过sys文件系统修改。7. 以下情况不做idlinga) 队列已超时b) idle优先级队列c) 异步队列d) 此队列和其它队列有close cooperator(请求合并)。8. idle队列没有时间片,一次只发送一个请求至驱动。9. 当服务BE进程队列时,若出现具有RT优先级的进程,则被抢占。即时间片未到,也不能发送下一批请求至驱动。10. 若进程启动时未指定I/O优先级,则I/O优先级会继承CPU优先级,即实时进程的I/O优先级也为RT,普通进程的I/O优

16、先级为BE。实时进程的CPU优先级为199,普通进程为100139。用户通过nice值设定实时和普通进程的优先级,-2019经过转换变为1139供内核使用。nice值通过如下公式转换至I/O优先级:(nice+20)/5。4.4.2 调优参数back_seek_penalty:反向寻道的代价。即相对于正向寻道,反向寻道相同数目的扇区所需要花费的时间,是正向寻道所需时间的倍数。此参数用于队列的扇区排序。默认是2back_seek_max:反向寻道最大数值,默认是16M。超过此值,则遵循电梯原则fifo_expire_sync:同deadline调度,fifo队列头的请求超时时间。默认为125ms

17、fifo_expire_async:同上。默认为250mslow_latency:桌面模式,当打开时,会加速写操作的交互时间。默认开启。在服务器上可关闭它。quantum:一次从队列中发给驱动的请求数,默认为4slice_sync:同步请求队列优先级的基准时间片,即BE类优先级为4的队列的时间片,默认为100ms,每一级相差20msslice_async:默认是40ms,每一级相差20msslice_idle:队列已空,但时间片未用尽,等待下一个请求到达的时间。默认为8ms。此等待时间对于寻道时间长的块设备很有用,但对于raid来说,寻道时间并不重要,因此将此值设为0更有效率。slice_as

18、ync_rq:基础值,用于确定一个发送给驱动的最大异步请求数目,当超过此数值,即使未用尽时间片,也认为它超时,开始调度下一个队列。2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq-ioprio);base_rq即slice_async_rq;CFQ_PRIO_LISTS为优先级个数,即为8;cfqq-ioprio为当前队列的优先级。4.4.3 ionice命令ionice可以更改任务的类型和优先级,不过只有cfq调度程序可以用ionice.有三个例子说明ionice的功能:采用cfq的实时调度,优先级为7ionice -c1 -n7 -pt

19、ime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&采用缺省的磁盘I/O调度,优先级为3ionice -c2 -n3 -ptime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&采用空闲的磁盘调度,优先级为0ionice -c3 -n0 -ptime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&4.5 I/O调度方法的查看与设置1)查看当前系统的I/O调度方法:cat /sys/block/sda/queue/scheduler noop anticipatory

20、deadline cfq2)临地更改I/O调度方法:例如:想更改到noop电梯调度算法:echo noop /sys/block/sda/queue/scheduler3)想永久的更改I/O调度方法:修改内核引导参数,加入elevator=调度程序名vi /boot/grub/menu.lst更改到如下内容:kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet 4)I/O调度器是针对设备的,不同的磁盘可以设定不同的调度器。5)调度器的参数设置:/sys/block/queue/iosched

21、第5节 I/O编程模型5.1 同步和异步所谓同步,就是在发出一个功能调用时,在没有得到结果之前,不做其它事。异步的概念和同步相对。当一个异步过程调用发出后,调用者并不等待结果,而是去做其它事。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。5.2 阻塞和非阻塞阻塞是指调用结果返回之前,当前进程或线程会被挂起。非阻塞和阻塞的概念相对应,指在得到结果之前,该进程或线程不会被阻塞,而可以继续做其它事情。5.3 同步阻塞I/O发出I/O读写请求,并等待结果。由于I/O时间较长,内核会阻塞该进程,做上下文切换,调度其它进程来执行。这是正常的、用的最多的I/O模型。5.4 同步非阻塞I/

22、O发出I/O请求,并要求立刻返回结果,如果结果没有返回(返回EAGAIN错误),则继续发请求,直至返回结果。下面这个图是一个I/O的read请求,设置了非阻塞I/O后,read调用会立刻返回结果,刚开始肯定不会成功,反复的调用read,直至读出数据。考虑一个telnet的例子,一个telnetd守护进程与一个客户端交互,通过read读取客户端的输入,同时还要等待新的客户端的连接。这就需要多个I/O读取,它不能在任一个读取上阻塞,否则会影响另一个的读取。因此它可以采用同步非阻塞的方法,设置非阻塞I/O,然后调用read,如果没有数据则立刻返回,过若干秒在去read一次。这种形式的循环称作轮询(p

23、olling)下面这段代码是write非阻塞I / O调用的一个实例,它从标准输入读500 000字节,并试图将它们写到标准输出上。该程序先将标准输出设置为非阻塞的,然后用 f o r循环进行输出,每次写的结果都在标准错误输出上打印。函数c l r_f l类似于s e t _ f 1,但与s e t _ f 1的功能相反,它清除1个或多个标志位。#include apue.h#include #include char buf500000;int main(void)int ntowrite, nwrite;char *ptr;ntowrite = read(STDIN_FILENO, buf

24、, sizeof(buf);fprintf(stderr, read %d bytesn, ntowrite);set_fl(STDOUT_FILENO, O_NONBLOCK); /* set nonblocking */ptr = buf;while (ntowrite 0) errno = 0; nwrite = write(STDOUT_FILENO, ptr, ntowrite); fprintf(stderr, nwrite = %d, errno = %dn, nwrite, errno); if (nwrite 0) ptr += nwrite; ntowrite -= nwr

25、ite; clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */exit(0);程序说明:若标准输出是普通文件,则w r I t e只执行一次。但是,若标准输出是终端,由于终端的限制,一次write调用不会写500000个字符,所以需要循环,写入成功时,每次write调用的返回值是的写成功字节数,有时则出错返回。下面是在一个系统上运行程序的结果:$ a.out stderr.out $ cat stderr.outread 100000 bytesnwrite = 8192, errno = 0nwrite = 8192, errn

26、o = 0nwrite = -1, errno = 11 这种错2 1 1次nwrite = 4096,errno = 0nwrite = -1, errno = 11 这种错6 5 8次nwrite = 4096,errno = 0nwrite = -1, errno = 11 这种错6 0 4次nwrite = 4096,errno = 0nwrite = -1, errno = 11 这种错1 0 4 7次nwrite = -1, errno = 11 这种错1 0 4 6次nwrite = 4096, errno = 0 等等在该系统上,errno 11是E A G A I N。系统上

27、的终端驱动程序总是一次接收 4 0 9 6或8 1 9 2字节。在另一个系统上,前三个w r I t e返回2 0 0 5,1 8 2 2和1 8 11,然后是9 6次出错返回,接着是返回1 8 4 6等等。每个w r I t e能写多少字节依赖于系统。这种I/O模型性能低下,在实际的的I/O编程中不会采用。但在其它情况下有可能使用。如进程A依赖进程B的结果,但进程B并不将结果返回给A,而将结果保存在其它位置上,那么A就反复读这个位置,直至取出数据。应此,同步非阻塞这个概念并非只应用在I/O编程中,而是一种广义的编程模型。5.5 异步阻塞I/O5.5.1 select在telnetd的例子中,

28、先设置非阻塞I/O,然后等待客户端的连接。客户端连接后,将连接文件描述符发送给select系统调用,此时进程阻塞在select系统调用上。它与同步阻塞I/O的区别在于:进程可以发起多个I/O请求,有读有写,select设置一个I/O集合(此集合的大小需要在调用select时设定好,以后不能增加,所以有局限性),进程依次将请求发给select的这个集合,当一个或多个I/O准备好了,select都会返回。进程做一循环,检查是哪个I/O请求准备好了,然后调用相应的处理代码。具体使用select编程的过程如下:进程首先打开设备,取得文件描述符,然后通过FD_SET将这个描述符及I/O操作(读、写等)注

29、册进一个fd_set结构(select中共有3个结构,分别是读、写、异常)。当所有要做的I/O请求都已注册完毕,调用select,select会阻塞,当select返回时,进程循环检查是哪个I/O请求准备好了,并执行相应的代码。在网络编程中,进程调用一个无限循环,循环起始调用select,在循环过程中,若有新的客户端,则注册进fd_set,下次循环select就会新老客户端一起检查。若客户端超过事先设定的上限,则拒绝注册新的客户端。异步阻塞I/O是对通知事件进行阻塞,而不是对 I/O 调用进行阻塞。即当有通知到达时,一定有某个I/O是已经ready的。若是单个I/O,则这种方式无意义,但当有多

30、个I/O时,进程不会因为某一个I/O被阻塞而影响其它已经ready的I/O。这种方式也称作I/O多路复用。#include csapp.hvoid echo(int connfd);void command(void);int main(int argc, char *argv) int listenfd, connfd, port; socklen_t clientlen = sizeof(struct sockaddr_in); struct sockaddr_in clientaddr; fd_set read_set, ready_set; if (argc != 2) fprintf

31、(stderr, usage: %s n, argv0); exit(0); port = atoi(argv1); listenfd = Open_listenfd(port); /line:conc:select:openlistenfd FD_ZERO(&read_set); /* Clear read set */ /line:conc:select:clearreadset FD_SET(STDIN_FILENO, &read_set); /* Add stdin to read set */ /line:conc:select:addstdin FD_SET(listenfd, &read_set); /* Add listenfd to read set */ /line:conc:select:a

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2