linux内核分析笔记----块I/O层

通用块层与bio 通用块层与bio通用块层什么是通用块层?通用块层是一个内核组件,它的作用就是处理来自上层对所有块设备发出的io操作。例如,上层文件系统对磁盘上某个文件的读写操作都会转换成相应的io操作然后交给我们的通用块层进行处理。bio结构上面我们提到了很多次io操作的概念,,内核用一个叫做bio的结构体来描述一次块io操作。下面我们来分析一下bio的重要结构。struct bio { sector_t 阅读详情

      如果您记性好的话,应该记得我在linux设备驱动实例帖中说的最多的就是字符设备驱动程序,那么今天的块I/O层是一个和字符设备驱动相对应的设备。两者最根本的区别就是看它们能否被随机访问,换句话说就是看它们能否在访问设备时从一个位置随意地调到另外一个位置,如果可以就是块设备,否则就字符设备。

      块设备中最小的可寻址单元是扇区。扇区的大小一般是2的整数倍,最常见的大小是512个字节。扇区的大小是设备的物理属性,扇区是所有块设备的基本单元,块设备无法对比它还小的单元进行寻址和操作,不过许多块设备能够一次就传输多个扇区。从软件角度来讲,最小的逻辑可寻址单元却是块,块是文件系统的一种抽象-----只能基于块来访问文件系统。虽然物理磁盘寻址是按照扇区级进行的,但是内核执行的所有磁盘操作都是按照块进行的。前边已经说过,扇区是设备的最小可寻址单元,所以块不能比扇区还小,只能数倍于扇区大小。另外内核还要求块大小是2的整数倍,=而且不能超过一个页的长度,所以大小的最终要求是,必须是扇区大小的2的整数倍,并且要小于页面大小。所以通常块大小是512字节,1k或4k。

当一个块被调入内存时,它要存储在一个缓冲区中,每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示。另外,由于内核在处理数据时需要一些相关的控制信息,所以每个缓冲区都有一个叫做buffer_head的描述符来表示,被称为缓冲区头,在linux/buffer_head.h中定义,它包含了内核操作缓冲区所需要的全部信息,如下:

struct buffer_head {
        unsigned long        b_state;          /* buffer state flags */
        atomic_t             b_count;          /* buffer usage counter */
        struct buffer_head   *b_this_page;     /* buffers using this page */
        struct page          *b_page;          /* page storing this buffer */
        sector_t             b_blocknr;        /* logical block number */
        u32                  b_size;           /* block size (in bytes) */
        char                 *b_data;          /* buffer in the page */
        struct block_device  *b_bdev;          /* device where block resides */
        bh_end_io_t          *b_end_io;        /* I/O completion method */
        void                 *b_private;       /* data for completion method */
        struct list_head     b_assoc_buffers;  /* list of associated mappings */
};

      其中的b_state域表示缓冲区的状态,下表给出一种标志或多种标志的组合,在linux/buffer_head.h中定义了所有合法标志的bh_state_bite列表,如下所示:

     image

      bh_state_bits列表包含了一个特殊标志----BH_PrivateStart,该标志不是可用状态标志,使用它是为了指明可能其它代码使用的起始位。块I/O层不会使用BH_PrivateStart或更高的位,那么某个驱动程序希望通过b_state域存储信息时就可以安全地使用这些位。驱动程序可以在这些位中定义自己的状态标志,只要保证自定义的状态标志不会与块IO层的专用位发生冲突就可以了。b_count域表示缓冲区的使用计数,可通过两个定义在文件linux/buffer_head.h中的内联函数对此域进行增减:

static inline void get_bh(struct buffer_head *bh)
{
        atomic_inc(&bh->b_count);
}
static inline void put_bh(struct buffer_head *bh)
{
        atomic_dec(&bh->b_count);
}

      在操作缓冲区头之前,应该先使用get_bh()函数增加缓冲区头的引用计数,确保缓冲区头不会再被分配出去,当完成对缓冲区头的操作之后,还必须使用put_bh()函数减少引用计数。与缓冲区对应的磁盘物理块由b_blocknr域索引,该值是b_bdev域指明的块设备中的逻辑块号。与缓冲区对应的内存物理页由b_page域表示,另外,b_data域直接指向相应的块(它位于b_page域所指明的页面的某个位置上),块的大小由b_size域表示,所以块在内存中的起始位置在b_data处,结束位置在(b_data+b_size)处。缓冲区头的目的在于描述磁盘块和物理内存缓冲区(在特定页面上的字节序列)之间的映射关系。这个结构体在内核中扮演一个描述符的角色,说明从缓冲区到块的映射关系。使用缓冲区头作为I/O操作有它的弊端,这里不细说,你明白就好。我们只需知道现在的内核采用了一种新型,灵活而且轻量级的容器---bio结构体。

      bio结构体定义在linux/bio.h中,该结构体代表了正在现场的(活动)以片断(segment)链表形式组织的块I/O操作。一个片断是一小块连续的内存缓冲区。这样的话,就不需要保证单个缓冲区一定要连续,所有通过片断来描述缓冲区,即使一个缓冲区分散在内存的多个位置上,bio结构体也能保证I/O操作的执行。下面给出bio结构体和各个域的描述,如下:

struct bio {
        sector_t             bi_sector;         /* associated sector on disk */
        struct bio           *bi_next;          /* list of requests */
        struct block_device  *bi_bdev;          /* associated block device */
        unsigned long        bi_flags;          /* status and command flags */
        unsigned long        bi_rw;             /* read or write? */
        unsigned short       bi_vcnt;           /* number of bio_vecs off */
        unsigned short       bi_idx;            /* current index in bi_io_vec */
        unsigned short       bi_phys_segments;  /* number of segments after coalescing */
        unsigned short       bi_hw_segments;    /* number of segments after remapping */
        unsigned int         bi_size;           /* I/O count */
        unsigned int         bi_hw_front_size;  /* size of the first mergeable segment */
        unsigned int         bi_hw_back_size;   /* size of the last mergeable segment */
        unsigned int         bi_max_vecs;       /* maximum bio_vecs possible */
        struct bio_vec       *bi_io_vec;        /* bio_vec list */
        bio_end_io_t         *bi_end_io;        /* I/O completion method */
        atomic_t             bi_cnt;            /* usage counter */
        void                 *bi_private;       /* owner-private method */
        bio_destructor_t     *bi_destructor;    /* destructor method */
};

      使用bio结构体的目的主要是代表正在现场执行的I/O操作,所有该结构体中的主要域都是用来管理相关信息的。其中最重要的几个域是bi_io_vecs,bi_vcnt和bi_idx.它们之间的关系如下图所示:

      image

      我在前边已经给出了struct bio的结构体,下面给出struct bio_vec的描述:

struct bio_vec {
        struct page     *bv_page;   /* pointer to the physical page on which this buffer resides */ 
        unsigned int    bv_len;     /* the length in bytes of this buffer */ 
        unsigned int    bv_offset;   /* the byte offset within the page where the buffer resides */ 
};

      下面来分析以上上面的那个图,我们说:每一个块I/O请求都通过一个bio结构体表示。每个请求包含一个或多个块,这些块存储在bio_vec结构体数组中,这些结构体描述了每个片断在物理页中的实际位置,并且像向量一样地组织在一起,IO操作的第一个片断由b_io_vec结构体所指向,其他的片断在其后依次放置,共有bi_vcnt个片断。当块IO开始执行请求,需要使用各个片段时,bi_idx域会不断更新,从而总指向当前片断。bi_idx域指向数组中的当前bio_vec片段,块IO层通过它跟踪块IO操作的完成进度。但该域更重要的作用是分割bio结构体。bi_cnt域记录bio结构体的使用计数,如果为0,则应该销毁该bio结构体,并释放它占用的内存。通过下面两个函数管理使用计数:

void bio_get(struct bio *bio);
void bio_put(struct bio *bio);

      最后一个域是bi_private域,这是一个属于拥有者的私有域,谁创建了bio结构,谁就可以读写该域。

      块设备将它们挂起的块IO请求保存在请求队列中,该队列有request_queue结构体体表示,定义在文件linux/blkdev.h中,包含一个双向请求链表以及相关控制信息。通过内核中想文件系统这样高层的代码将请求加入到队列中。请求队列只要不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去请求队列表中的每一项都是一个单独的请求,有reques结构体体表示。队列中的请求由结构体request表示,定义在文件linux/blkdev.h表示。因为一个请求可能要操作多个连续的磁盘块,所有每个请求可有由多个bio结构体组成,注意,虽然磁盘上的块必须连续,但是在内存中的这些块并不一定要连续----每个bio结构都可以描述多个片段,而每个请求也可以包含多个bio结构体。

      好了,我们明白了块IO请求,下面的就是IO调度了。每次寻址的操作就是定位磁盘磁头到特定块上的某个位置,为了优化寻址操作,内核既不会简单地按请求接收次序,也不会立即将其提交给磁盘,相反,它会在提交前,先执行名为合并与排序的预操作,这种预操作可以极大地提高系统的整体性能。

      IO调度程序通过两种方法减少磁盘寻址时间:合并与排序。合并指将两个或多个请求结合成一个一个新请求。关于排序的,最有名的当然就是大名鼎鼎的电梯调度。排序就是整个请求队列将按扇区增长方向有序排列,使所有请求按磁盘上扇区的排列顺序有序排列的目的不仅是为了缩短单独一次请求的寻址时间,更重要的优化在于,通过保持磁盘头以直线方向移动,缩短了所有请求的磁盘寻址的时间。关于linux中的电梯调度程序,很多操作系统的书上都已经说的很明白,我这里给出一个大致流程:

1.首先,如果队列中已存在一个对相邻磁盘扇区操作的请求,那么新请求将和这个已经存在的请求合并为一个请求。
2.如果队列中存在一个驻留时间过长的请求,那么新请求将被插入到队列尾部,以防止其他旧的请求发生饥饿。
3.如果队列中以扇区方向为序存在合适的插入位置,那么新的请求将被插入到该位置,保证队列中的请求是以被访问磁盘物理位置为序进行排序的。
4.如果队列中不存在合适的请求插入位置,请求将被插入到队列尾部。

      我前边提到过电梯调度,但是有一个问题一直没提,那就是电梯调度程序的缺点:饥饿。出于减少磁盘寻址时间的考虑,对某个磁盘区域上的繁重操作,无疑会使得磁盘其他位置上的操作得不到运行机会,实际上,一个对磁盘同一位置操作的请求流可以造成较远位置的其他请求永远得不到运行机会,这是一种很不公平的饥饿现象。更糟糕的是,普通的请求饥饿还会带来写--饥饿--读这种特殊问题。我们知道写操作通常发生在内核有空时,而读操作却必须阻塞知道读请求被满足,这对系统性能影响是非常大的。而且我们知道读请求往往相互依靠,比如要读大量的文件,每次都是针对一块很小的缓冲区进行读操作,而应用程序只有将上一个数据区域从磁盘中读取并返回之后,才能继续读取下一个数据区,所以如果每一次请求都发生饥饿现象,那么对读取文件的应用程序来说,全部延迟加起来会造成过长的等待时间。减少饥饿请求必须以降低全局吞吐量为代价。为了避免这种问题,提出了最后期限IO调度程序,既要尽量提高全局吞吐量,又要使请求得到公平处理。在最后期限IO调度程序中,每个请求都有一个超时时间。默认情况下,读请求的超时时间是500ms,写请求的超时时间是5s。最后期限IO调度请求类似与linux电梯,也以磁盘物理位置为次序维护请求队列,这个队列被称为排序队列。当一个新请求递交给排序队列时,最后期限IO调度程序类似于linux电梯,合并和插入请求,但是最后期限IO调度程序同时也会以请求类型为依据将它们插入到额外队列中。读请求按次序被插入到特定的读FIFO队列中,写请求被插入到特定的写FIFO队列中。虽然普通队列以磁盘扇区为序进行排序,但是这些队列是以FIFO形式组织的,结果新队列总是被加入到队列尾部。对于普通操作来说,最后期限IO调度将请求从排序队列的头部去下,再推入到派发队列中,派发队列然后将请求提交给磁盘驱动,从而保证了最小化的请求寻址。如果在写FIFO队列头,或是在读FIFO队列头的请求超时,那么最后期限IO调度程序便从FIFO队列中提取请求进行服务。依靠这种方法,最后期限IO调度程序试图保证不会发生有请求在明显超期的情况下仍不能得到服务的现象,如下图所示:

     image

      最后期限IO调度程序的实现在文件driver/block/deadline-iosched.c中。

      虽然最后期限IO调度程序为降低读操作响应时间做了许多工作,但同时也降低了系统吞吐量。考虑这样的情况,假设一个系统正处于很繁重的写操作期间,每次提交新请求,IO调度程序都会迅速处理读请求,这样磁盘会首先为读操作寻址,执行读操作,然后返回再寻址进行写操作,并且对每个读操作都重复这个过程。这种做法明显损害了系统全局吞吐量。这事就有了预测IO调度程序。它的基础就是最后期限IO调度程序。最主要的改进是它增加了预测启发能力。它的不同之处在于读操作提交后并不直接返回处理其他请求,而是会有意空闲片刻。这空闲的几秒钟,对应用程序来说是个提交其他读请求的好机会-----任何对相邻磁盘位置操作的请求都会立刻得到处理。在等待时间结束后,预测IO调度程序重新返回原来的位置,继续执行以前剩下的请求。要注意,如果等待可以减少读请求所带来的向后再向前(back-and-forth)寻址操作,那么完全值得花一些时间来等待更多的请求(这里的时间花在对更多请求的预测上),如果一个相邻的IO请求在等待期带来,那么IO调度程序可以节省两次寻址操作。如果存在愈来愈多的访问同样区域的读请求到来,那么片刻等待无疑会避免大量的寻址操作。当然,不得不说,如果没有IO请求在等待期到来,那么预测IO调度程序会给系统性能带来轻微的损失,浪费掉几毫秒。预测调度程序所带来的优势在于能否正确预测应用程序和文件系统的行为。这种预测依靠一系列的启发和统计工作。预测IO调度程序的实现在文件driver/block/as-iosched.c中。块设备使用哪个IO调度程序是可以选择的。默认的IO调度程序就是预测IO调度程序。

利用blktrace分析磁盘I/O blktrace对于分析block I/O是个非常好的工具,本篇文章记录了如何使用blktrace。blktrace原理blktrace是对通用块层(block layer)的I/O跟踪机制,它能抓取详细的I/O请求(request),发送到用户空间。blktrace主要由3部分组成:内核部分记录内核到用户空间的I/O追踪信息的程序分析、展示I/O追踪信息的程序主要在block layer实现,抓... 阅读详情

相关推荐

从块层到文件 I/O:io_uring、直通 I/O 与队列深度的性能真相

本文从 Linux I/O 栈的工作机理出发,梳理块层到文件 I/O 的关键机制与实践,包括 I/O 调度器、队列深度、O_DIRECT、缓存与预取、AIO 与 io_uring 的差异、fio 基准方法与指标判读,并附上针对 NVMe/SAS 的优化建议与一致性风险提醒。I/O 优化从来不是对某一个神奇开关的迷信,而是对栈中每一层行为的量化理解:调度器是否该“少做事”、队列深度在哪里拐点、直通 I/O 值不值得、缓存与预取是否帮了倒忙、io_uring 的优势如何发挥、fio 的数字到底在讲什么。

wolf800的博客 890

Matlab在新能源场景生成与削减中的实践应用

新能源场景生成与削减是电力系统规划中的关键技术,主要用于处理风能、太阳能等可再生能源的不确定性。该技术通过随机过程建模生成大量可能场景,再运用优化算法筛选代表性场景,可大幅降低计算复杂度。Matlab凭借其强大的数学计算能力和丰富的工具包,成为实现这类算法的首选平台,特别适合处理威布尔分布风速建模、Copula多变量相关分析等工程问题。在200MW光伏电站等实际案例中,该技术能将计算时间从8小时缩短至20分钟,同时保证调度方案质量损失小于2%。

weixin_34354945的博客 484

一文图解|I/O 调度层

现实中块设备的种类非常多,如磁盘、SSD(固态硬盘) 和 CD-ROM 等。由于不同种类的块设备其物理结构不同,所以优化 I/O 效率的算法也不一样。如:SSD 读写任意地址中的数据速度都一样,所以就没必要进行额外的优化,只需要将用户提交 I/O 操作直接发送给块设备驱动即可。但有些块设备的物理结构比较特殊,如磁盘,其读写速度与磁头移动的距离(寻道)有关,所以磁头移动的距离越远,读写速度就越慢。磁盘的物理结构如下图所示:对于磁盘来说,顺序读写的速度是最快的。这是由于顺序读写时,磁头移动的距离最小。

youzhangjing_的博客 1021

request_queue, request, bio 关系一句话描述

<br />看了代码,调了程序,看了文档,总算有点概念<br />记录一下<br />bio 代表一个IO 请求<br />request 是bio 提交给IO调度器产生的数据,一个request 中放着顺序排列的bio<br />当设备提交bio 给IO调度器时,IO调度器可能会插入bio,或者生成新的request<br /> <br />request_queue代表着一个物理设备,顺序的放着request<br /> <br />===========================分割线=====

flyingcloud_2008的专栏 8504

【存储原理】IO超时处理 块层block-scsi层之间

【存储原理】IO超时处理 块层block-scsi层之间

sinat_37817094的博客 1024

使用freesurfer和3Dslicer进行脑区分割和电极定点(详细版)

1、安装好matlab和freesurfer2、在目标位置创建文件夹3、开放权限4、将需要计算的nii文件放入文件夹。

zQIANYUN的博客 5628

linux内核block层源码优化之缓解容器间(多进程)IO抢占造成的IO延迟

我想从事服务器线上问题排查的同学,都应该遇到过多进程读写文件时,IO抢占导致的IO延迟明显问题。比如这样一个场景,磁盘sata,进程A不定时读取100KB的日志文件,正常情况几百us就读取完成。但是正碰巧遇到B进程也在读写一个200MB的数据文件,进程A大概率读取这100KB的配置文件耗时几十ms,甚至上百ms。 这种情况很常见,因为sata盘随机读写性能也就几十MB,IOPS也就几百吧(好点的上千)。进程B读写那200MB的数据文件基本把sata盘带宽占完了,进程A只能等待进程B暂时让出IO...

dongzhiyan_hjp 1910

基于集成运放心电放大器设计(原创)

原创作者:einyboy or alert 最近在看美剧《危机边缘》关于边缘科学的案件,科技控可以看一下,但建议不在吃东西的时候看。想像力是创造的思想源头,动手能力则是创造的车床。 自认为是没有想像力的那类,只能发挥动手能力了。 心电测量简介 图1 心电极接线图 如图1心电测试一般使用3个心电极进行测量,各个电极的说明如下: RA: Right Arm缩写,右手电极 LA: L...

huandaohack的专栏 6924

linux内核之块IO层

使用缓冲区头作为IO操作单元有两个弊端:缓冲区头是一个很大且不受控制的结构体(上面的是已经缩减过的),而且缓冲区头对数据的操作既不方便也不清晰,对内核来说,它更倾向操作页面(内存章节中讲到分配内存时按页分配),页面比缓冲区大,效率更高,同时更为简单;块是文件系统最小逻辑可寻址单元(物理磁盘的最小单位是扇区,但是内核执行的所有磁盘操作都是基于块来进行的),对于块单位的要求是:数倍于扇区,2的整数倍,并且要小于页面大小,所以通常块的大小为512、2k、4k。该调度程序就是最轻量级的调度,只提供指向合并的功能。

抱猫人的博客 804

Elasticsearch 8.17.1 JAVA工具类

整理了Elasticsearch8.17最新版的API工具类

weixin_39555954的博客 1125

SQLite学习——Dapper初识

dapper下载:https://www.nuget.org/packages/Dapper/1.40.0

jiDxiaohuo的博客 1296

linux内核分析笔记----块i/o层,《Linux内核设计与实现》——块I/O层

一、概论1、系统中能够随机(不需要按顺序)访问固定大小数据片的硬件设备称作块设备,这些固定大小的数据片就称作快。2、如果一个硬件设备是以字符流的方式被访问的话,那就应该将它归于字符设备;相反吗如果一个设备是随机访问,那么它就属于块设备。3、内存管理快设备要比管理字符设备细致得多,需要考虑的问题和完成的工作相对于字符设备来说要复杂得多。二、剖析一个块设备1、块设备中最小的可寻址单元是扇区。扇区大小一...

weixin_30768979的博客 277

MDK开发篇:基于立创逻辑派FPGA-G1与Cortex-M1软核的按键控制LED实战

本文详细介绍了基于立创逻辑派FPGA-G1开发板与高云Cortex-M1软核的完整开发流程。通过Gowin云源软件配置软核系统与GPIO外设,并在Keil MDK环境中编写按键控制LED的C程序,最终实现程序固化与上电自启动。教程涵盖硬件配置、软件开发、在线调试与固化部署全步骤,帮助STM32开发者快速上手FPGA软核开发。

weixin_42103128的博客 147

Linux I/O编程:I/O多路复用与异步 I/O对比

本文将简要介绍 Linux 中的多路复用 I/O 和异步 I/O 模型,并编写示例代码简述。对于网络 I/O,特别是 UDP 和 TCP,多路复用 I/O(如 `select`、`epoll()`)通常是更好的选择。而异步 I/O(如 `libaio`)只建议用在文件和块设备的 I/O 操作。

Where there is life, there is hope. 1446

Unity UGUI深度优化

Unity UGUI优化相关

不定时分享所学所得,包括游戏开发和其他收获! 2717

uni-app - 修改默认端口,H5 项目控制台运行出来的 IP 地址的默认端口号(H5 项目运行后控制台,修改项目运行到内置浏览器默认 8080 端口号)

uni-app运行到H5修改默认端口号,uni-app如何修改默认端口,uni-app修改默认端口,uni-app本地运行修改调试已上线微信H5项目,请问在UNIAPP的H5运行调试时候的IP是否可以自己设置固定,uni-app开发环境,如何设置h5服务器的端口,uni-app如何修改默认端,uni-app修改默认端口,uni-app指定端口号,uni-app-修改H5项目控制台运行出来的IP地址的默认端口号(H5项目运行后控制台,修改项目运行到内置浏览器默认8080端口号)

🏆 前端领域优质创作者 9887

Linux系统——I/O模型

I/O模型(Input,Output)同步异步、阻塞非阻塞

一坨小橙子的博客 1878

虚拟电厂功率预测最佳实践白皮书

虚拟电厂(VPP)通过聚合分散的可再生能源资源,为电网提供可观测、可调度和可交易的解决方案。本文提出了一套功率预测方法论,并给出LSTM实现脚本,涵盖资源接入、数据治理、预测模型设计及市场交易闭环。针对风-光-储-负荷混合场景,该方法论强调轻量化部署和滚动优化,可有效提升预测精度和调度收益。未来研究将融合深度气象预报和强化学习,进一步优化VPP的协同调度能力。

专注AI大模型,软件混淆,授权 377

Linux的缓存I/O和无缓存IO

现在我们在用户层建立另一个缓存区(用户层缓存区或者叫流缓存),假设流缓存的长度是50字节,我们用标准C库函数的fwrite()将数据写入到这个流缓存区里面,流缓存区满50字节后在进入内核缓存区,此时再调用系统函数write()将数据写入到文件(实质是磁盘)上标准IO操作fwrite()最后还是要掉用无缓存IO操作write,这里进行了两次调用fwrite()写100字节也就是进行两次系统调用write()函数。linux对IO文件的操作分为不带缓存的IO操作和带缓存的IO操作(标准IO操作)。

sinat_31608641的博客 1231

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Linux 磁盘I/O的三种方式对比:标准I/O、直接 I/O、mmap

1.引入 让我们先看一下Linux系统下IO结构模型 从图中可以看到标准 I/O、mmap、直接 I/O 这三种 I/O 方式在流程上的差异 1.1 标准I/O 大多数文件系统的默认I/O操作都是标准I/O。在Linux的缓存I/O机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址空间。 读操作:操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么...

Yu's Notes 2214

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Linux 内核中的文件系统优化:从挂载到 I/O 调度

Linux 内核中的文件系统优化是提高系统 I/O 性能的关键之一,它涉及到文件系统的选择、挂载参数、I/O 调度等多个方面。文件系统优化的设计思路与企业管理中的数据管理有着密切的联系,它通过资源优化、性能优化、成本控制和可靠性等机制,为系统的高效运行提供了保障。工作也要流程化,文件系统优化就像是系统中的数据管理工具,它确保了数据的高效存储和访问。在实际应用中,我们需要选择合适的文件系统,优化挂载参数,选择合适的 I/O 调度器,监控文件系统状态,以实现系统的最佳 I/O 性能。

jiang_style的博客 4116

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Linux network I/O

对于传统的操作系统来说,普通的 I/O 操作一般会被内核缓存,这种 I/O 被称作缓存 I/O。缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。

cjluxuwei的专栏 2785

《LKD3粗读笔记》(14)块I/O层

完全公正的排队I/O调度程序(空操作的I/O调度程序(最终期限I/O调度程序(预测I/O调度程序(

嵌入式点灯砖家的博客 590

Linux 内核源码分析---I/O 体系结构与访问设备

学习记录

学习记录 1845
上一篇: linux内核分析笔记----虚拟文件系统(下)
下一篇: linux内核分析笔记----进程地址空间
wustdatamining
博客等级 码龄15年 12粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值