如何将大型数组预加载并行缓存?

时间:2014-04-22 15:47:32

标签: c multithreading caching intel preload

我的机器是Intel IvyBride架构。我的L3缓存是12MB,16路关联,缓存行大小为64B。

我的程序中有一个非常大的数组长数组[12MB / sizeof(long)]。我想在程序执行之前预加载大型数组以加速初始化过程。

我能想到实现这一目的的一种方法是从索引0到“按顺序”的数组末尾访问整个数组。但是,访问整个阵列的时间太长。这种方法使用一个核心。

我能做的另一种方法是使用多个线程并行访问整个数组。每个线程只访问数组的一部分。由于这些线程可以在多个内核上运行,因此可以加速将阵列预加载到共享缓存。但是,这种方法需要多核才能运行这些线程。

我的问题是: 是否有任何硬件(如DMA)可用于发出命令并使硬件将一堆数据预加载到共享缓存中?

2 个答案:

答案 0 :(得分:2)

DMA只能将您的阵列预装到主内存中,例如磁盘,它不适用于缓存。除了从RAM加载到RAM中12MB的时间与从磁盘加载到RAM的成本相比,这是无关紧要的。

要实现后者,您可以使用mmap/MAP_POPULATE。这将留下将数据预取到RAM直到内核实现的机制,但通常比手动执行更快。内核很可能会使用DMA或类似的机制。

将内容加载到缓存中是一个更大的问题,尤其是您无法控制如何逐出缓存。 你可以得到的最接近的是预取指令(gcc __builtin_prefetch(const void *addr, ...)),但是这甚至不能保证预取,而且你必须在每个缓存行上调用它,这可能需要花费更多的时间。缓存未命中。

答案 1 :(得分:2)

在某些情况下可能 - 检查您的CPU是否支持" DCA" (直接缓存访问),如果可以激活此功能。这可能很有用:https://www.myricom.com/software/myri10ge/790-how-do-i-enable-intel-direct-cache-access-dca-with-the-linux-myri10ge-driver.html

我认为你真的不需要这样,顺序遍历整个阵列应该非常高效,因为它很容易被CPU识别为顺序流并触发HW预取器。由于它是IvyBridge,因此即使是线性页面交叉也应该很快,因为它可以预取到下一个物理页面。在并行访问多个页面时也可能有一点优化(也就TLB未命中延迟而言),但最终归结为问题 - 你能否使你的内存带宽饱和。单个核心可能会遇到核心/ L3边界的瓶颈,因此最佳方式是通过在每个核心上运行HW线程来分配工作,每个核心到不同的段(每次迭代的大小可以是4k页,但是更大的块也可以享受每个核心中的页面映射局部性的好处

但是,您可能遇到比访问数据更大的问题,并且说服L3将其保留在那里。据说IvyBridge在L3中使用动态替换策略,这意味着它会问自己 - 谁使用了所有这些数据,并且因为你只是预加载一次,答案就是可能是"没有人"。此时,L3可以决定完全避免缓存该阵列,或者将较新的块写入较旧的阵列。

确切的行为取决于未公布的实际实施,但取决于"技巧"它,我相信你必须多次访问每个数据行才能获得'扔掉了。请注意,连续两次访问它不会有帮助,因为它已经在上层缓存中,您必须在一定距离内访问它 - 而不是再次访问L3,但不要太大,以免被扔掉。当然需要进行一些实验来微调这一点。

编辑:

这是一篇关于IvyBridges'的博客文章。您应该担心的L3替换政策 -
http://blog.stuffedcow.net/2013/01/ivb-cache-replacement/

当然,实际的过程应该表现得很好,因为它应该被利用L3缓存的好处,它只是预加载阶段,可能会给你带来麻烦。如果处理时间相对较长,那么最初的冷缺失可能不值得预加载 - 谨防过早优化。