LRU与FIFO对比随机

时间:2011-08-03 17:53:04

标签: algorithm hardware fifo lru

当出现页面错误或缓存未命中时,我们可以使用最近最少使用(LRU),先进先出(FIFO)或随机替换算法。我想知道,哪一个提供最佳性能,又称最不可能的未来缓存未命中'/页面错误?

架构:Coldfire处理器

6 个答案:

答案 0 :(得分:8)

不存在完美的缓存策略,因为它需要了解未来(程序如何访问内存)。

但是,在常见的内存访问模式案例中,有些内容明显优于其他内容。这是LRU的情况。从历史上看,LRU在整体使用方面表现非常出色。

但是,对于你想要做的事情,另一项政策可能会更好。总有一些内存访问模式会导致缓存策略执行不佳。

你可能会觉得这个帖子很有用(而且更详细!) Why is LRU better than FIFO?

答案 1 :(得分:8)

表达式"没有愚蠢的问题"适合这一点。这是一个很好的问题,我必须创建一个帐户并在其上发布并分享我的观点,就像在几个CPU上建模缓存的人一样。

您指定的体系结构是68000,它是CPU而不是GPU或USB控制器,或者可以访问缓存的其他硬件...

因此,您在68000上运行的代码将对问题部分产生巨大影响,最不可能的未来缓存未命中/页面错误"。

在此,您可以区分缓存未命中和页面错误,我不确定您正在参考哪个Coldfire架构,但我假设这没有硬件TLB替换,它使用软件mechansim(因此缓存将与应用程序的数据共享)。

在替换政策中,最重要的因素是关联(或方式)的数量。

直接映射高速缓存(1路),直接与地址的低位相关(最常用)(位数指定高速缓存的大小),因此32k高速缓存将是低15位。在这种情况下,替换algorthims LRU,FIFO或Random将是无用的,因为只有一种可能的选择。

然而,写入或写入选择缓存会产生更多效果。仅对内存进行写入写入意味着高速缓存行不被分配为与写回高速缓存相关联,其中当前在高速缓存中共享相同低15位的行从高速缓存中弹出并读回然后被修改,使用IF在CPU上运行的代码使用此数据。)

对于写入并且不对数据执行多个操作的操作,然后写入通常要好得多,在现代处理器上也是如此(我不知道这个架构是否支持它),但是Writethrough或Writeback可以在TLB / Page基础上选择。这可以对缓存产生比策略更大的影响,您可以对系统进行编程以匹配每个页面中的数据类型,尤其是在直接地图缓存中; - )

因此,直接地图缓存非常容易理解,它也很容易理解缓存的最坏情况,最佳情况和平均情况的基础。

想象一个memcpy例程,它复制与缓存大小对齐的数据。例如,32k直接映射缓存,在32k边界上对齐两个32k缓冲区....

0x0000 -> read
0x8000 -> write
0x8004 -> read
0x8004 -> write
...
0x8ffc -> read
0x8ffc -> write

在这里,您可以看到复制每个数据字时的读写操作,注意每个读写操作的低15位是相同的。

使用回写的直接映射缓存(记住回写分配行执行以下操作)

0x0000 -> read
 cache performs: (miss)
   0x0000:0x001f -> READ from main memory (ie. read 32 bytes of the source)

0x8000 -> write
  cache performs: (miss)
    invalidate 0x0000:0x001f (line 0)
    0x8000:0x801f -> READ from main memory (ie. read 32 bytes of the destination)
    0x8000           (modify this location in the cache with the read source data)

<loop>

0x0004 -> read
  cache performs: (miss)
    writeback 0x8000:0x801f -> WRITE to main memory (ie. write 32 bytes to the desitnation)
    0x0000:0x001f -> READ from main memory (ie. read 32 bytes of source (the same as we did just before)

0x8004 -> write
  cache performs: (miss)
    invalidate 0x0000:0x001f (line 0)
    0x8000:0x801f -> READ from main memory (ie. read 32 bytes of the destination)
    0x8004           (modify this location in the cache with the read source data)

</loop>  <--- (side note XML is not a language but we use it as such)

当你看到很多内存操作继续下去时,这实际上被称为&#34; thrashing&#34;并且是最坏情况scenairo的最好例子。

现在假设我们使用了一个写入缓存,这些是操作:

<loop>
0x0000 -> read
 cache performs: (miss)
   0x0000:0x001f -> READ from main memory (ie. read 32 bytes of the source)

0x8000 -> write
  cache performs: (not a miss)
   (not a lot, the write is "posted" to main memory) (posted is like a letter you just place it in the mailbox and you don't care if it takes a week to get there).

  <loop>

  0x0004 -> read
    cache performs: (hit)
      (not a lot, it just pulls the data it fetched last time which it has in it's memory so it goes very quickly to the CPU)

  0x8004 -> write
    cache performs: (not a miss)
     (not a lot, the write is "posted" to main memory)

  </loop until next 32 bytes>
</loop until end of buffer>

正如你所看到的那样,我们现在不会发生巨大变化,事实上我们在这个例子中是最好的。

好的,这就是写通和回写的简单案例。

然而,

直接映射缓存现在并不是大多数人使用的常见缓存,2,4或8路缓存,即一行中有2,4或8种不同的可能分配。所以我们可以在4路或8路缓存中同时在缓存中存储0x0000,0x8000,0x1000,0x1800(显然8路也可以存储0x2000,0x2800,0x3000,0x3800)。

这可以避免这种颠簸问题。

只是为了澄清32k直接映射缓存中的行号是地址的底部15位。 以32k 2的方式,它是最低的14位。 以32k 4的方式,它是最低的13位。 以32k 8的方式,它是最低的12位。

在完全关联的缓存中,它是行大小(或者是带有32字节行的底部5位)。你不能有一条线。 32字节通常是DDR内存系统中最优的操作(还有其他原因,有时16或有时64字节可能更好,1字节在algorthmic情况下是最佳的,让我们使用32作为&#39;很常见)

为了帮助理解LRU,FIFO和Random认为缓存是完全关联的,在32k 32字节行缓存中这是1024行。

随机替换策略会随机导致每1024次替换最坏情况(即命中率达到99.9%),无论是LRU还是FIFO,我都可以编写一个程序,该程序将会&&#34; thrash&#34;即。总是导致最坏情况的行为(即0%命中)。

显然,如果你有一个完全关联的缓存,你只能选择LRU或FIFO,如果该程序是已知的并且已知该程序的确切行为。

对于没有99.9%可预测的任何东西你会选择RANDOM,它只是最好的不是最差的,并且是最好的平均值之一,但最好的情况怎么样(我得到的地方)最好的表现)...

这主要取决于方式的数量......

两种方式,我可以优化像memcpy和其他algorthims这样的东西来做好工作。随机会在一半时间内弄错。 4种方式,当我在其他任务之间切换时,我可能不会破坏缓存,以至于他们的数据仍然是本地的。随机会让时间错误。 8种方式现在统计数据可以生效,memcpy的7/8%命中率不如1023/1024%(完全关联或优化的代码),但对于非优化代码,它会产生影响。

那么为什么人们不能通过随机替换政策制作完全关联的缓存!

好吧,不是因为它们无法生成好的随机数,实际上伪随机数生成器也同样好,是的,我可以编写一个程序来获得100%的未命中率,但这不是& #39;重点是,我无法编写一个有100%错过的有用程序,我可以使用LRU或FIFO算法。

一个32k 32字节的行全关联缓存要求你比较1024个值,在硬件中这是通过CAM完成的,但这是一个昂贵的硬件,而且它也是不可能的在&#34;快速&#34;中比较这许多值。处理时间,我想知道量子计算机能不能......

无论如何要回答你的问题哪一个更好:

  1. 考虑写作是否可能比回写更好。
  2. 大方的RANDOM更好
  3. 未知代码RANDOM适用于4种或更高版本。
  4. 如果它是单一功能,或者你想从你想要优化的东西中获得最大速度,或者你不关心最坏的情况,那么LRU可能就是你想要的。
  5. 如果您的方式很少,LRU可能就是您想要的,除非您有一个非常具体的场景,那么FIFO可能没问题。
  6. 参考文献:

答案 2 :(得分:2)

我研究的许多架构都使用LRU,因为它通常不仅提供了实现效率,而且在防止未命中方面也非常好。但是,在最新的x86架构中,我认为还有一些更复杂的事情在发生。 LRU是一种基本模型。

这实际上取决于您在设备上执行的操作类型。根据运营类型,不同的疏散政策将更好地运作。例如,FIFO可以顺序遍历内存。

希望这有帮助,我不是一个真正的建筑人。

答案 3 :(得分:2)

在三者之间,我推荐LRU。首先,当假定局部性时,它是对最优调度的良好近似(这证明是一个很好的假设)。随机调度不能从地方受益。其次,它不会受到Belady的异常(如FIFO)的影响;也就是说,更大的缓存意味着更好的性能,对于FIFO来说不一定如此。

只有当您的特定问题域强烈建议使用其他内容时,LRU才会在一般情况下难以击败。

答案 4 :(得分:2)

在这三者中,LRU通常是最好的,而FIFO是最差的,随机介于两者之间。您可以构建访问模式,其中三者中的任何一个都优于其他任何一个,但它有点棘手。有趣的是,这个订单大致也是它们实施的成本 - LRU是最昂贵的,而FIFO是最便宜的。只是去展示,没有免费的午餐

答案 5 :(得分:0)

如果您想要两全其美,请考虑采用自适应方法,根据实际使用模式改变策略。例如,查看算法IBM的Adaptive Replacement Cachehttp://code.activestate.com/recipes/576532-adaptive-replacement-cache-in-python/

相关问题