0

我正在阅读缓存一致性(http://simple.wikipedia.org/wiki/Cache_coherence缓存一致性有什么意义?)。据称,

具有多个高速缓存存储器的处理器会出现高速缓存一致性问题。

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

4

2 回答 2

1

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

于 2014-09-16T02:40:29.387 回答
0

您误解了缓存的功能以及它是如何控制的。

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

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

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

如果处理器需要不在缓存中的数据,则会出现缓存未命中。处理器停止在其轨道上,直到数据从 RAM 中被带入,这可能意味着处理器在任何数量的 CPU 时钟周期内完全不做任何事情,我假设正常情况是在 30 到 100 个周期之间。

真正快速的应用程序——通常以高级计算机游戏的形式——如果不以代码组织(小、快)、数据局部性(数据小到可能而不是遍布整个地方)并尽可能预加载。在更高的级别上,您需要良好的设计和算法,但它们也或多或少与缓存相关联。

由于您是嵌入式程序员,情况有所不同。大多数嵌入式处理器具有片上 SRAM 形式的 RAM,没有等待状态。这意味着读写 SRAM 的速度与处理器希望的一样快,也就是说,由于 SRAM 与它保持同步,因此它永远不需要停止在其轨道上。

该处理器还具有比 SRAM 慢得多的片上 FLASH 存储器。为了弥补这一点,芯片将在 FLASH 和 CPU 之间设置一个读取缓存,以便从 FLASH(因为它是只读的)执行大多数读取操作,而无需处理器等待数据到达。

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

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

_____ 回答第一条评论 _____

缓存一致性比这要复杂一些。

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

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

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

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

多核处理器通常有一个通用的 L3 接口连接到北桥和特定于内核的 L2 缓存。L3 将向所有连接的 L2 发送有关任何更新的信息,因为只有它们知道它们包含什么。

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

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

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

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

我使用“辅助轮”类比:如果您的自行车上有辅助轮(总缓存一致性),您可能不会摔倒,但您不能快速行驶,因为您几乎无法转向。取下辅助轮,您可以随心所欲地行驶并避免危险,因为您可以驾驶。另一方面,淘汰的结果要严重得多。

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

公交车锁可不是小事。不管成功与否,总线锁定都需要大量的 CPU 周期来尝试:从 300 到 3000 不等。这就是没有完全缓存一致性所付出的代价:如果你作为程序员想出一种有效的软件同步方案,因为您很少使用它,所以几乎不会被注意到。没有经验的程序员会安全地使用它并一直使用它,结果系统会很慢。凭借经验,她或他将了解到以或多或少聪明的方式“安全行事”是可能的。

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

于 2013-09-04T08:47:01.137 回答