Linux 核心101:cache原理

liaochangjiang發表於2019-04-19

本文參考了:

簡述

相信你肯定對這一張圖很熟悉了(如果還是第一次聽說就請關掉此頁面吧:))。越靠近 CPU,速度越快,但是容量小且價格昂貴。如何能夠高效利用快取(LEVEL 1),是作業系統中非常重要的一環。

Linux 核心101:cache原理

上篇文章中,我們有講到同一個 CPU 中的 core 之間會對 last-level cache產生競爭,從而影響系統效能。UMA 架構下,假如一個 CPU 裡面有多個 threads 執行在不同 core 中,可以將其中一個 core 上的 thread 移動到其他核,從而緩解了對 last-level cahce 的競爭,達到提高速度的目的(我們也講了這種方法在 NUMA 架構中不適用,具體原因請看上篇文章)。

Last-level cache 競爭給效能帶來影響的原因是顯而易見的,因為 cahce 大小有限,其中一個 thread 佔據一部分 cache,很有可能是會把其他 cache 的擠佔掉的。這種現象是 cache miss中的一種。cache miss 的大小是衡量快取效率的重要指標。

此篇文章將先講講 cache 一些基礎的知識,後面再逐步深入。

Direct Mapped Cache

下圖中,main memory 有16個 bytes,cache 有4個 bytes。

Linux 核心101:cache原理

簡單來講,就是把main memory 中的 0,4,8,12對映到 cache 的0;1,5,9,13對映到 cache 的2… 對,就是取模運算。這回答了我們的第一個問題。

這種方法叫做Direct Mapped Cache,是最簡單的一種 map方法,效率也不是最高的,還有幾種可以通過以下連結檢視 : en.wikipedia.org/wiki/Cache_…

如果要是複雜點,可以看下維基百科上的這張圖,原地址如下: en.wikipedia.org/wiki/Cache_…

Linux 核心101:cache原理

從 cache 中讀資料

用上面的方法,可以很容易知道 main memory 某個 byte 的資料在 cache 的什麼位置,但是要知道有很多個不同的 block 指向cache 裡同一個位置。

可以把 main memory 的最高位作為 tag,存在cache 裡面,如圖:

Linux 核心101:cache原理

這樣,比如cache 中一個 entry 的 index 為01,他的 tag 為11,對應的 main memory 地址就是tag + index,即1101

Linux 核心101:cache原理

再進一步,加上一個 valid bit,用來表示該 cache block是否是合法的。

  • 最開始的時候,cache 是空的,所以這個 bit 都是0.
  • 當有資料被 load 到這個 block 的時候,這個 bit 就變成了1.

Linux 核心101:cache原理

cache hit 的時候會發生什麼?

我們已經知道該如何通過 main memory 的地址從 cache 中找資料了,如果正如我們所意,確實成功在 cache 中獲取到了,這一段發生了什麼呢?

當 CPU 需要從 memory 中read 資料的時候,地址會傳送給 cache controller:

  • address 的最低幾位會對應到 cache 中的某個 block
  • 如何 valid bit 是1,且tag 位是匹配的,就說明cache 成功 hit 了,就可以把data 返回給 CPU 了

如下圖:

Linux 核心101:cache原理

cache miss 的時候會發生什麼?

CPU 從cache 中獲取資料可以達到 ns 級,如果是 cache miss 了,就得先把main memory 的資料load 到 cache。 現在 data 已經從 main memory 中讀取到了,通過以下步驟load 到 cache:

  • 低位的 k 位指定了cache block的位置
  • 高位的(m-k)位存在 cache block 的tag 位
  • main memory 的 data 資料拷貝到 cache 的 data field
  • 將 valid bit 置為1

如圖:

Linux 核心101:cache原理

再講講cache miss

首先 cache miss 相比 cache hit 的效能差異是數量級的,應該儘可能減少 cache miss 的機率。cache miss 有很多種原因,這裡講最主要的兩種,詳細列表請看: en.wikipedia.org/wiki/Cache_…

  • 無法避免的 miss:所有的 cache 最開始肯定都是不在 cache 中的,所以這必然需要先從 main memory 中 load 進來。(除非試用 prefetch: en.wikipedia.org/wiki/Cache_…
  • 衝突導致 miss:這種 miss 之前該資料已經在 cache 裡面,但是被另外的程式搶佔了。(回顧一下上篇文章講的 last-level cache 競爭~這種可以通過排程來解決)

Spatial locality

前面都是一個 byte 為一個 block 的。我們有一個這樣的假設,訪問一個 address,下一次訪問很有可能會訪問臨近的某一個 address。這個假設大多數情況下都是正確的。這個假設就叫做Spatial locality,那該如何實現這種假設?可以增加每個block的大小。

Linux 核心101:cache原理

現在將每個 cache block 的大小設定為2個 bytes,於是我們就可以一次性 load 兩個 bytes 的資料。當我們要 load 位置12的資料到 cache 的時候,同時也會把位置13的也 load 過去。

這時候,可以把 main memory 也劃分成兩個 byte 一個 block。byte address 和 block address 的對應關係也很簡單,0和1對應一個 block address:0

Linux 核心101:cache原理

匯入 cache 的過程也很之前一樣,沒什麼好贅述的:現在從 main memory 中 load 第12或者第13個byte,都會同時12,13這兩個 byte load 過去。

Linux 核心101:cache原理

總結

Cache資源對於整個系統效能的影響巨大,關於如何設計 cache,排程 cache 資源的方法、論文層出不窮。此文講的Direct Mapped Cache是最最簡單的,但是對於我們理解 cache 有很大幫助。後面我們還會繼續深入學習一下 cache。

最後,gakki 式求贊~

Linux 核心101:cache原理

Linux 核心101:cache原理

廣告時間,歡迎大家關注我的微信公眾號。同時本文同步於 github: github.com/liaochangji…

Linux 核心101:cache原理

相關文章