gpt4 book ai didi

windows - 小读(重叠,缓冲)的性能优于大连续读的解释?

转载 作者:行者123 更新时间:2023-12-01 23:00:06 25 4
gpt4 key购买 nike

(对于冗长的介绍,我们深表歉意)

在开发将整个大文件(> 400MB)预先故障转移到缓冲区高速缓存中以加快以后的实际运行速度的应用程序的开发过程中,我测试了一次读取4MB是否比一次仅读取1MB块还有明显的好处。令人惊讶的是,较小的请求实际上却更快。这似乎违反直觉,所以我进行了更广泛的测试。

在运行测试之前清除了缓冲区高速缓存(为笑起见,我也对缓冲区中的文件进行了一次运行。无论请求大小如何,缓冲区高速缓存均可提供高达2GB/s的速度,尽管令人惊讶地+/- 30%随机方差)。
使用的所有读取与具有相同目标缓冲区的ReadFile重叠(句柄使用FILE_FLAG_OVERLAPPED和不使用FILE_FLAG_NO_BUFFERING打开)。使用的硬盘有些陈旧,但是功能齐全,NTFS的群集大小为8kB。初始运行后对磁盘进行了碎片整理(6个碎片与未碎片化,零差)。为了获得更好的数字,我也使用了一个较大的文件,以下数字表示读取1GB。

结果确实令人惊讶:

4MB x 256    : 5ms per request,    completion 25.8s @ ~40 MB/s
1MB x 1024 : 11.7ms per request, completion 23.3s @ ~43 MB/s
32kB x 32768 : 12.6ms per request, completion 15.5s @ ~66 MB/s
16kB x 65536 : 12.8ms per request, completion 13.5s @ ~75 MB/s

因此,这表明提交两个长度为两个簇的一万个请求实际上比提交几百个大的连续读取要好。提交时间(ReadFile返回之前的时间)确实随着请求数量的增加而大大增加,但是异步完成时间几乎减少了一半。
每种情况下,在异步读取完成时,内核CPU时间大约为5-6%(在四核上,所以应该说20-30%),这是令人惊讶的CPU数量-显然,操作系统会执行一些非忙碌的等待也可忽略不计。 30%的CPU在2.6 GHz下运行25秒,这是“无所事事”的相当多的周期。

知道如何解释吗?也许有人在这里对Windows重叠IO的内部工作有更深入的了解?或者,可以使用ReadFile读取兆字节数据的想法有什么本质上的错误吗?

我可以看到IO调度程序如何通过最小化寻道来优化多个请求,尤其是当请求是随机访问时(不是)。我还可以看到在NCQ中有一些请求,硬盘将如何执行类似的优化。
但是,我们谈论的是可笑的小请求的数量可笑的-然而,这些请求的性能要比看起来合理的高2倍。

旁注:明显的赢家是内存映射。我几乎倾向于添加“毫不奇怪”,因为我是内存映射的忠实拥护者,但是在这种情况下,这确实让我感到惊讶,因为“请求”更小,并且操作系统应该甚至无法预测和安排IO。我最初没有测试内存映射,因为它似乎甚至可以远程竞争,这似乎是违反直觉的。非常适合您的直觉,呵呵。

以不同的偏移量重复映射/取消映射 View 实际上需要零时间。使用一个16MB的 View 并通过一个简单的for()循环对每个页面进行故障读取,每页读取一个字节将以9.2秒的速度(〜111 MB/s)完成。 CPU使用率始终低于3%(一个内核)。同一台计算机,同一张磁盘,所有内容都相同。

似乎Windows一次将8个页面加载到缓冲区缓存中,尽管实际上只创建了一个页面。每第8页故障以相同的速度运行,并从磁盘加载相同数量的数据,但显示的“物理内存”和“系统缓存”指标较低,并且只有1/8的页故障。随后的读取证明了这些页面仍然明确地位于缓冲区高速缓存中(没有延迟,没有磁盘 Activity )。

(可能与 Memory-Mapped File is Faster on Huge Sequential Read?非常非常远地相关)

为了使其更具说明性:

更新:

使用 FILE_FLAG_SEQUENTIAL_SCAN似乎可以“平衡” 128k的读取,从而将性能提高100%。另一方面,它严重影响了512k和256k的读取(您必须知道为什么吗?),而对其他任何内容都没有实际影响。较小块大小的MB/s图可以说看起来更“均匀”,但运行时间没有差异。

我可能已经找到了一种解释,也可以解释较小块的性能更好。如您所知,如果操作系统可以立即(即从缓冲区中)(并且由于各种特定于版本的技术限制)可以立即处理请求,则异步请求可以同步运行。

当考虑实际的异步与“立即”异步读取时,可能会注意到256k以上的Windows异步运行每个异步请求。块大小越小,即使无法立即使用(即ReadFile只是简单地同步运行),也会“立即”处理更多请求。我无法确定清楚的模式(例如“前100个请求”或“超过1000个请求”),但是请求大小和同步性之间似乎存在反相关关系。块大小为8k时,每个异步请求均被同步处理。
出于某种原因,缓冲的同步传输速度是异步传输的两倍(不知道为什么),因此,请求大小越小,整体传输速度就越快,因为更多的传输是同步完成的。

对于内存映射的预故障,FILE_FLAG_SEQUENTIAL_SCAN会导致性能图的形状略有不同(存在一个“凹口”,该凹口向后移一点),但是所用的总时间完全相同(再次,这令人惊讶,但是我不能帮助它)。

更新2:

无缓冲的IO使1M,4M和512k请求测试用例的性能图更高一些,并且“尖峰”,最大值为90s GB/s,但是最小值也很苛刻,因此1GB的总体运行时间在+/- 0.5以内s的缓冲运行时间(具有较小缓冲区大小的请求完成速度明显加快,但是,这是因为在处理2558个以上的请求时,将返回ERROR_WORKING_SET_QUOTA)。在所有无缓冲的情况下,测得的CPU使用情况均为零,这并不奇怪,因为发生的任何IO都通过DMA运行。
FILE_FLAG_NO_BUFFERING的另一个非常有趣的发现是,它极大地改变了API的行为。 CancelIO不再起作用,至少在取消IO方面无效。对于未缓冲的进行中请求, CancelIO将仅阻塞直到所有请求完成为止。律师可能会辩称,该功能不承担疏忽职责的责任,因为它返回时不再有运行中的请求,因此以某种方式完成了所要求的工作,但是我对“取消”的理解有所不同。
有了缓冲的,重叠的IO, CancelIO可以轻松解决问题,所有进行中的操作都会立即终止,正如人们所期望的那样。

另一个有趣的事情是,在所有请求完成或失败之前,该过程不可终止。如果操作系统在该地址空间中进行DMA,这种方式是有意义的,但是它仍然是一个令人惊叹的“功能”。

最佳答案

我不是文件系统专家,但是我认为这里发生了一些事情。首先。 w.r.t.您对内存映射获胜的评论。这并不完全令人惊讶,因为NT缓存管理器基于内存映射-通过自己进行内存映射,您可以在没有其他内存副本的情况下复制缓存管理器的行为。

当您从文件中顺序读取时,缓存管理器会尝试为您预取数据-因此您很可能在缓存管理器中看到预读的效果。在某些时候,缓存管理器停止预取读取(或者在某个时候,预取的数据不足以满足您的读取,因此缓存管理器必须停止)。这可能是造成您看到的较大I/O速度下降的原因。

您是否尝试过将FILE_FLAG_SEQUENTIAL_SCAN添加到CreateFile标志中?这指示预取器更加激进。

这可能是违反直觉的,但传统上从磁盘读取数据的最快方法是使用异步I/O和FILE_FLAG_NO_BUFFERING。当您这样做时,I/O将从磁盘驱动器直接进入您的I/O缓冲区,而不会造成任何阻碍(假设文件的各段是连续的-如果不是,则文件系统必须发出几次磁盘读取以满足应用程序读取请求)。当然,这也意味着您将失去内置的预取逻辑,必须自己动手。但是使用FILE_FLAG_NO_BUFFERING,您可以完全控制I/O管道。

要记住的另一件事:当您执行异步I/O时,确保始终有一个I/O请求非常重要-否则,您将失去最后一个I/O完成与下一个I/O之间的时间。开始。

关于windows - 小读(重叠,缓冲)的性能优于大连续读的解释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5909345/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com