2014-09-20 45 views
3

爲什麼在Linux中,許多結構使用____cacheline_aligned_in_smp宏?它是否有助於在訪問結構時提高性能?如果是,那麼如何?____cacheline_aligned_in_smp用於linux中的結構

+0

它減少了必須由SMP系統中的緩存監聽邏輯進行同步的緩存行數。 – 2014-09-20 10:56:30

+0

Hi Paul, 我找到了一個解釋: 它是一個擴展到__attribute__(gcc擴展名)的宏,它要求在L1緩存行大小的整數倍地址處分配這樣聲明的變量。 http://vivekbhadra.wordpress.com/article/linux-cacheline-aligned-in-smp-macro-3c84lj4klzp0d-15/ 這是正確的嗎? – 2014-09-22 15:50:07

+0

對不起,是的,我認爲這是一個給定的 - 一般的想法是,通過將分配與緩存行對齊,可以最大限度地減少緩存佔用量,從而最大限度地減少SMP系統中的緩存監聽流量。 – 2014-09-22 16:13:45

回答

0

任何緩存(dcache或icache)中的每個緩存行都是64字節(x86)體系結構。需要高速緩存對齊以避免高速緩存行的虛假分頁。如果全局變量之間共享高速緩存行(在內核中發生更多)如果其中一個全局變量被其高速緩存中的一個處理器更改,那麼它將該高速緩存行標記爲髒。在剩餘的CPU cahce行中,它變成陳舊的條目。哪些需要刷新並從內存中重新獲取。這可能會導致緩存行未命中。這需要更多的CPU週期。這降低了系統的性能。請記住這是針對golabl變量的。大多數內核數據結構使用這種方法來避免緩存行未命中。

0

Linux以與TLB非常相似的方式管理CPU緩存。像TLB緩存一樣,CPU緩存利用了這樣一個事實,即程序往往表現出一個參考的地方。爲了避免爲每個引用從主內存中獲取數據,CPU將緩存CPU緩存中非常少量的數據。通常,有兩個級別稱爲級別1和級別2 CPU高速緩存。二級CPU緩存較大,但比一級緩存慢,但Linux只關心一級或一級緩存。

CPU高速緩存被組織成行。每行通常很小,通常是32個字節,每行對齊到它的邊界大小。換句話說,32字節的高速緩存行將在32字節地址上對齊。使用Linux時,該行的大小爲每個體系結構定義的L1_CACHE_BYTES

地址如何映射到高速緩存行結構之間不同,但都映射在三個標題下,直接映射關聯映射組相聯映射。直接映射是最簡單的方法,其中每個內存塊只映射到一個可能的緩存行。通過關聯映射,任何內存塊都可以映射到任何緩存行。集合關聯映射是一種混合方法,其中任何內存塊都可映射到任何行,但只能映射到可用行的子集內。

無論映射方案如何,它們每個都有一個共同點,那些靠近在一起並與高速緩存大小對齊的地址可能使用不同的行。因此,Linux的採用簡單的技巧,試圖最大限度地提高緩存使用率

  • 經常訪問的結構域是在 結構,以增加只有一行是需要 地址的共同領域的機會的開始;
  • 結構中不相關的項目應該嘗試 至少爲高速緩存大小字節,以避免 CPU之間的虛假共享;
  • 一般高速緩存中的對象(如mm_struct高速緩存)爲 ,與L1 CPU高速緩存對齊以避免錯誤共享。

如果CPU引用不在高速緩存中的地址,則會發生高速緩存未命中並從主內存中獲取數據。高速緩存未命中的成本相當高,因爲對高速緩存的引用通常可以在小於10ns內執行,其中對主存儲器的引用通常將花費在100ns和200ns之間。基本目標是儘可能多的緩存命中和儘可能少的緩存未命中。

正如一些體系結構不會自動管理它們的TLB一樣,有些不會自動管理它們的CPU高速緩存。掛鉤放置在虛擬到物理映射更改的位置,例如在頁面表更新期間。 CPU高速緩存刷新應始終首先發生,因爲某些CPU在虛擬地址從高速緩存刷新時需要存在虛擬物理映射。

更多信息here

2

____cacheline_aligned指示編譯器實例化在對應於L1高速緩存行的開頭的地址的結構或變量,對於特定的體系結構,即,使得它是L1高速緩存線對齊。 ____cacheline_aligned_in_smp是類似的,但實際上只有在內核以SMP配置編譯時(即,使用選項CONFIG_SMP)進行L1高速緩存行對齊。這些定義在文件include/linux/cache.h中。

這些定義對於未通過某個分配器動態分配,而是通過全局編譯器分配的變量進行分配的變量(和數據結構)很有用(類似的效果可以可以通過動態內存分配器完成,這些內存分配器可以按特定的對齊方式分配內存)

緩存行對齊變量的原因是在SMP系統中通過硬件緩存一致性機制來管理這些變量的緩存到緩存傳輸,以便在移動其他變量時不會隱含地發生它們的移動。這是針對性能嚴重的代碼,其中人們期望爭用多個cpus(核心)訪問變量。在這種情況下,人們試圖避免的常見問題是虛假分享。

從緩存行開始處開始的變量內存是此目的的一半;一個也需要「包裝它」只有應該一起移動的變量。一個例子是一個變量數組,數組的每個元素是由只有一個CPU(核心)來訪問:

struct my_data { 
    long int a; 
    int b; 
} ____cacheline_aligned_in_smp cpu_data[ NR_CPUS ]; 

這種定義的將需要從編譯器(在內核的SMP配置)每個cpu的結構將從緩存線邊界開始。編譯器會隱式地在每個cpu的結構之後分配額外的空間,以便下一個cpu的結構也將從高速緩存行邊界開始。

一種替代方法是墊的數據結構與虛設的高速緩存行的大小,未使用的字節:

struct my_data { 
    long int a; 
    int b; 
    char dummy[L1_CACHE_BYTES]; 
} cpu_data[ NR_CPUS ]; 

在這種情況下,只有虛設的,未使用的數據將被無意地移動,並且那些實際上由每個CPU訪問由於緩存容量未命中,將只從緩存移到內存,反之亦然。

+0

好解釋:) – 2016-03-24 05:09:41