使用mmap时查找缓存未命中

时间:2014-07-01 13:39:38

标签: python linux mmap

我需要在相当大的文件中执行搜索。搜索操作需要随机访问(考虑二进制搜索),我将mmap文件以便于使用和性能。搜索算法会考虑页面大小,因此每当我需要访问某些内存区域时,我都会尝试充分利用它。因此,有几个参数需要调整。我想找到能够从块设备中获得最少读取次数的参数

我可以用笔和纸做到这一点,但理论工作只能到目前为止。发生很多事情和不同页面缓存的实际环境更复杂。有几个进程访问文件,由于文件上的其他活动,某些页面通常可以在文件系统页面缓存中使用。 (我假设在使用mmap时操作系统会注意到这些。)

为了根据从块设备读取的块数来查看搜索算法的实际性能,我需要知道在mmap访问期间发生的页面未命中数。

梦想真实的解决方案是告诉我内存区域的哪些页面已经在缓存中。一个非常好的解决方案是一个函数,它告诉我一个给定的页面是否在真实的内存中。这将使我能够调整参数,甚至可能成为我的算法的一部分(“如果这个页面在实际内存中,我们将从中提取一些信息,如果不是,那么我们将读取另一个页面” )。

系统将在Linux(3系列内核)上运行,因此如果没有与操作系统无关的答案,则可以接受特定于Linux的答案。基准测试将用python编写,但如果接口只存在于C中,那么我将继续使用它。

示例

让我们有一个具有固定记录长度记录的文件,其中包含已排序的标识符和一些数据。我们想要在一些起始位置和结束位置之间提取数据(由标识符定义。平凡的解决方案是使用二进制搜索来查找起始位置,然后返回所有内容,直到达到结束。

但是,如果我们需要考虑缓存,情况会有所改变。然后直接内存访问基本上是免费的,但页面未命中是昂贵的。一个简单的解决方案是使用二进制搜索来查找范围内的任何位置。然后可以向后遍历文件,直到达到开始位置。然后将文件移动到正向,直到到达结尾。这听起来很愚蠢,但它确保一旦找到范围内的单个点,就不需要加载额外的页面。

所以,重要的是找到范围内的单个位置。二进制搜索是一个很好的选择,但是如果我们知道,例如,文件的最后三个或三个第一页通常都在页面缓存中,我们也应该使用该信息。如果我们知道哪些页面在缓存中,搜索算法可以做得更好,但即使使用 a posteriori 知识,无论我们是打击还是错过,都会有所帮助。

(实际问题比这复杂一点,但也许这说明了需要。)

部分解决方案:

正如JimB在他的回答中所说,Linux中没有这样的API。这给我们留下了更通用的分析工具(例如Linux中的python的cProfileperf stat)。

我的代码面临的挑战是,我知道大部分时间都花在内存访问上,最终导致缓存未命中。这很容易,因为它们是代码可能阻塞的唯一点。在代码中我有类似b = a[i]的内容,根据i,这将非常快或非常慢。

当然,在流程运行期间查看缓存未命中的总数可能有助于进行一些优化,但我真的知道系统的其余部分是否会产生一种情况,例如:无论如何,文件的第一页或最后一页大部分时间都在缓存中。

因此,我将实现关键内存访问的时序(可能错过缓存的时间)。由于几乎所有在系统中运行的都是I / O限制(不受CPU限制),因此上下文切换不太可能经常破坏我的时序。这不是一个理想的解决方案,但它似乎是最不好的解决方案。

1 个答案:

答案 0 :(得分:2)

这确实需要在程序之外处理。虚拟内存层由内核处理,细节不会暴露给进程本身。您可以在其过程中分析您的程序,并根据函数调用的时间估计发生的情况,但要真正了解您需要使用特定于操作系统的分析工具。

Linux有一个很好的工具:perfperf stat命令可能是您了解程序执行情况所需的全部内容。