LWN:我希望看到的关于readahead的文档!

Linux文件系统预读(一) 本博客主要阐述最新内核(linux-3.12)的文件系统预读及时的设计和实现,可能有理解不全面的地方,望各位能多多指教。 所谓的预读,值的是文件系统为应用程序一次读出比预期更多的文件内容,当然,这个细节对应用程序透明,应用程序可能的感觉唯一就是下次读的速度会更快,当然这是好事。 同步预读         让我们设想这样一种情境:进程P打开文件f,读offset从0开始size 阅读详情

关注了就能看到更多这么棒的文章哦~

Readahead: the documentation I wanted to read

April 8, 2022
This article was contributed by Neil Brown
DeepL assisted translation
https://lwn.net/Articles/888715/

Linux 内核中的 readahead 代码从名字就可以看出是负责把那些尚未明确请求的数据从存储设备中读出来,原因是认为它很可能很快就会需要用到了。该代码是稳定的、功能正常、在广泛使用的、没有争议的,所以我们有理由认为该代码应该是质量很高的,而且基本上是这样。最近,我发现需要给这段代码写一些文档,来进一步完善它。这项工作还揭示了一些功能上的小问题以及命名上的大问题。

我想要添加文档的具体原因可能会影响到我对这段代码的看法,所以我就先介绍一下这个原因吧。很久以前,Linux 在 I/O path 上有一个强烈的 "congestion" 的概念。如果对某些设备的请求队列增长得太大了,那么相应的设备就会被标记为 "congested (拥堵状态)",此时某些不那么必要的 I/O 请求将会被跳过或延后执行,具体来说就是 writeback 以及 readahead。随着时间的推移,拥塞管理的需求也(显然)越来越大。也许这是因为许多 I/O 设备现在都比我们的 CPU 更加快了,但是,不管是什么原因,block layer 不再跟踪这些拥堵状态了,只有一些虚拟的 "底层设备" 在继续这种过时的做法。

在 Linux 5.16 中,唯一被标记为 "read congested" 的设备就是用于 FUSE 文件系统的虚拟设备。我在进行消除所有拥塞跟踪残余的工作,因此我提议 FUSE 真的没有什么特别之处,它应该像其他人一样接受所有的 readahead 请求。Miklos Szeredi,FUSE 的维护者,认为我的理由不令人满意,我们不可能说他是不对的。如果 FUSE 不想要 readahead request,它就不应该接受这些请求。试图理解 FUSE 如何能够安全地对 readahead 说 "不",而不必在公共代码中维护这些拥塞跟踪功能,这使我开始了去阅读理解 readahead 的工作,一直看到我能明白这不是简单地将 FUSE 中的 "readahead" 回调修改为返回 0 为止。

mm/readahead.c 导出的 API 的主要部分是两个函数:page_cache_sync_ra()和 page_cache_async_ra()。这个功能也有两个稍微简单一些的接口 page_cache_sync_readahead()和 page_cache_async_readahead(),它们在内核文档中都有很好的说明。

Sync and async

不幸的是,该文档没有明确说明名称中的 "sync "或 "async "是为什么。弄清楚这一点是我的首要任务之一,因此,我向各位读者推荐我的新文档,这是针对 5.18 release 而合并的。它一开始是这么写的:

Readahead 用于在应用程序明确请求数据之前就将内容读入 page cache。Readahead 只尝试读取那些尚未在 page cache 中的 page。如果一个 page 存在但内容已经过期了(not up-to-date),readahead 也不会尝试去读取它。在这种情况下,将会直接调用 ->readpage()。

当应用程序的读取请求(无论是系统调用还是 page fault)发现所请求的 page 不在 page cache 中,或者它在 page cache 中并且设置了 PG_readahead 标志时,Readahead 就会被触发。这个 flag 表明,该 page 是作为前一个 readahead 请求的一部分加载的,现在它已经被访问了,是时候进行下一个 readahead 了。

每个 readahead request 都是部分是同步读取(synchronous read),部分是异步 readahead。

我们在这里先停一下,集中讨论一下这两个术语:同步和异步(sync and async)。Readahead 本质上就是异步的,没有什么东西在等待它完成。相反,一个明确请求的 read 操作,最终肯定是同步的(synchronous),因为在数据到达之前,操作是无法完成的(complete)。这两种模式显然是相关的,应该在同一代码中处理它们。把它们都描述为 "readahead" (这实际上是代码里面强加给我的说法)就不那么合适了。

任何一个熟悉计算机的人,知道一个 "kilobyte" 并不一定就是 1000 个字节,他们同样会知道,我们技术人员经常遵循 Lewis Carroll 在《透过玻璃看世界(Through the Looking Glass)》中的 "胖墩(Humpty Dumpty)" 的做法:

"当我使用一个单词时,"Humpty Dumpty 用相当轻蔑的语气说,"它表达的意思只是我所选择的那个意思,不多也不少。"

我们似乎更多地犯了这个错误,而 readahead 代码当然也不是无辜的。

每个文件系统都可以提供一个 address_space_operations 方法,名为 readahead(),用于开始进行 read。正是基于此,文档中使用了 "readahead request" 这一术语。还有一个名为 readpages() 的地址空间操作(address-space operation),尽管它在 2020 年中期被标记为废弃,并将在 5.18 中被删除了。这两个函数的功能基本相同(它们都对一组 page 发出 read 请求)。较新的 readahead() 接口更加好一些(这个细节超出了本文的范围),但 readpages()无疑有一个更好的名字,因为这就是它们都在做的事情。它们不仅仅是 "read ahead (提前读取)",而且还发出明确要求的 read 操作。

一旦人们意识到 readahead() 的功能只是提交 read 请求,其中一些调用者会等待("sync"),另一些调用者不会等待("async"),那么代码的意图就开始变得更加清晰。因此名字确实很重要。

When readahead can be skipped

回到最初的问题,也就是如何让 FUSE 有机会跳过 readahead,目前就可以看到有一条可行道路了。FUSE 提供的 readahead() 函数必须读取所有在等待读取的 page,但它不需要读取多余的 page。随着引入 readahead() 操作,这里对接口的改进之一是,文件系统可以获得更多的信息了。这些信息包括一个 struct file_ra_state,它包含一个叫做 async_size 的字段。啊哈! 这一定是 readahead 部分的大小。

真的是这样吗?我们能相信这个名字吗?幸运的是,这个 structure 是有文档的,其中 async_size 字段的描述是这样的:"当剩下这么多 page 时开始下一个 readahead"。这是什么意思,它与 "async" 有什么关系?可能多读一些新的文档会有帮助:

每个 readahead request 都部分是同步读取,部分是异步 readahead。这反映在 file_ra_state 结构中,其中的 ->size 成员是总 page 数,而 ->async_size 是异步部分的 page 数。这个异步部分的第一个 page 将设置 PG_readahead 来触发后续 readahead。一旦进行了一系列的连续读取,应该就不需要同步部分了,所有的 readahead 请求都会是完全异步的。

第二句话介绍了 async_size 的含义,是我总结的–以前从来没有出现在任何文档中,而且与代码不完全一致,尽管它与字段名完全对得上。第三句话是关于 PG_readahead 标志的,这与代码和以前的文档相符。

readahead 的一个核心思想是冒一点风险来读取比请求的数据更多的内容。如果这个风险带来了回报,并且这些额外的数据被访问到了,那么这就证明我们值得进一步冒风险来读取更多尚未被请求的数据。当对一个文件进行一次连续读取(sequential read)时,过去的行为细节可以很容易地存储在 struct file_ra_state 中。然而,如果一个应用程序从文件的两个、三个或更多的部分读取,并且这些顺序读取是交错进行的,那么 file_ra_state 就不能跟踪到所有这些状态了。相反,我们依靠已经在 page cache 中的内容。具体来说,我们有一个 flag,PG_readahead,它可以在一个 page 上设置上。这个名字应该用过去式来读:该 page 已经被提前读取过了。在读取该 page 时,我们曾经是冒了风险的,所以,如果这个风险得到了回报,也就是该 page 被访问了,那么就有理由再冒一次险,来多读一些。

这个 flag 应该设置在哪一个 page?readahead 的另一个核心前提是,阅读通常是有顺序的,只有在这个基础上,我们才会冒风险去读取接下来的 page。因此,如果 readahead 的第一个 page 被访问了,那么可以假设是顺序读取(sequential read)。如果后面跳过一些位置的 page 被读取,就不一定足以下结论了。在我看来,PG_readahead 必须被设置在第一个会被投机性地请求的 page 上。这与文档中根据 async_size 的值来设置它的行为是一致的,也与大部分代码一致,尽管有几个地方使用了一些不同的值,但没有给出明确的理由。

那么,这足以让 FUSE 在其 readahead() 处理程序中选择何时跳过 page 了——它根据 async_size 值来判断——但对于采取完全正确的行为来说还不够。当 readahead() 被调用时,这些内存 page 已经被添加到 page cache 中,尽管它们还没有被标记为是最新内容。把它们留在那里而不启动 read,会导致以后试图读取它们时降低效率。如果 readahead()函数选择忽略这些 page,并通过不更新 readahead_control 结构中的一些(private)字段来表明这一点,那么可以通过让调用者从 page cache 中删除 page 来轻松解决。

Oddities

文档中还有一些内容,也有更多奇怪的地方,正是因为需要写文档才注意到的。所以,继续我们之前的话题:

当任何原因出发一次 readahead 时,需要确定三个数字:区域的 start,size,以及 async tail 的 size。

区域的 start 是指在被访问地址处或其之后的第一个 page 地址,这个地址目前还没有被填充到 page cache 中。这可以通过在 page cache 中直接搜索而找到。

async tail 的 size 是从最终确定的 request size 中减去明确请求的 size 来确定的,如果这个大小小于 0 那么就使用 0。注意,当区域的 start 不是正在被访问的 page 时,这种计算是错误的。

我经常把写文档的行为作为发现和 fix bug 的手段,如果准确的文档读起来开始感觉到很难受了,那么更容易的做法是先 fix 代码,这样可以使文档更加流畅。这次,我选择让文档变得拗口一点,部分原因是这里命名又是一个问题了,而我们知道,总是很难找到好名字的。

如前所述,readahead 代码有两个 API 函数,名字有些不太好:page_cache_sync_ra()和 page_cache_async_ra()。这两个函数是针对两个触发条件而调用的,一个是在试图访问某个没有在 cache 里的 page 时,另一个是在访问一个被标记为 PG_readahead 的 page 时。两者都可能会发出一些需要等待结果的读取(同步),以及一些暂时不需要等待结果的读取(非同步)。

这些函数中的每一个都有一个叫做 req_count 的参数,它就是最初 request 中的 page count。其含义是说,我们至少需要这么多页,但如果有条件的话可以多读一些。正是由于 req_count 的含义和使用,才有了上面那一节文档中的干脆地了结。

将 req_count 解释为 "size of the initial request (初始请求的大小)" 是跟名称很相符的,但这并没有明确表明,这就是传递进来的数字。正如我们所见,readahead 代码中的逻辑主要是猜测未来可能需要多少数据。这些函数的一些调用者已经知道正在进行顺序读取,例如使用了 madvise() 系统调用来告知了应用程序的后续意图。在这些情况下,req_count 被设置为一个恰当的较大数字。这并不完全是现在需要的 page 数量,但它是已知想要的 page 数,所以这些 page 是文件系统不应该跳过的,只是因为现在读取它们不方便。

在注意到 request 可能包括明确要求的一些未来才需要的 page 的情况下,req_count 的意思就相当清楚了,但它是如何使用的?在深入探讨这个问题之前,多读一下新的文档,了解一下 readahead 请求的大小是如何计算的,会有帮助:

区域的 size 通常是由之前加载前面的 page 的 readahead 的 size 来决定的。这可以从简单的顺序读取的结构 file_ra_state 中找到,或者从检查多个交错进行的顺序读取的 page cache 状态中发现。具体来说:如果 readahead 是由 PG_readahead 标志触发的,那么前一个 readahead 的 size 被假定为从触发的 page 到下一次 readahead 开始的 page 数量。在这些情况下,前一个 readahead 的 size 会被放大,通常会是翻倍,用来进行新的 readahead,当然详细情况见 get_next_ra_size()的实现。

在 page_cache_sync_ra()的情况下,它是在一个想要的 page 缺失时会被调用的,我们期望 req_count 至少是 1,事实上就是这样。这里会分配一些 page,这取决于 page cache 中有多大的空洞,request 有多大,以及进行多少 readahead 才是合理的。这些 page 被添加到 page cache 中,文件系统的 readahead() 函数就被调用来加载这些 page。

当 page_cache_async_ra() 是因为发现了一个 PG_readahead 标记的 page 而被调用时,情况就不同了。将被读取的这些 page 就不会包括刚刚发现的 page(它已经被 read 了),可能也不包括一些后续 page。代码将在 page cache 中搜索第一个缺失的 page,并考虑从那里开始读取。这些 page 中,有多少会在最初 request 所需的 page 之中?也许是有一些,但肯定不是 req_count 那么多的。

最后一个关于 req_count 和实际读取的 page 之间关系的说法是基于假设的,正如我偶尔会重复说的,这些假设并不总是与代码完全一致。为了确定这一点,我们需要回到代码中,看看在 page_cache_async_ra()的情况下,req_count 究竟是如何使用的。幸运的是,我们在 Git 中拥有多年的开发历史,某些 patch 中带有的文档说明往往比在代码中找到的文档更好。

req_count through the ages

在 Linux 2.6.31 之前,req_count(当时叫 req_size)根本不用于 PG_readahead 所触发的 read。该版本改动开始,它被用来增加 readahead 的 size。以前,它的计算方式是前一个 readahead 的 size,放大 2 或 4 倍。从那时起,它改为前一个 ahead read 的 size 加上 req_count,然后再按比例放大。这一改动的理由是:

确保交错的 readahead size 大于 request size。这也使得 readahead 窗口增长得更快。

不幸的是,没有解释什么样的 workload 会从这种改动中受益。在我看来,使用 req_count 并不是因为它是某种基于理论分析的正确数字,而是因为它是一个容易获得的、看起来合适的 size。因此,这并没有提供多少关于 req_count 应该是什么意思的解释。

然后,在 Linux 4.10 中,req_count 出现了一个新的用途。那个 patch 允许在 readahead 过程中请求的 page 数量至少是原始请求的 size,即使它大于配置的最大 readahead size(只要它不大于设备最大的接受能力就行)。这是一个明确的确认,"readahead" 的一部分实际上是一个同步读取,不受 readahead 限制的约束。它还强调了 req_count 并不简单地是一个 size(也会用于放大),而是确定了一组特定的 page —— 从 request 的起始点开始。因此,当 readahead 的起始点向前移动,越过已经在 page cache 中的任何 page 时,req_count 确实减去那些应该被跳过的 page 数量来变小。只有这样,它才能强调作为原始请求一部分的 page 数量,这些页面仍然需要被读取,这也是超过最大 readahead 大小的理由。

从纯粹的行为学角度来看,这个参数的含义不明确可能并不那么重要。readahead size 的计算是启发式的,没有标准答案,如果误打误撞地加入了几个额外的模糊因素,那么只是得到另一个启发式方法而已。但是从想要理解代码的角度来看,特别是想要在不破坏任何东西的情况下来修改代码,这些细节可能就是相当重要的了。

如前所述,我想让文件系统知道有多少 page 是明确 request 的,有多少是启发式建议的。这需要清楚地了解 req_count 的含义。得到稍微不正确的数据可能不会有很大的损害,但肯定没有什么好处。

The rest of the story

现在我们可以阅读文档的其余部分了,希望它能整合一些已经探讨过的想法。由于它针对的是那些已经普遍熟悉 Linux page cache 的人,因此它包含了一些概念,如 page locking 等,普通读者最好直接跳过这些内容:

如果不能确定前次 read 的 size,则使用 page cache 中它前面的 page 数量来估计上一次 read 的 size。这种估计很容易被随机读取的相邻内容所误导,所以它一般是被忽略掉的,除非它比当前的 request 要大,而且也没有被放大过,除非它在文件的开头。

一般来说,readahead 在文件的最开头就用来加速了,因为从那里开始的读取通常都是连续进行的。各种特殊情况下对 readahead 的 size 还有一些小调整,这些最好通过阅读代码来了解。

上述计算,基于之前的 readahead size,决定了这次 readahead 操作的 size,可能加上了一些请求的 read size。

readahead request 是使用 ->readahead() 这个地址空间操作来发送到文件系统的,mpage_readahead() 就是一个典型的实现。->readahead() 通常应启动对所有 page 的读取,但可能无法在不引起 I/O error 的情况下读取任何一个或所有 page。page cache 读取代码将为任何 ->readahead() 没有提供的页面发出 ->readpage()请求,只有这个请求也报错,才算是最终结果。

->readahead() 一般会重复调用 readahead_page(),从那些为 readahead 准备的 page 中获取每一个 page。它可能会因为以下原因而无法读取一个 page:

  • 调用 readahead_page()的次数不够多,从而导致忽略了一些 page,这在存储路径拥塞的情况下可能是合理的。

  • 可能由于资源不足,未能实际提交对某一特定 page 的 read request,或者

  • 在后续的 request 处理过程中出现错误。

在后两种情况下,这个 page 应该被 unlock,来表明读取尝试已经失败。在第一种情况下,该 page 将由调用者来 unlock。

那些不在这个 request 的最终 async_size 中的 page 应该也被认为是重要内容,并且 ->readahead() 不应该因为拥塞或暂时资源不可用而失败,而是应该等待必要的资源(例如内存或 indexing 信息)可用再进行。在最终的 async_size 中的 page 可能被认为不是那么紧急的,对这些进行 read 时可以接受失败。在这种情况下,最好使用 delete_from_page_cache() 将这些 page 从 page cache 中删除,因为对于那些没有被 readahead_page() 获取的 page,会自动进行删除。这将允许后续的同步 readahead request 来再次尝试读取这些内容。如果它们被留在 page cache 中,那么它们将使用->readpage() 来单独读取。

写文档的目的是为了确保我理解这些代码,并确保其他人能够理解我对这些代码进行修改的动机。我想,它已经达到了这个目的。然而,它也为使代码和代码中使用的命名更加清晰提供了可能性。虽然我希望这样的改进能够发生,但我不确定我什么时候能找到时间。如果有人想推动这项工作,我会抽出时间来帮忙。

这个关于文档写作的元叙事(meta-narrative)的目的是与众不同的。我想强调保持代码的各种细节的连贯 "意图(intent)" 或 "意义(meaning)" 是很困难的,因为它在不同的时间被不同的人修改。意义可能会发生改变,出现越来越多不一致的地方,错误的名词可能会变得根深蒂固。作为一个社区,我们已经发现,最大限度地提高正确性和一致性的最好方法就是拥有能够提醒我们注意到问题的工具。在我们拥有能够阅读文档(包括变量名称含义这个隐含文档信息)并突出显示问题的工具之前,这是我们必须继续自己来完成的工作。

所以请:当你改变代码时,也要修改文档。如果还没有任何文档,那就写一些吧!

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

ba98f01989ea1a243d35df273aa23d70.png

Page Cache之Readahead   readahead即预读,提前从块设备(如硬盘)里多读一些page缓存到page cache tree,以便下次读时能直接从page cache中命中,而不需要触发实际块设备的访问,提高IO效率。  那么什么时候readahead,readahead多少个page呢?     调用系统调用read时,先find page cache,若cache miss则进行sync readahead;若... 阅读详情

相关推荐

linux那些事之page cache

page cache page cache又称高速缓存,主要是针对文件文件系统,为了减少不必要的磁盘IO操作(读/写)造成卡顿问题,内核将磁盘文件中的内容缓存到内存中,并选择适当时机对磁盘进行读写操作。 page cache在linux文件系统中占用重要地位。主要是由于CPU访问磁盘比从内存中读取要慢上百甚至上千倍;同时利用空间和时间局部性,当系统访问该文件中一定位置的内容之后,那么经常会很快访问附近位置,如果能提前将文件一部分内容缓存到内存中将会加快对文件操作效率。 he Linux kernel

weixin_42730667的博客 2428

Linux 读文件 - readahead预读算法

根据ondemand_readahead中initial_readahead label处逻辑看,ra->size是由get_init_ra_size函数计算,该函数第一个参数是应用read的数据页(每个数据页4K)的数量,该场景每次读取4K bytes,相当于调用get_init_ra_size(1,32)返回4。这里async readahead就是指generic_file_buffered_read函数中的:page_cache_async_readahead函数调用。: 开始预读的数据页索引,

GetnextWindow的专栏 1557

嵌入式开发避坑指南:手把手教你用STM32CubeMX配置W9825G6KH SDRAM(含时序参数详解)

本文详细介绍了如何使用STM32CubeMX配置W9825G6KH SDRAM,包括硬件连接检查、CubeMX初始化步骤、时序参数优化及稳定性问题排查。通过实测波形分析和案例分享,帮助开发者避免常见配置错误,提升嵌入式系统性能与稳定性。

weixin_42542669的博客 192

文件预读readahead内核优化提升文件读取性能

之前写过一篇文章《page cache之文件预读readahead内核源码详解》,主要讲解了内核vfs层文件预读内核源码。受内核block层io_uring异步机制的影响,觉得可以对内核预读机制优化,提升文件读取性能。 首先,我们需知晓,内核文件预读机制本身可以一定程度提升文件读取性能,这点在《page cache之文件预读readahead内核源码详解》中就提到过,我们这里再简单提下。比如,我们cat test读取文件,每次read系统调用只读取64K字节的文件数据: 第1次执行read系统调用,读

dongzhiyan_hjp 3302

保姆级教程:IAR for STM8 3.11版本安装与破解全流程(附资源包)

本文提供IAR for STM8 3.11版本的详细安装与破解教程,涵盖环境准备、主程序安装、许可配置及实战验证全流程。针对新手常见问题,如许可证报错、驱动安装失败等,给出了具体解决方案,帮助开发者快速搭建稳定的STM8开发环境。

study的专栏 945

物联网开发笔记(34)- 使用Micropython开发ESP32开发板之控制步进电机(28BYJ-48)

使用Micropython开发ESP32开发板之控制步进电机(28BYJ-48)

zhusongziye的博客 1万+

Linux readahead文件预读

​ Linux read/mmap 时将文件从磁盘读区到内存当中,read读取文件操作必然会带来IO如果能直接从内存当中读取文件这样就能有效的解决IO及延迟问题。page cache的诞生就是解决这个问题,文件读取后将文件对应的物理page 添加到redix tree当中管理后续在做同样的读取操作时就直接从page cache当中直接读取文件。这个机制本质上来讲与硬件架构的cache原理上是想通的,理解cache机制有助于理解page cache。

谨以此记录下自己的每一点、每一滴、每一步,以督促自己,不忘目标,不忘理想。 1530

【C语言】一文搞懂C语言文件操作

读写文件、文件相关库函数详解、文件缓冲区介绍

StackFrame 5655

Linux内核的文件预读

Linux文件预读算法磁盘I/O性能的发展远远滞后于CPU和内存,因而成为现代计算机系统的一个主 要瓶颈。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。本文作者是中国科学技术大学自动化系 的博士生,他在1998年开始学习Linux,为了优化服务器的性能,他开始尝试改进Linux kernel,并最终重写了内核的文件预读...

weixin_34054931的博客 538

Fluent验证案例03:管道中湍流流动压降计算——采用kw-sst模型计算压降更为准确。

阅读(4053) 评论(0)本案例利用Fluent计算管道中湍流流动压降。

qq_15963745的博客 874

【Java基础知识 19】Java接口的作用和意义

Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

学Java,找哪吒 2万+

Linux内核的文件预读readahead

nux的文件预读readahead,指Linux系统内核将指定文件的某区域预读进页缓存起来,便于接下来对该区域进行读取时,不会因缺页(page fault)而阻塞。因为从内存读取比从磁盘读取要快很多。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。 维基百科上关于readhead的介绍资料: readahead is a system call of the Linux kernel that loads a file's contents into

qq_42894864的博客 571

基于Simulink的H∞鲁棒控制器设计与仿真建模示例

本文介绍了基于Simulink的H∞鲁棒控制器设计与仿真方法。针对质量-弹簧-阻尼系统存在±50%刚度不确定性的问题,详细阐述了从构建广义被控对象、设计性能加权函数,到使用hinfsyn综合控制器的完整流程。通过Simulink仿真验证,所设计的H∞控制器在参数摄动和外部扰动下均保持良好性能,位移控制误差小于2%,扰动衰减超过20dB。相比传统PID控制,H∞方法展现出显著鲁棒性优势。文章还总结了工程实践中的加权函数调参技巧、控制器降阶方法,并展望了μ-综合等扩展方向,为处理系统不确定性提供了实用解决方案。

amy_mhd的博客 70

深入解析Linux IO调用链与性能优化

IO操作是Linux系统编程的核心基础,涉及从用户空间到内核的多层调用链。理解C标准库缓冲区、系统调用接口和内核页缓存的工作原理,对于优化IO密集型应用至关重要。通过分析文件流缓冲策略、VFS抽象层和块设备调度机制,开发者可以掌握减少系统调用开销、提升数据吞吐量的关键技术。在实际场景中,合理选择mmap内存映射、AIO异步IO或O_DIRECT直接IO等方案,能够显著提升数据库、大数据处理等应用的性能表现。本文结合Linux内核参数调优和SSD特别优化等实践技巧,为系统级软件开发提供全面的IO性能优化指南。

weixin_34111790的博客 457

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

block多队列分析 - 3. 读文件过程

目录1. 前言1.通过文件系统读取nullb上的文件 1. 前言 本专题文章是对多队列部分学习的笔记。主要以null_dev为例来研究多队列的工作机制, 为了能够凸显多队列的工作流程,只对block层做重点分析说明,对其它代码只做注释性说明。本文主要通过分析文件系统(ext4为例)读取null blk的流程,来理解多队列的读取流程。 kernel版本:5.10 平台:arm64 注: 为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“ 1.通过

HZero 2011

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

文件读取的底层实现——generic_read_iter分析

本文分析了Linux 6.x内核中文件读取和预读机制的实现变化。相比Linux 4.x使用复合页,6.x改用folio结构。在文件系统层,传统的.read/.write方法已被.read_iter/.write_iter取代,如ext2文件系统的ext2_file_read_iter底层调用generic_file_read_iter。文件读取的核心流程是:通过filemap_get_pages获取数据页到fbatch,再通过copy_folio_to_iter将数据拷贝到用户空间。预读机制最终都调用ond

Aruko的博客 1610

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

文件系统和裸块设备的page cache问题

原文地址:http://www.wowotech.net/filesystem/439.html 作者:阿克曼 注:本文代码基于linux-3.18.31,此版本中块缓存已经合入页缓存(两个缓存合并的意思是:这里)。 普通文件的address space 文件系统读取文件一般会使用do_generic_file_read(),mapping指向普通文件的address space。如果一个...

去级得骨灰 1066

文件系统概述

术语 文件系统:一种把数据组织成文件和目录的存储方式,提供基于文件的存取接口,通过文件权限控制访问。另外还包括一些表示设备、套接字和管道的特殊文件类型,以及包含文件访问时间戳的元数据 文件系统缓存:主存(通常是DRAM)的一块区域,用来缓存文件系统的内容,可能包含各种数据和元数据 操作: 对文件系统的请求,主要包括read()、write()、open()、close()、stat()、mkdir()及其他操作 I/O:文件系统I/O有多种定义,此处仅指直接读写(执行I/O)的操作,包括read()、wr

9线艺术家的博客 1203

文件的预读

为了优化读取文件的时间延迟,文件系统(FS)在去磁盘读取文件时会有一个read_ahead的动作。主要思路是:当FS发现用户读取文件是按照文件的顺序读取,FS就假定用户在下一次读取时大概率会读取下一个block。所以FS在把当前的block读取到内存后,会发送读取下一个block的命令,然后将当前block数据返回给用户。这样用户在处理数据的时候,磁盘IO也在并行的执行(如果是DMA的方式,磁盘IO在完成之后,会通过中断的方式告诉FS)

qq_41104683的博客 534

page cache之文件预读readahead内核源码详解

提起linux内核的文件预读机制,很多小伙伴肯定是听说过的,为什么预读机制可以提高性能?怎么让初学者快速理解预读机制呢?实践下来觉得还是用示意图举例最简单。本文首先根据实际读取文件的测试数据,用示意图讲解讲解预读机制,然后讲解相关内核源码。内核源码基于3.10.96,详细源码注释见https://github.com/dongzhiyan-stack/kernel-code-comment。 1 文件预读示意图讲解 测试命令很简单cat test >/dev/null,test文件之前没有...

dongzhiyan_hjp 3519

Linux内核File cache机制(上篇)

一、什么是File cache?1. File cache概述Linux File cache机制,每次动笔想写到该知识点的时候,我心里总会犹豫迟疑,众所周知内存管理是Linux系统的...

内核工匠 5618

Linux read系统调用之 page_cache_sync_readahead()

1 page_cache_sync_readahead() 上篇文章说道在 do_generic_file_read() 函数中 label find_page 中调用 page_cache_sync_readahead() 启动同步预读。 void page_cache_sync_readahead(struct address_space *mapping, struct ...

嘉明的博客 2100

ext2文件系统inode.c分析(一)

2021SC@SDUSC static int __ext2_write_inode(struct inode *inode, int do_sync); ext2_inode_is_fast_symlink检测一个inode是不是一个快速符号链接。快速符号链接是一个ext2文件系统的特性,要求符号链接指向的文件名是一个短的路径名,小于等于60字节,就把它的路径名放在一个inode里,而不用通过一个数据块来进行转换 static inline int ext2_i...

weixin_45742312的博客 1772

linux文件读取中的Readahead预读机制

Readahead预读机制 由于内存的速度比磁盘速度快很多,如果每一次访问文件数据都要从磁盘读取一次数据,就会导致非常严重的时延。因此Linux为了提高性能,通过page cache机制,将多个用户数据缓存在内存当中,从而避免多次再磁盘读取。Readahead预读机制正是将用户数据缓存到内存的方法之一。 Readahead机制的介绍 Readahead预读机制是Linux针对顺序读的性能优化机制。它的核心思想是当用户访问连续多个page的时候,一次性将多个连续的页从磁盘读取到内存中,从而避免多次与磁盘

jinking01的专栏 7440

Linux内核的文件预读值的修改,Linux内核的文件预读readahead

Linux的文件预读readahead,指Linux系统内核将指定文件的某区域预读进页缓存起来,便于接下来对该区域进行读取时,不会因缺页(pagefault)而阻塞。因为从内存读取比从磁盘读取要快很多。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。维基百科上关于readhead的介绍资料:readaheadis a system call o...

weixin_31738297的博客 645
上一篇: LWN: KVM guest 里的私有内存!
下一篇: LWN: trusted_for() 没能被合并!
LinuxNews搬运工
博客等级 码龄7年 438粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值