NUMA 記憶體效能¶
NUMA 區域性性¶
某些平臺可能連線了多種型別的記憶體到計算節點。這些不同型別的記憶體可能共享一些特性,例如 CPU 快取一致性,但效能可能不同。例如,不同的介質型別和匯流排會影響頻寬和延遲。
系統透過將每種記憶體型別根據區域性性和效能特性分組到不同的域或“節點”下,來支援這種異構記憶體。某些記憶體可能與 CPU 共享同一節點,而其他記憶體則作為純記憶體節點提供。雖然純記憶體節點不提供 CPU,但它們相對於其他節點,可能仍然與一個或多個計算節點區域性。下圖展示了兩個計算節點及其本地記憶體以及每個計算節點的純記憶體節點的一個示例。
+------------------+ +------------------+
| Compute Node 0 +-----+ Compute Node 1 |
| Local Node0 Mem | | Local Node1 Mem |
+--------+---------+ +--------+---------+
| |
+--------+---------+ +--------+---------+
| Slower Node2 Mem | | Slower Node3 Mem |
+------------------+ +--------+---------+
“記憶體發起方”(memory initiator)是包含一個或多個裝置(如 CPU 或獨立的記憶體 I/O 裝置)的節點,這些裝置可以發起記憶體請求。“記憶體目標”(memory target)是包含一個或多個物理地址範圍的節點,這些地址範圍可由一個或多個記憶體發起方訪問。
當存在多個記憶體發起方時,它們在訪問給定記憶體目標時可能不會都具有相同的效能。每個發起方-目標對可以被組織成不同的訪問類等級,以表示這種關係。訪問給定目標時效能最高的發起方被認為是該目標的本地發起方之一,並被賦予最高的訪問類,即 0。任何給定目標都可能有一個或多個本地發起方,任何給定發起方都可能擁有多個本地記憶體目標。
為了幫助應用程式將記憶體目標與其發起方匹配,核心提供了相互的符號連結。以下示例列出了訪問類“0”記憶體發起方和目標的關係:
# symlinks -v /sys/devices/system/node/nodeX/access0/targets/
relative: /sys/devices/system/node/nodeX/access0/targets/nodeY -> ../../nodeY
# symlinks -v /sys/devices/system/node/nodeY/access0/initiators/
relative: /sys/devices/system/node/nodeY/access0/initiators/nodeX -> ../../nodeX
一個記憶體發起方可以在同一訪問類中擁有多個記憶體目標。給定類中目標記憶體的發起方表明這些節點的訪問特性相對於其他連結的發起方節點共享相同的效能。然而,發起方訪問類中的每個目標之間不一定具有相同的效能。
訪問類“1”用於區分作為 CPU 因而適用於通用任務排程的發起方,以及 GPU 和網絡卡等 I/O 發起方。與訪問類 0 不同,只考慮包含 CPU 的節點。
NUMA 效能¶
應用程式可能希望根據節點的效能特性來決定從哪個節點分配記憶體。如果系統提供這些屬性,核心會將它們匯出到節點 sysfs 層級結構下,方法是在記憶體節點的訪問類 0 發起方下附加屬性目錄,如下所示:
/sys/devices/system/node/nodeY/access0/initiators/
這些屬性僅在透過連結到此訪問發起方的節點訪問時適用。
核心為本地發起方提供的效能特性匯出如下:
# tree -P "read*|write*" /sys/devices/system/node/nodeY/access0/initiators/
/sys/devices/system/node/nodeY/access0/initiators/
|-- read_bandwidth
|-- read_latency
|-- write_bandwidth
`-- write_latency
頻寬屬性以 MiB/秒為單位提供。
延遲屬性以納秒為單位提供。
此處報告的值對應於平臺的額定延遲和頻寬。
訪問類 1 具有相同的形式,但只包含 CPU 到記憶體活動的值。
NUMA 快取¶
系統記憶體可以構建成一個具有各種效能特性的分層結構,以便透過較小、效能較高的記憶體快取來提供較大、效能較低的記憶體的地址空間。記憶體發起方所感知的系統物理地址由層次結構中的最後一級記憶體提供。同時,系統使用效能較高的記憶體透明地快取對逐漸較慢級別的訪問。
“遠端記憶體”(far memory)一詞用於表示層次結構中的最後一級記憶體。每個增加的快取級別都提供更高效能的發起方訪問,“近端記憶體”(near memory)一詞代表系統提供的最快快取。
這種編號與 CPU 快取不同,CPU 快取(例如:L1、L2、L3)採用 CPU 側視角,每個增加的級別效能都較低。相比之下,記憶體快取級別以最後一級記憶體為中心,因此編號越高的快取級別對應於離 CPU 越近、離遠端記憶體越遠的記憶體。
記憶體側快取不能被軟體直接定址。當軟體訪問一個系統地址時,如果該地址存在於近端記憶體快取中,系統會從中返回資料。如果不存在,系統會訪問下一級記憶體,直到在該快取級別命中或到達遠端記憶體。
應用程式無需瞭解快取屬性即可使用系統。軟體可以選擇性地查詢記憶體快取屬性,以最大化此類設定的效能。如果系統提供了一種讓核心發現此資訊的方式,例如透過 ACPI HMAT(異構記憶體屬性表),核心會將這些屬性附加到 NUMA 節點記憶體目標。
當核心首次將記憶體快取註冊到節點時,核心將建立以下目錄:
/sys/devices/system/node/nodeX/memory_side_cache/
如果該目錄不存在,則系統要麼不提供記憶體側快取,要麼該資訊對核心不可訪問。
每個快取級別的屬性都在其快取級別索引下提供:
/sys/devices/system/node/nodeX/memory_side_cache/indexA/
/sys/devices/system/node/nodeX/memory_side_cache/indexB/
/sys/devices/system/node/nodeX/memory_side_cache/indexC/
每個快取級別的目錄都提供其屬性。例如,以下顯示了一個單一快取級別以及可供軟體查詢的屬性:
# tree /sys/devices/system/node/node0/memory_side_cache/
/sys/devices/system/node/node0/memory_side_cache/
|-- index1
| |-- indexing
| |-- line_size
| |-- size
| `-- write_policy
如果快取是直接對映快取,則“indexing”為 0;對於任何其他基於索引的多路關聯性,則為非零值。
“line_size”是指在未命中時從下一快取級別訪問的位元組數。
“size”是指此快取級別提供的位元組數。
“write_policy”對於寫回(write-back)快取為 0,對於寫穿(write-through)快取為非零。
另請參閱¶
[1] https://www.uefi.org/sites/default/files/resources/ACPI_6_2.pdf - 第 5.2.27 節