Memory 现代处理器上的并行内存访问

Memory 现代处理器上的并行内存访问,memory,parallel-processing,x86,multicore,bus,Memory,Parallel Processing,X86,Multicore,Bus,我最近有一个12核Intel CPU(Haswell架构),它有4个内存通道。机器可以并行执行多少次DRAM内存访问 例如,如果我有一个程序,它使用12个线程,这些线程位于一个紧循环中,从随机内存地址中读取一个字节,这个范围太大,无法放入缓存。我预计所有12个线程将花费几乎所有的时间等待内存获取 线程是否必须轮流使用DRAM总线 注意:假设我使用的是1-GB虚拟机页面大小,因此没有TLB缓存未命中。英特尔数据表几乎回答了这个问题 我的第一个线索是英特尔论坛上的一个问题: Jaehuk.Lee,

我最近有一个12核Intel CPU(Haswell架构),它有4个内存通道。机器可以并行执行多少次DRAM内存访问

例如,如果我有一个程序,它使用12个线程,这些线程位于一个紧循环中,从随机内存地址中读取一个字节,这个范围太大,无法放入缓存。我预计所有12个线程将花费几乎所有的时间等待内存获取

线程是否必须轮流使用DRAM总线


注意:假设我使用的是1-GB虚拟机页面大小,因此没有TLB缓存未命中。

英特尔数据表几乎回答了这个问题

我的第一个线索是英特尔论坛上的一个问题:

Jaehuk.Lee,2017年2月1日09:27问了几乎和我一样的问题:

第二个问题是关于IMC及其应用程序的同时请求 支持全新的CPU型号,如skylake和kaby lake 遵循 在上面的链接中,“内存控制器最多可以在32个磁盘上运行 同时请求(读写)“我想知道有多少 skylake和kabylake CPU支持同时请求。我已经 已经检查了第6代和第7代Intel CPU数据表, 但是我找不到任何信息

链接已断开。但他的“32”数字听起来似乎有道理

英特尔的一名工作人员回应说:

内存控制器有一个高级命令调度程序,其中 同时检查挂起的请求以确定 下一步将发出有效的请求。最有效的请求是 从所有挂起的请求中选取并发送到系统内存 及时合理利用命令重叠。因此,相反 让所有内存访问请求分别通过 强制每次执行一个请求的仲裁机制, 它们可以在不干扰当前请求的情况下启动 允许并发发出请求。这允许进行优化 带宽和减少的延迟,同时保持适当的命令 满足系统内存协议的间距

令人恼火的是,Xeon E5-2670 v3的数据表没有包含等效部分

答案的另一部分是E5-2670有4个DDR通道。内存以256字节的粒度交错以优化带宽。换句话说,如果从地址0读取1024字节的块,则前256个字节将从DIMM 0获取。字节256到511来自DIMM 1等

把这两个放在一起,我怀疑内存控制器可以并行执行4次读取,并且足够智能,如果4个或更多线程正在等待映射到4个不同DIMM的读取,它将并行执行这些读取。而且它有足够的硬件来维持其调度表中大约32个读/写操作

我可以想出另一种实现并行性的可能方法。每个DDR通道都有自己的数据和地址总线。当内存控制器请求读取时,它使用地址行+一些控制行来请求读取,然后等待响应。对于随机读取,通常有两个等待-RAS到CAS延迟和CAS延迟-每个大约15个周期。您可以想象内存控制器在这些等待期间从不同的DIMM(*)开始另一次读取,而不是让地址线空闲。我不知道这是否完成了

*事实上,根据我们的研究,DRAM硬件的并行性比每个通道有多个DIMM要多。每个DIMM可能有多个列组,每个列组有多个列组。我认为您可以切换到DIMM中的任何其他列组和列组,以并行执行另一次访问

编辑

我测量我的机器至少可以并行执行6次随机访问,尽管只有4个内存通道。因此,单个内存通道可以并行执行2个或更多随机访问,可能使用上面段落中描述的方案I

为了获得这些信息,我曾经在我的机器上测量DRAM访问的延迟。结果是60纳秒。然后我编写了一个小C程序,从1GB的随机数表中执行32位读取,并使用结果增加校验和。伪代码:

uint32\u t校验和=0;
对于(int i=0;i<256*1024*1024;i++){
无符号偏移量=rand32()&(表大小-1);
校验和+=随机数[偏移量]表;
}
循环的每次迭代平均耗时10 ns。这是因为我的CPU中的无序和推测性执行特性能够将这个循环并行化6次。即10纳秒=60纳秒/6

如果我将代码替换为:

unsigned offset=rand32()&(表大小-1);
对于(int i=0;i<256*1024*1024;i++){
偏移量=随机数字表[offset];
偏移量&=(表大小-1);
}
然后每次迭代需要60 ns,因为循环无法并行化。它无法并行化,因为每次访问的地址取决于上次读取的结果

我还检查了编译器生成的程序集,以确保它没有执行并行化

编辑2

我决定测试当我并行运行多个测试时会发生什么,每个测试作为一个单独的进程。我使用了上面包含校验和的程序段(即每次访问的延迟为10 ns的程序段)。通过并行运行6个实例,我得到了13.9 ns的平均明显延迟,这意味着大约26个访问必须并行进行。(60 ns/13.9 ns)*6=25.9

6例为最佳。任何其他因素都会导致总吞吐量下降

编辑3-回答Peter Cordes RNG问题

我尝试了两种不同的随机数生成器

uint32\u t g\u seed=12345;
uint32_t fastrand(){
g_seed=214013*g_seed+2531011;
返回g_种子;
}

//*真的*最小PCG32 c
// Pseudo random number is in edx
// table is in rdi
// loop counter is in rdx
// checksum is in rax
.L8:
        imul    edx, edx, 214013
        add     edx, 2531011
        mov     esi, edx
        and     esi, 1073741823
        movzx   esi, BYTE PTR [rdi+rsi]
        add     rax, rsi
        sub     rcx, 1
        jne     .L8
        ret