3

我正在写一个关于页面错误的文档并试图获得一些具体的数字来使用,所以我编写了一个简单的程序来读取 12*1024*1024 字节的数据。简单的:

int main()
{
  FILE*in = fopen("data.bin", "rb");
  int i;
  int total=0;
  for(i=0; i<1024*1024*12; i++)
    total += fgetc(in);
  printf("%d\n", total);
}

所以是的,它会遍历并读取整个文件。问题是我需要在此过程中将触发 1536 次的 dtrace 探针(12M/8k)。即使我计算了所有 fbt:mach_kernel:vm_fault*: 探测器和所有 vminfo::: 探测器,我也没有达到 500,所以我知道我没有找到正确的探测器。

任何人都知道我在哪里可以找到当页面从磁盘出现故障时触发的 dtrace 探测器?

更新:

如果问题在于 stdio 函数中正在进行一些智能预取,我尝试了以下操作:

int main()
{
  int in = open("data.bin", O_RDONLY | O_NONBLOCK);
  int i;
  int total=0;
  char buf[128];
  for(i=0; i<1024*1024*12; i++)
  {
    read(in, buf, 1);
    total += buf[0];
  }
  printf("%d\n", total);
}

这个版本需要更长的时间来运行(42 秒实时,其中 10 秒是用户时间,其余是系统时间 - 我猜是页面错误),但仍然会产生五分之一的错误,正如我预期的那样。

出于好奇,时间增加并不是由于循环开销和强制转换(char 到 int)。执行这些操作的代码版本需要 0.07 秒。

4

3 回答 3

1

不是直接的答案,但您似乎将磁盘读取和页面错误等同起来。它们不一定相同。在您的代码中,您正在将文件中的数据读取到一个小的用户内存块中,因此 I/O 系统可以以任何它认为合适的方式和大小将文件读入缓冲区/VM 缓存。我可能在这里错了,我不知道达尔文是怎么做到的。

我认为更可靠的测试是将mmap(2)整个文件放入进程内存然后去触摸每个页面是那个空间。

于 2010-08-13T20:03:56.010 回答
1

我最近在同一个老鼠洞里。我现在没有可用的 DTrace 脚本或测试程序,但我会给你以下建议:

1.) 掌握 Amit Singh 的 OS X Internals 并阅读关于虚拟内存的第 8.3 节(这将使您进入选择 DTrace 探针的正确参考框架)。

2.) 亲身体验 Brendan Gregg / Jim Mauro 的 Solaris 性能和工具。阅读有关虚拟内存的部分,并密切注意使用 vminfo 提供程序的示例 DTrace 脚本。

3.) OS X 肯定会从文件系统中预取大块页面,并且您的测试程序正在参与这种优化(因为您是按顺序读取的)。有趣的是,Solaris 并非如此。尝试随机访问大数组以击败预取。

于 2010-11-30T04:24:10.933 回答
0

操作系统会在作为单独操作被触摸的每个页面中出现故障的假设(因此,如果您触摸 N 个页面,您将看到 DTrace 探测器触发 N 次)是有缺陷的;大多数 UN*Xes 将执行某种预读或预故障,并且您不太可能获得与页面完全相同数量的调用。即使您直接使用 mmap() 也是如此。

确切的比率也可能取决于文件系统,因为预读和页面集群的实现和阈值不太可能对所有它们都相同。

如果您直接使用 mmap 然后应用 madvise(MADV_DONTNEED) 或类似的和/或使用 msync(MS_INVALIDATE) 清除整个范围,您可能可以强制执行每页错误策略。

于 2010-11-18T16:47:30.060 回答