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

sle*_*ort 7 c linux performance caching memory-address

欢迎任何建议/讨论!

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


背景:

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

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

0x00000000, 0x20000000, 0x40000000...

和程序B访问数据

0x10000000, 0x30000000, 0x50000000...

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

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


第一次尝试:

从堆,面具吃一大块空间,并获得一定的地址.

我的CPU有一个L2缓存,大小= 2048KB,关联性= 8,因此物理地址类似于0x12340000, 0x12380000, 0x123c0000L2缓存中的第一个设置.

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]
}
Run Code Online (Sandbox Code Playgroud)

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


第二次尝试

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

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

Jon*_*art 7

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

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

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

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

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