欢迎任何建议/讨论!
问题实际上是简短的标题,但我会解释为什么我需要实际地址。
背景:
这些天我对缓存和多核架构很着迷,现在我很好奇缓存在并行环境下如何影响我们的程序。
在某些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
,并尝试获取内存信息。
嗯......似乎结果仍然是关于虚拟内存。
答案 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?