4

我想查看我的程序正在访问哪些页面。现在一种方法是使用mprotectwith SIGSEGVhandler 来记下正在访问的页面。但是,这涉及为我感兴趣的所有内存页面设置保护位的开销。

想到的第二种方法是在开始时使翻译后备缓冲区 (TLB) 无效,然后记下未命中的内容。在每次未命中时,我都会记下寻址的内存页,因此记下它。现在的问题是如何处理 linux 程序在用户空间中的 TLB 未命中。

如果您知道比 TLB 未命中或mprotect更快的方法来记下脏内存页,请告诉我。另外,我想要一个仅适用于 x86 的解决方案。

4

3 回答 3

7

我想查看我的程序正在访问哪些页面。

您可以模拟 CPU 并获取此数据。变体:

  • 1) valgrind - 用户空间二进制文件的动态翻译器,具有良好的检测支持。试试 cachegrind 工具——它甚至可以模拟 L1/L2 缓存;您也可以尝试构建新工具来记录所有内存访问(例如,使用页面粒度)
  • 2) qemu - 动态翻译器,系统范围和进程范围的模式。据我所知,原始 qemu 中没有仪器
  • 3) bochs - 系统范围的 CPU 模拟器(非常慢)。您可以轻松破解“内存访问”代码以获取内存日志。
  • 4) PTLsim - www.ptlsim.org/papers/PTLsim-ISPASS-2007.pdf

但是,这涉及为所有内存页设置保护位的开销

这个开销是不是太大了?

现在的问题是如何处理 linux 程序在用户空间中的 TLB 未命中。

您无法在内核空间(在 x86 和许多其他流行平台上)中处理未命中或用户空间。这是因为大多数平台在硬件中管理 TLB 未命中: . MMU(CPU/芯片组的一部分)将对页表进行遍历,并透明地获取物理地址。只有当某些位被设置或地址区域没有被映射时,才会产生缺页中断并将其传递给内核。

此外,似乎没有办法在现代 CPU 中转储 TLB(但 386DX 能够做到这一点

您可以尝试通过引入的延迟来检测 TLB 未命中。但是这种延迟可以通过 TLB 查找的乱序启动来隐藏。

此外,大多数硬件事件(内存访问、tlb 访问、tlb 命中、tlb 未命中)都由硬件性能监控计数(这部分 CPU 由 Vtune、CodeAnalyst 和 oprofile 使用)。不幸的是,这只是事件的全局计数器,您不能同时激活超过 2-4 个事件。好消息是,您可以将 perfmon 计数器设置为在达到某个计数时中断。然后,您将(通过中断)获得指令($eip)的地址,该地址已达到计数。因此,您可以使用此硬件找到 TLB-miss-heavy 热点(它存在于每个现代 x86 cpu;intel 和 amd 中)。

于 2011-09-24T15:09:46.930 回答
6

TLB 对用户空间程序是透明的,最多可以通过一些性能计数器(没有地址)来计算 TLB 未命中。

于 2011-09-23T15:08:25.727 回答
-1

查看您的进程的 /proc/PID/maps 文件。根据http://www.kernel.org/doc/Documentation/filesystems/proc.txt中的文档,/proc/PID/maps 指定每个进程的内存映射。该地图将告诉您“我的程序正在访问哪些页面”。但是,您似乎想知道其中哪些是脏页。虽然我不确定如何找到脏页面的确切列表,但可以通过查看 /proc/PID/smaps 中的私有脏和共享脏字段并将其除以页面大小来找到有多少页面是脏的。请注意,此方法非常快。我相信可以通过定期轮询 /proc/PID/maps 来大致了解哪些页面是脏的。

于 2012-10-10T00:26:10.777 回答