我们如何为变量指定物理地址?

时间:2012-12-19 06:30:35

标签: c linux performance caching memory-address

欢迎任何建议/讨论!

问题实际上是简短的标题,但我会解释为什么我需要实际地址。


背景

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

在某些CPU型号(例如,我的英特尔酷睿双核T5800)中,L2缓存在核心之间共享。因此,如果程序A正在访问物理地址的内存,如

0x00000000, 0x20000000, 0x40000000...

和程序B访问

的数据

0x10000000, 0x30000000, 0x50000000...

由于这些地址共享相同的后缀,因此L2缓存中的相关集将经常刷新。我们预计会看到两个程序相互争斗,从内存缓慢读取数据而不是缓存,但是它们在不同的核心中分开。

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


第一次尝试:

从堆,掩码中占用大量空间,并获取特定地址。

我的CPU有一个L2缓存,大小= 2048KB,关联性= 8,所以像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]可能与不同的缓存集相关。


第二次尝试

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

嗯......似乎结果仍然是关于虚拟内存。

1 个答案:

答案 0 :(得分:7)

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

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

因此,为了解决背景示例,这些地址来自两个不同的进程 - 它绝对没有什么可以尝试和比较它们。它们的代码是否存在于任何缓存中取决于许多事情,包括处理器的cache-replacement strategy,OS启用的缓存策略,其他进程的数量(包括内核模式线程)等等。

第一次尝试中,再次直接实际测试CPU缓存,您无法获得任何结果。首先,你的大缓冲区不会在堆上。它将成为可执行文件的数据部分(特别是.bss)的一部分。堆用于malloc()内存分配系列。其次,如果你分配一些巨大的1GB区域并不重要,因为虽然它在你的进程的虚拟地址空间中是连续的,但是由操作系统来分配虚拟内存的页面,它认为合适 - 可能< em> not 实际上是连续的。同样,您几乎无法控制来自用户空间的内存分配。 “Is there a way to allocate contiguous physical memory from userspace in linux?”简短的回答是否。

/proc/$pid/maps也不会让你到任何地方。是的,其中列出了大量地址,但同样,它们都在进程$pid的虚拟地址空间中。有关这些的更多信息:How do I read from /proc/$pid/mem under Linux?