7

欢迎任何建议/讨论!

这个问题实际上很简短,但我会解释为什么我需要实际地址。


背景

这些天我对缓存和多核架构着迷,现在我很好奇缓存在并行环境下如何影响我们的程序。

在某些 CPU 型号(例如,我的 Intel Core Duo T5800)中,L2 缓存在内核之间共享。因此,如果程序 A 正在访问物理地址的内存,例如

0x00000000, 0x20000000, 0x40000000...

和程序 B 访问数据

0x10000000, 0x30000000, 0x50000000...

由于这些地址共享相同的后缀,因此二级缓存中的相关集合会被频繁刷新。我们预计会看到两个程序相互竞争,从内存而不是缓存中缓慢读取数据,尽管它们在不同的内核中是分开的。

然后我想在实践中验证结果。在这个实验中,我必须知道物理地址而不是虚拟地址。但是我该如何应对呢?


第一次尝试:

从堆中吃掉一大块空间,掩码,得到某个地址。

我的 CPU 有一个大小为 2048KB 且关联性为 8 的 L2 缓存,因此物理地址之类0x12340000, 0x12380000, 0x123c0000的将与 L2 缓存中的第一组相关。

int HEAP[200000000]={0};
int *v[2];
int main(int argc, char **argv) {

    v[0] = (int*)(((unsigned)(HEAP)+0x3fffc) & 0xfffc0000);
    v[1] = (int*) ((unsigned)(v[0]) + 0x40000); 

    // one program pollute v[0], another polluting v[1]
}

可悲的是,在虚拟内存的“帮助”下,变量HEAP在物理内存中并不总是连续的。v[0]并且v[1]可能与不同的缓存集有关。


第二次尝试

access /proc/self/mem,并尝试获取内存信息。

嗯……看来结果还是关于虚拟内存的。

4

1 回答 1

7

您对内存和这些地址的理解不完整/不正确。本质上,您尝试测试的内容是徒劳的。

在用户模式进程的上下文中,您看到的几乎每个地址都是虚拟地址。也就是说,只有在该过程的上下文中才有意义的地址。操作系统管理此虚拟内存空间(进程独有)映射到内存页面的位置。这些内存页面在任何给定时间都可能映射到被调入的页面(即驻留在物理 RAM 中)——或者它们可能被调出,并且仅存在于磁盘上的交换文件中。

因此,为了解决背景示例,这些地址来自两个不同的进程 - 尝试比较它们绝对没有任何意义。它们的代码是否存在于任何缓存中取决于很多因素,包括处理器的缓存替换策略、操作系统启用的缓存策略、其他进程的数量(包括内核模式线程)、等等

在您的第一次尝试中,就直接实际测试 CPU 缓存而言,您也不会取得任何进展。首先,您的大缓冲区不会在堆上。它将成为可执行文件的数据部分(特别是 .bss)的一部分。堆用于malloc()内存分配系列。其次,是否分配一些巨大的 1GB 区域并不重要,因为尽管它在进程的虚拟地址空间中是连续的,但操作系统可以在它认为合适的地方分配虚拟内存页面 - 这可能不是实际上是连续的。同样,您几乎无法控制来自用户空间的内存分配。"有没有办法在 linux 中从用户空间分配连续的物理内存?“ 最简洁的答案是不。

/proc/$pid/maps也不会把你带到任何地方。是的,那里列出了很多地址,但同样,它们都在 process 的虚拟地址空间中$pid。有关这些的更多信息:如何在 Linux 下从 /proc/$pid/mem 读取?

于 2012-12-19T07:01:49.513 回答