如何防止两个进程争夺公共缓存?

How to prevent two processess from fighting for a common cache?

我在考试中被问到这个问题。我们有两个 CPU 或同一个 CPU 中的两个核心,它们共享一个公共缓存(例如 L3)。在每个 CPU 上都有一个 MPI 进程(或一个普通进程的线程)。我们如何确保这两个进程不会相互干扰,这意味着它们不会将彼此的条目推出或各自使用一半的缓存或类似的东西。这里的目标是提高内存访问的速度。

OS 是某种 Unix,如果这很重要的话。

您需要在 multi-thread 编程方面使用锁。不了解你的具体情况,不好举例。

当一个进程有权访问时,将所有其他进程锁定在外,直到 'accessing' 进程完成对资源的访问。

根据您的评论,似乎需要 "textbook answer",因此我建议在进程之间对缓存进行分区。通过这种方式,您可以保证它们不会竞争相同的缓存集并互相攻击。这是假设您实际上不想在这两个进程之间共享任何东西,在这种情况下这种方法会失败(尽管可能的解决方法是将缓存 space 分成 3 - 每个进程一个范围,并且一个用于共享数据)。

由于您可能不希望重新设计缓存并提供硬件分区方案(除非问题出现在计算机体系结构课程的范围内),实现此目的的最简单方法就是检查缓存大小和关联性,计算出我们的集合数量,并将每个 process/thread 的数据集对齐到不同的部分。

例如,如果您的共享缓存有 2MB 大,并且有 16 路和 64B 行,那么您将有 2k 组。在这种情况下,每个进程都希望将其物理地址(假设缓存是物理映射的)对齐到不同的半 1k 集,或者每个 0x20000 中的不同 0x10000。换句话说,P0 可以自由使用第 16 位等于 0 的任何物理地址,而 P1 可以使用第 16 位等于 1 的地址。

请注意,由于这超过了基本 4k 页面的大小(0x1000 对齐),您需要修改 OS 以将页面分配给每个进程的适当物理地址,或者只需使用更大的页面(2M 就足够了)。 另请注意,通过保持每次分配连续的 0x10000,我们仍然享受空间局部性和高效的硬件预取(否则您可以简单地选择任何其他拆分,甚至 even/odd 通过使用位 6 设置,但这会使您的数据破碎。

最后一个问题是针对大于此 0x10000 配额的数据集 - 要进行对齐,您只需将它们分成最大 0x10000 的块,然后分别对齐。还有 code/stack/pagemap 和其他类型的 OS/system 数据的问题,你对这些数据的控制较少(实际上代码也可以对齐,或者在这种情况下更有可能 - 共享) - 我假设这有对抖动的影响可以忽略不计。

再次 - 这试图在不知道您使用什么系统、您需要实现什么,甚至不知道课程背景的情况下回答。有了更多的上下文,我们可能可以将其集中在一个更简单的解决方案上。

缓存中的路有多大?

例如,如果您有一个缓存,其中每条路的大小为 128KiB,您可以这样划分内存,即对于每个地址模 128KiB,进程 A 使用 0-64KiB 区域,进程 B 使用较低的 64KiB-128KiB 区域。 (这假设每个核心私有 L1)。

如果您的物理页面大小为 4KiB(并且您的 CPU 使用物理地址进行缓存,而不是虚拟地址 - 这确实发生在某些 CPU 上),您可以做得更好。假设您将相同数量的内存映射到每个内核的虚拟地址 space - 16KiB。第0、2、4、6页进入进程A的内存映射,第1、3、5、7页进入进程B的内存映射。只要您只在那个精心布局的区域中寻址内存,缓存就永远不会发生冲突。当然,这样做实际上已经将高速缓存通道的大小减半了,但是您有多种方法...