每CPU頁框快取記憶體

2021-05-21 17:58:52 字數 2699 閱讀 4344

在「linux頁框級記憶體管理處理細節」一篇博文中,我們談到核心呼叫alloc_pages等系列函式分配乙個或一片連續的頁框。這一系列函式本質上是使用夥伴演算法從指定zone_t中取到乙個或一片連續的空閒的頁框。

正如我們將在以後重點博文「slab分配器」所看到的,核心經常請求和釋放單個頁框。為了提公升系統效能,如果請求單個或釋放單個頁框時,核心在使用夥伴演算法之前多添了乙個步驟,即每cpu頁框快取記憶體。

每個記憶體管理區定義了乙個「每cpu」頁框快取記憶體,所有「每cpu」快取記憶體包含一些預先分配的頁框,它們被用於滿足本地cpu 發出的單個頁記憶體請求。

更進一步,核心為每個記憶體管理區和每個cpu提供了兩個快取記憶體:乙個熱快取記憶體,它存放的頁框中所包含的內容很可能就在cpu 硬體快取記憶體中;還有乙個冷快取記憶體。

如果核心或使用者態程序在剛分配到頁框後就立即向頁框寫,那麼從熱快取記憶體中獲得頁框就對系統效能有利。什麼意思?我們知道,cpu中的硬體快取記憶體存在有最近使用過的頁框。而我們每次對頁框儲存單元的訪問將都會導致原來乙個存在於硬體快取記憶體的一頁被替換掉。當然,除非硬體快取記憶體包含有一行:它對映剛被訪問的 「熱」頁框單元,那麼我們稱為「命中」。

反過來,如果頁框將要被dma操作填充,那麼從冷快取記憶體中獲得頁框是方便的。在這種情況下, 不會涉及到cpu,並且硬體快取記憶體的行不會被修改。從冷快取記憶體獲得頁框為其他型別的記憶體分配儲存了熱頁框儲備。

如果實在理解不了上面對熱快取和冷快取的定義,那我們就乾脆這樣理解:熱快取跟cpu有關,要使用到對應cpu的快取記憶體,當我們讀寫乙個頁面時,如果沒有命中硬體快取記憶體就替換乙個頁;冷快取跟cpu無關,當我們讀寫乙個頁面時根本不去管有沒有命中cpu的硬體快取。

實現每cpu頁框快取記憶體的主要資料結構是存放在記憶體管理區描述符zone_t的pageset欄位中的乙個per_cpu_pageset陣列資料結構。該陣列包含為每個cpu 提供的乙個元素;這個元素依次由兩個per_cpu_pages描述符組成,乙個留給熱快取記憶體而另乙個留給冷快取記憶體。

具體資料結構如圖所示:

核心使用兩個位標來監視熱快取記憶體或冷快取記憶體的大小:如果頁框個數低於下界low,核心通過從夥伴系統中分配batch個單一頁框來補充對應的快取記憶體;否則,如果頁框個數高過上界high,核心從快取記憶體中釋放batch個頁框到夥伴系統中。值batch、low和high本質上取決於記憶體管理區中包含的頁框個數。

buffered_rmqueue()函式在指定的記憶體管理區中分配頁框。它使用每cpu頁框快取記憶體來處理單一頁框請求。

引數為記憶體管理區描述符的位址,請求分配的記憶體大小的對數order,以及分配標誌gfp_flags。如果gfp_flags中的_ _gfp_cold標誌被置位,那麼頁框應當從冷快取記憶體中獲取,否則它應從熱快取記憶體中獲取(此標誌只對單一頁框請求有意義)。該函式本質上執行如下操作:

1.    如果order 不等於0,每cpu 頁框快取記憶體就不能被使用:函式跳到第4 步。

2.    檢查由_ _gfp_cold標誌所標識的記憶體管理區本地每cpu 快取記憶體是否需要補充(per_cpu_pages描述符的count欄位小於或等於low欄位)。在這種情況下,它執行如下子步驟:

a)    通過反覆呼叫_ _rmqueue()函式從夥伴系統中分配batch 個單一頁框。

b)    將已分配頁框的描述符插入快取記憶體鍊錶中。

c)    通過給count 增加實際被分配頁框的個數來更新它。

3.    如果count值為正,則函式從快取記憶體鍊錶獲得乙個頁框,count 減1 並跳到第5步。(注意,每cpu 頁框快取記憶體有可能為空,當在第2a 步調用_ _rmqueue()函式而分配頁框失敗時就會發生這種情況。)

4.    到這裡,記憶體請求還沒有被滿足,或者是因為請求跨越了幾個連續頁框,或者是因為被選中的頁框快取記憶體為空。呼叫_ _rmqueue()函式從夥伴系統中分配所請求的頁框。

5.    如果記憶體請求得到滿足,函式就初始化(第乙個)頁框的頁描述符:清除一些標誌,將private 欄位置0,並將頁框引用計數器置1。此外,如果gfp_flags 中的_ _gpf_zero 標誌被置位,則函式將被分配的記憶體區域填充0。

6.    返回(第乙個)頁框的頁描述符位址,如果記憶體分配請求失敗則返回null。

為了釋放單個頁框到每cpu 頁框快取記憶體,核心使用free_hot_page ( ) 和free_cold_page()函式。它們都是free_hot_cold_page()函式的簡單封裝,接收的引數為將要釋放的頁框的描述符位址page和cold標誌(指定是熱快取記憶體還是冷快取記憶體)。

free_hot_cold_page()函式執行如下操作:

1.    從page->flags 字段獲取包含該頁框的記憶體管理區描述符位址。

2.    獲取由cold 標誌選擇的管理區快取記憶體的per_cpu_pages 描述符的位址。

3.    檢查快取記憶體是否應該被清空:如果count值高於或等於high,則呼叫free_pages_bulk()函式,將管理區描述符、將被釋放的頁框個數(batch欄位)、快取記憶體鍊錶的位址以及數字0(為0 到order 個頁框)傳遞給該函式。free_pages_bulkl()函式依次反覆呼叫_ _free_pages_bulk()函式來釋放指定數量的(從快取記憶體鍊錶獲得的)頁框到記憶體管理區的夥伴系統中。

4.    把釋放的頁框新增到快取記憶體鍊錶上,並增加count 字段。

應該注意的是,在當前的linux 2.6核心版本中,從沒有頁框被釋放到冷快取記憶體中:至於硬體快取記憶體,核心總是假設被釋放的頁框是熱的。當然,這並不意味著冷快取記憶體是空的:當達到下界時通過buffered_rmqueue()補充冷快取記憶體。

7每CPU頁框快取記憶體

在 linux頁框級記憶體管理處理細節 一篇博文中,我們談到核心呼叫alloc pages等系列函式分配乙個或一片連續的頁框。這一系列函式本質上是使用夥伴演算法從指定zone t中取到乙個或一片連續的空閒的頁框。正如我們將在以後重點博文 slab分配器 所看到的,核心經常請求和釋放單個頁框。為了提公...

CPU快取記憶體行

cpu 為了更快的執行 於是當從記憶體中讀取資料時,並不是唯讀自己想要的部分。而是讀取足夠的位元組來填入快取記憶體行。根據不同的 cpu,快取記憶體行大小不同。如 x86是 32bytes 而alpha 是64bytes 並且始終在第 32個位元組或第 64個位元組處對齊。這樣,當 cpu訪問相鄰的...

總結 CPU快取記憶體

我們都知道,程式是由一條條指令和資料組成的,cpu在執行時的工作也是周而復始的執行一條條用途各異的指令。在一開始,程式載入到主存,在程式執行的過程中,將指令一條條的從主存中取出並執行,巨集觀上來說我們把主存看做是乙個很大的一維位元組陣列,位址即可看作為陣列的下標。這樣的結構可以確保程式可以順利執行。...