多个线程和CPU缓存

时间:2011-01-26 08:32:52

标签: c multithreading caching

我正在使用多个线程在C中实现图像过滤操作,并使其尽可能优化。我有一个问题:如果一个内存被thread-0访问,并且如果同一个内存被thread-1访问,它是否会从缓存中获取它?这个问题源于这两个线程可能运行到CPU的两个不同核心的可能性。所以另一种方法是:所有内核是否共享相同的公共缓存?

假设我有一个如下所示的内存布局

int output [100];

假设有2个CPU核心,因此我产生了两个并发工作的线程。一种方案可以是将内存分成两个块,0-49和50-99,并让每个线程在每个块上工作。另一种方法是让线程0在偶数索引上工作,比如0 2 4等等。而另一个线程工作在奇数索引上,比如1 3 5 ......这个后来的技术更容易实现(特别是对于3D)数据)但我不确定我是否可以通过这种方式有效地使用缓存。

4 个答案:

答案 0 :(得分:20)

这个问题的答案在很大程度上取决于架构和缓存级别,以及线程实际运行的位置。

例如,最近的英特尔多核CPU具有每个核心的L1缓存,以及在同一CPU包中的核心之间共享的二级缓存;但是不同的CPU包将拥有自己的L2缓存。

即使在您的线程在一个包中的两个核心上运行的情况下,如果两个线程都访问同一个高速缓存行中的数据,您将在两个L1高速缓存之间弹出该高速缓存行。 非常低效,您应该设计算法以避免这种情况。


有一些评论询问如何避免这个问题。

从本质上讲,它确实不是特别复杂 - 您只是想避免两个线程同时尝试访问位于同一缓存行上的数据,其中至少有一个线程正在写入数据。 (只要所有线程只是读取数据,就没有问题 - 在大多数体系结构中,只读数据可以存在于多个缓存中。)

要做到这一点,您需要知道缓存行大小 - 这取决于体系结构,但目前大多数x86和x86-64系列芯片使用64字节缓存行(请参阅其他体系结构的体系结构手册)。您还需要知道数据结构的大小。

如果您要求编译器将感兴趣的共享数据结构与64字节边界(例如,您的数组output)对齐,那么您就知道它将从缓存行的开头开始,并且您还可以计算后续缓存行边界的位置。如果int为4个字节,则每个缓存行将包含8个int值。只要数组在缓存行边界上开始,output[0]output[7]将在一个缓存行上,output[8]output[15]在下一个缓存行上。在这种情况下,您可以设计算法,使每个线程处理一个相邻int值的块,该值是8的倍数。

如果您要存储复杂的struct类型而不是普通的int,那么pahole实用程序将会被使用。它将分析已编译二进制文件中的struct类型,并显示布局(包括填充)和总大小。然后,您可以使用此输出调整struct - 例如,您可能需要手动添加一些填充,以便struct是缓存行大小的倍数。

在POSIX系统上,posix_memalign()函数对于分配具有指定对齐的内存块非常有用。

答案 1 :(得分:5)

一般来说,分享重叠的内存区域是一个坏主意,就好像一个线程处理0,2,4 ......以及其他进程1,3,5 ......虽然有些架构可能会支持这一点,但大多数架构都会不,您可能无法指定代码将在哪台机器上运行。此外,操作系统可以自由地将您的代码分配给它喜欢的任何核心(一个,两个在同一物理处理器上,或两个核心在不同的处理器上)。此外,每个CPU通常都有一个单独的第一级缓存,即使它位于同一个处理器上。

在大多数情况下,0,2,4 ... / 1,3,5 ...会使性能降低,甚至可能比单个CPU慢。 Herb Sutters "Eliminate False Sharing"证明了这一点。

使用方案[... n / 2-1]和[n / 2 ... n]在大多数系统上都可以更好地扩展。它甚至可以导致超线性性能,因为可以使用总和中所有CPU的高速缓存大小。使用的线程数应始终可配置,并且应默认为找到的处理器核心数。

答案 2 :(得分:0)

我可能会犯错,但是核心的缓存是否共享取决于CPU的实现。您必须在制造商页面上查找技术表,以检查CPU中的每个核心是否都有自己的缓存,或者缓存是否已共享。

我正在为一家安全公司从事图像处理工作,有时候我们在线程上运行批处理操作后会出现损坏的图像。经过长时间的调查,我们得出结论,缓存是在CPU Core之间共享的,在极少数情况下,数据被覆盖或用不正确的数据替换。

这是否值得考虑,或者是一种罕见的事件,我无法回答。

答案 3 :(得分:0)

英特尔文档

英特尔发布了per-generation datasheets,其中可能包含此类信息。

例如,对于我在旧计算机上安装的处理器i5-3210M,我查看了3rd generation - Datasheet Volume 1 3.3“英特尔超线程技术(英特尔HT技术)”:

  

处理器支持英特尔超线程技术(英特尔HT技术)   允许执行核心充当两个逻辑处理器。虽然有些   共享诸如缓存,执行单元和总线之类的执行资源,每个资源   逻辑处理器具有自己的体系结构状态,具有自己的一组通用寄存器和控制寄存器。

确认在该代CPU的给定超线程中共享缓存。

另请参阅: