缓存一致性及其解决方案

时间:2013-09-04 07:39:07

标签: linux multithreading

我正在阅读缓存一致性(http://simple.wikipedia.org/wiki/Cache_coherenceWhat's the point of cache coherency?)。据说

  

对于具有多个缓存的处理器,会出现缓存一致性问题。

我的问题是:即使我们在一个处理器中有多个缓存。因为内核将根据每页进度表仅分配一个缓存行。那么为什么Cache Coherence问题会出现呢?它的解决方案是什么?

2 个答案:

答案 0 :(得分:1)

您可能在进程中有多个线程和/或中断处理程序。然后,CPU可以将单个存储器地址的值保存到单独的高速缓存中。外部模块和驱动程序也可以使用自己的缓存值共享该内存资源。在这种情况下,会出现缓存一致性问题。

答案 1 :(得分:0)

您误解了缓存的功能及其控制方式。

首先,可以启用或禁用缓存,或者(如果它具有写缓存功能)在直接程序(通常是OS)控制下刷新。程序还可以指示缓存预加载(读取)某些内存区域,因为程序比缓存更好地了解它接下来需要的数据。

除此之外,缓存还充当透明的高速缓冲区或处理器内核与RAM之间的高速缓冲区系统。如果我们假设一台带有DDRx RAM内存的标准PC,我们就会遇到这样的问题:DDRx RAM无法在接近处理器使用率的任何地方向处理器提供数据。以同样的方式,DDRx RAM无法写入处理器能够写入的速度附近,因此缓存也会缓冲写入的数据(如何取决于所选的缓存写入策略设计)。

通常,经历处理器(应用程序)访问RAM存储区域的高速缓存将假定紧随其后的RAM也将被访问并将其预加载到高速缓存行中。当应用程序想要访问该数据时,它已经在缓存中并且程序运行得更快。如果程序不需要它,则意味着缓存已经不必要地加载它,浪费时间和内存系统接口容量,这可能会影响以后的缓存工作。

如果处理器需要不在缓存中的数据,则会出现缓存未命中。处理器停止运行,直到从RAM引入数据,这可能意味着处理器对任何数量的CPU时钟周期都没有任何作用,我认为正常情况介于30到100个周期之间。

真正快速的应用程序 - 通常以高级计算机游戏的形式 - 如果他们没有以代码组织(小,快速),数据位置等方式最大限度地利用缓存,那么它们就不会很快数据尽可能小,并且不会遍布整个地方)并尽可能预加载。在更高的层次上,您需要良好的设计和算法,但它们或多或少地与缓存相关联。

由于您是嵌入式程序员,情况有点不同。大多数嵌入式处理器都具有片上SRAM形式的RAM,没有等待状态。这意味着SRAM的读取和写入速度可以像处理器一样快速完成,因为SRAM无法与其保持同步,因此不需要停止运行。

处理器还具有片上闪存,比SRAM慢得多。为了弥补这一点,芯片将在FLASH和CPU之间具有读缓存,以便在没有处理器等待数据到达的情况下执行FLASH(因为它是只读)的大多数读取。

嵌入式设计可能需要比芯片上更多的RAM。在这些情况下,外部SDRAM或DDRx RAM芯片安装在卡上。现在你又回到了我所描述的用于PC的RAM情况,其中外部RAM无法快速访问。此外,外部存储器通常由小于32位宽的数据路径访问,这意味着32位或更大的数据实体在到达处理器之前将需要两次或更多次物理访问。与此同时,处理器等待。

回到原来的问题。嵌入式处理器的SRAM可以由处理器或外围设备(通常使用处理器无法检测的DMA)修改。由于SRAM没有被缓存缓冲(由于其速度),因此其内容始终是最新的。如果 - 另一方面 - 你有外部安装RAM等待状态,那么你需要一个同步功能(称为BIU - 总线接口单元),以确保(处理器和DMA)写入它以受控方式发生。 BIU将执行各种技巧来加快速度,但最终,BIU不是缓存,处理器必须等待它,减慢速度。

_____回答第一条评论_____

缓存一致性比这更复杂。

您应该将缓存一致性视为与在缓存中维护某些RAM区域的合理最新副本有关的事情。有几种方法可以更新RAM中的位置。一种是通过任意数量的现有核心,例如在大规模并行应用中,读取使用公共存储器区域,同时在存储器空间中对其他存储器区域进行修改,但是他们都希望不会同时更新。“ / p>

很容易忘记不仅核心更新RAM。当命令硬盘控制器将数据读入RAM时,它具有很大的自主权。它将磁头排列在正确的磁盘磁道上,并等待磁盘到达该位置,然后开始读取。从磁盘到达的数据被发送到RAM中的某个位置。完成此操作后,控制器会中断操作系统以通知它完成。

物理上,控制器位于"南桥"主板上的组件(控制所有外围设备),并将其从驱动器读取的数据发送到"北桥"连接到CPU,图形控制器和RAM的组件。这个描述说明了一个适用于许多处理器但不是所有处理器的设计(AMD的Opteron就是其中之一)。

因此,需要通知核心RAM地址的任何更改,这些地址是自己的缓存可能已经提取的地址,以加快核心的执行速度。控制器告诉北桥在哪里写数据。当它这样做时,它还通知(通常)L3缓存发生变化的位置。 L3对此进行比较并确定其任何缓存行是否受到影响。 L3还通知L2检查其线路并通知L1检查其线路。如果一行或多行受到影响,相应的Lx缓存会将该行标记为无效,从而将其释放。

多核处理器通常具有与北桥和核心特定L2高速缓存的单个通用L3接口。 L3将向所有连接的L2发送有关任何更新的信息,因为只有他们知道它们包含的内容。

在多核处理器,多处理器系统中,北桥将通知所有L3内存更新。如果其中一个内核更新了RAM位置,则L3将通知L2核心的片上兄弟。北桥检测到更新并通知L3其他已安装的处理器。

如果经常使用新的无效缓存行中的数据,缓存将急于重新加载新副本,从而发生冲突:不是在L2上的L1而是在L2上的L2和在RAM上的L3。

您可以理解北桥和缓存执行的一致性工作是重要的,复杂的和耗时的。因为它很复杂,并且由于所涉及组件的分层性质,所以在RAM更新发生时和传播到受影响组件(缓存)之间存在延迟。

这意味着可以实现的缓存一致性有一个限制,因为如果CPU从缓存中获取数据会在几个周期内失效怎么办?事实证明,缓存一致性是可接受的一致性和完全一致性之间的平衡。为什么不完全一致?总体一致性意味着缓存必须在更新传播时停止核心执行,最终你会破坏将缓存系统放在那里的目的:最小化核心被迫等待来自RAM的数据

我使用"训练轮"打个比方:如果你的自行车上有训练轮(总缓存一致性),你可能不会摔倒但是因为你几乎无法驾驶而无法快速行驶。取下训练轮,您可以尽可能快地前进并避免危险,因为您可以驾驶。另一方面,擦除的结果更加激烈。

由程序员来处理最后一小段同步。程序将(通常)不让核心读取由从磁盘读取的数据块更新的存储器位置。在任何时候,核心都可能需要写入共享内存位置,这将影响所有其他内核。在x86上,这是通过使用(通常)一种形式的" xchg reg,mem"来断言总线锁定信号。指令。该信号告诉系统每个人都必须完成他们正在做的事情,因为它需要一个已知状态。当xchg指令完成并且结果成功(我正在进行另一个总线锁定)时,数据被写入并且总线锁被释放。我已经写过herehere

公共汽车锁并非易事。无论是否成功,总线锁都需要大量的CPU周期才能尝试:300到300之间的任何CPU周期。这是你没有完全缓存一致性所付出的代价:如果你作为程序员想出来的话一个有效的软件同步方案,它几乎不会被注意到,因为你很少使用它。缺乏经验的程序员将安全地使用它并一直使用它,结果系统会很慢。根据经验,她或他将了解到可以安全地发挥其作用。或多或少地以聪明的方式。

核心拥有自己的L1和L2缓存的原因是它们可能正在处理不同的数据或不同的程序。如果他们正在处理相同的事情,他们会在尝试从公共缓存中读取时发生冲突。 L3是核心的公共缓存,也就是它们发生冲突的地方。在他们走得那么远之前,他们将(希望)能够在L1和L2中做很多有用的,不受干扰的和不间断的工作。我说"希望"因为这取决于程序员。