国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Linux 內核是如何感知到硬件上的 NUMA 信息的?

系統 Linux
在現代服務器的非統一內存訪問(NUMA)是一種用于多處理器硬件架構下,識別和保存每個 CPU 核和內存條之間的連接拓撲非常的重要。因為 CPU 只是和它直連的內存訪問速度最快,訪問和其它 CPU 連接的內存速度將會大大下降。

在 Linux 程序運行過程中,有一個對性能影響較大的特性,那就是 NUMA。在不少公司中,都通過 numactl 等命令對運行的服務進行了 NUMA 綁定,進而提高程序的運行性能。

那么我們今天來深入了解一下 NUMA 的原理。在硬件上的 NUMA 組成為什么會影響程序的運行性能,Linux 操作系統又是如何識別 NUMA 信息,來將 CPU 和內存進行分組劃分 node 的。

一、NUMA 介紹

NUMA 全稱是 Non-uniform memory access,是非一致性內存訪問的意思。不過這段話還是由點費解,我們需要看看硬件才能更好地理解它。

現代的 CPU 都在硬件內部實現了一個內存控制器,內存條都會和這個內存控制器進行相連。

圖片圖片

之前我們在 深入了解服務器 CPU 的型號、代際、片內與片間互聯架構 一文中提到過,服務器 CPU 和個人 PC CPU 的一個很大的區別就是擴展性。在一臺服務器的內部是支持插2/4/8等多 CPU 的。每個 CPU 都可以連接幾條的內存。兩個 CPU 之間如果想要訪問對方上連接的內存條,中間就得跨過 UPI 總線。

圖片圖片

下面是一臺服務器的實際內部圖片。中間兩個銀色長方形的東東是罩著散熱片的 CPU,每個 CPU 旁邊都有一些內存插槽,支持插入多條內存。

圖片圖片

CPU 擴展性的設計極大地提升了服務器上的 CPU 核數與內存容量。但同時也帶來了另外一個問題,那就是 CPU 物理核在訪問不同的內存條的時候延遲是不同的。這就是非一致性內存訪問的含義。

其實不僅僅是跨 CPU 訪問存在延時差異。在服務器高核心 CPU 上,由于 Mesh 架構、以及存在兩個內存控制器,物理核訪問不同的內存控制器上的內存條也會有差異。只不過這個差異沒有跨 CPU 差異大。

這種問題的出現使得 Linux 操作系統不得不關注內存訪問速度不平均的問題。你在 Linux 上執行 numactl 命令可以查看你機器上的 NUMA 配置情況。拿我手頭的一臺虛擬機來舉例。

# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3
node 0 size: 7838 MB
node 0 free: 6208 MB
node 1 cpus: 4 5 6 7
node 1 size: 7934 MB
node 1 free: 6589 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

上面的輸出中展示了 Linux 把所有的 CPU 核心和內存分成了兩個 node。其中 node 0 中的擁有的 CPU 核心是 0、1、2、3 這四個核,總共擁有 7838 MB 的內存。node 1 中擁有的核心是 4、5、6、7 四個核,擁有的內存是 7934 MB。

另外 node distances 這里顯示了跨 node 進行內存訪問時一個大概的延時差距。同 node 內部的內存訪問肯定是最快的,跨 node 則相對較慢。

那么內核是如何識別到底層的 NUMA 信息的呢?

二、Linux 對 NUMA 信息的讀取

2.1 Linux 內核識別如何識別內存屬于哪個節點

在計算機的體系結構中,除了操作系統和硬件外,其實中間還存在著一層固件,英文名叫 firmware。它是位于主板上的使用 SPI Nor Flash 存儲著的軟件。起著在硬件和操作系統中間承上啟下的作用。它負責著硬件自檢、初始化硬件設備、加載操作系統引導程序,并提供接口將控制權轉移到操作系統。

圖片圖片

回到我們今天的話題。那么 CPU 和內存條之間這種訪問非一致性特點,Linux 就是通過固件來獲得這個知識的。其中在 Linux 和固件中間的接口規范是 ACPI(Advanced Configuration and Power Interface),高級配置和電源接口。

這是較新的 6.5 版本的文檔地址: https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf。感興趣的同學可以下載下來。

在這個接口規范中的第 17 章中描述了 NUMA 相關的內容。在 ACPI 中定義了兩個表,分別是:

  • SRAT(System Resource Affinity Table)。在這個表中表示的是 CPU 核和內存的關系圖。包括有幾個 node,每個 node 里面有那幾個 CPU 邏輯核,有哪些內存。
  • SLIT(System Locality Information Table)。在這個表中記錄的是各個結點之間的距離。

有了這個規范,CPU 讀取這兩個表就可以獲得 NUMA 系統的 CPU 及物理內存分布信息。操作系統在啟動的時候會執行 start_kernel 這個核心函數,然后會調用到

//file:arch/x86/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
 ...
// 保存物理內存檢測結果
 e820__memory_setup();
 ...

// membloc內存分配器初始化
 e820__memblock_setup();

// 內存初始化(包括 NUMA 機制初始化)
 initmem_init();
}

在 setup_arch 中顯示調用了 e820__memory_setup 來保存物理內存檢測結果。然后調用 e820__memblock_setup 初始化內存分配器。詳情參見Linux 內核“偷吃”了你的內存! 一文。在 initmem_init 完成了 NUMA 的初始化。

在 initmem_init 中,依次調用了 x86_numa_init、numa_init、x86_acpi_numa_init,最后執行到了 acpi_numa_init 函數中來讀取 ACPI 中的 SRAT 表,獲取到各個 node 中的 CPU 邏輯核、內存的分布信息。

//file:drivers/acpi/numa/srat.c
int __init acpi_numa_init(void)
{
 ...
 // 解析 SRAT 表中的 NUMA 信息
 // 具體包括:CPU_AFFINITY、MEMORY_AFFINITY 等
 if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
  ...
 }
 ...
}

在 SRAT 表讀取并解析完成后,Linux 操作系統就知道了內存和 node 的關系了。numa 信息都最后保存在了 numa_meminfo 這個數據結構中,這是一個全局的列表,每一項都是(起始地址, 結束地址, 節點編號)的三元組,描述了內存塊與 NUMA 節點的關聯關系。

//file:arch/x86/mm/numa.c
static struct numa_meminfo numa_meminfo __initdata_or_meminfo;

//file:arch/x86/mm/numa_internal.h
struct numa_meminfo {
 int   nr_blks;
 struct numa_memblk blk[NR_NODE_MEMBLKS];
};

2.2 memblock 分配器 關聯 NUMA 信息

在此之后,Linux 就可以通過 numa_meminfo 數組來獲取硬件 NUMA 信息了。前面在 一文中我們提到了內核的 memblock 內存分配器。有了 numa_meminfo 數組,memblock 就可以根據這個信息讀取到自己各個 region 分別是屬于哪個 node 的了。

這件工作是在 numa_init 中開始的。

//file:arch/x86/mm/numa.c
static int __init numa_init(int (*init_func)(void))
{
 ...

//2.1 把numa相關的信息保存在 numa_meminfo 中
 init_func();

//2.2 memblock 添加 NUMA 信息,并為每個 node 申請對象
 numa_register_memblks(&numa_meminfo);

 ...
// 用于將各個CPU core與NUMA節點關聯
 numa_init_array();
return0;
}

在 numa_register_memblks 中完成了三件事情

  • 將每一個 memblock region 與 NUMA 節點號關聯
  • 為每一個 node 都申請一個表示它的內核對象(pglist_data)
  • 再次打印 memblock 信息
//file:arch/x86/mm/numa.c
static int __init numa_register_memblks(struct numa_meminfo *mi)
{
 ...
//1.將每一個 memblock region 與 NUMA 節點號關聯
for (i = 0; i < mi->nr_blks; i++) {
struct numa_memblk *mb = &mi->blk[i];
  memblock_set_node(mb->start, mb->end - mb->start,
      &memblock.memory, mb->nid);
 }
 ...
//2.為所有可能存在的node申請pglist_data結構體空間 
 for_each_node_mask(nid, node_possible_map) {
  ...
//為nid申請一個pglist_data結構體
  alloc_node_data(nid);
 }

//3.打印MemBlock內存分配器的詳細調試信息
 memblock_dump_all();
}

這個函數的詳細邏輯就不展開了。我們來看下 memblock_dump_all。如果你開啟了 memblock=debug 啟動參數,在它執行完后,memblock 內存分配器的信息再次被打印了出來。

[    0.010796] MEMBLOCK configuration:
[    0.010797]  memory size = 0x00000003fff78c00 reserved size = 0x0000000003d7bd7e
[    0.010797]  memory.cnt  = 0x4
[    0.010799]  memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x0
[    0.010800]  memory[0x1] [0x0000000000100000-0x00000000bffd9fff], 0x00000000bfeda000 bytes on node 0 flags: 0x0
[    0.010801]  memory[0x2] [0x0000000100000000-0x000000023fffffff], 0x0000000140000000 bytes on node 0 flags: 0x0
[    0.010802]  memory[0x3] [0x0000000240000000-0x000000043fffffff], 0x0000000200000000 bytes on node 1 flags: 0x0
[    0.010803]  reserved.cnt  = 0x7
[    0.010804]  reserved[0x0] [0x0000000000000000-0x00000000000fffff], 0x0000000000100000 bytes on node 0 flags: 0x0
[    0.010806]  reserved[0x1] [0x0000000001000000-0x000000000340cfff], 0x000000000240d000 bytes on node 0 flags: 0x0
[    0.010807]  reserved[0x2] [0x0000000034f31000-0x000000003678ffff], 0x000000000185f000 bytes on node 0 flags: 0x0
[    0.010808]  reserved[0x3] [0x00000000bffe0000-0x00000000bffe3d7d], 0x0000000000003d7e bytes on node 0 flags: 0x0
[    0.010809]  reserved[0x4] [0x000000023fffb000-0x000000023fffffff], 0x0000000000005000 bytes flags: 0x0
[    0.010810]  reserved[0x5] [0x000000043fff9000-0x000000043fffdfff], 0x0000000000005000 bytes flags: 0x0
[    0.010811]  reserved[0x6] [0x000000043fffe000-0x000000043fffffff], 0x0000000000002000 bytes on node 1 flags: 0x0

不過這次不同的是,每一段內存地址范圍后面都跟上了 node 的信息,例如 on node 0、on node 1 等。

三、操作系統內存識別過程總結

在剛開始操作系統啟動的時候,操作系統通過 e820 讀取到了內存的布局,并將它打印到了日志中。

[    0.000000] BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bffd9fff] usable
[    0.000000] BIOS-e820: [mem 0x00000000bffda000-0x00000000bfffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000feff4000-0x00000000feffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000043fffffff] usable

接著內核創建了 memblock 內存分配器來進行系統啟動時的內存管理。如果開啟了 memblock=debug 啟動參數,同樣能把它打印出來。

[    0.010238] MEMBLOCK configuration:
[    0.010239]  memory size = 0x00000003fff78c00 reserved size = 0x0000000003c6d144
[    0.010240]  memory.cnt  = 0x3
[    0.010241]  memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes flags: 0x0
[    0.010243]  memory[0x1] [0x0000000000100000-0x00000000bffd9fff], 0x00000000bfeda000 bytes flags: 0x0
[    0.010244]  memory[0x2] [0x0000000100000000-0x000000043fffffff], 0x0000000340000000 bytes flags: 0x0
[    0.010245]  reserved.cnt  = 0x4
[    0.010246]  reserved[0x0] [0x0000000000000000-0x0000000000000fff], 0x0000000000001000 bytes flags: 0x0
[    0.010247]  reserved[0x1] [0x00000000000f5a40-0x00000000000f5b83], 0x0000000000000144 bytes flags: 0x0
[    0.010248]  reserved[0x2] [0x0000000001000000-0x000000000340cfff], 0x000000000240d000 bytes flags: 0x0
[    0.010249]  reserved[0x3] [0x0000000034f31000-0x000000003678ffff], 0x000000000185f000 bytes flags: 0x0

不過到這里,Linux 操作系統還不知道內存的 NUMA 信息。它通過 ACPI 接口讀取固件中的 SRAT 表,將 NUMA 信息保存到 numa_meminfo 數組中。從此,Linux 就知道了硬件上的 NUMA 信息,并對 memblock 內存分配器也設置了 node 信息。并再次將其打印了出來。這次 memblock 的每一個 region 中就都攜帶了 node 信息。

[    0.010796] MEMBLOCK configuration:
[    0.010797]  memory size = 0x00000003fff78c00 reserved size = 0x0000000003d7bd7e
[    0.010797]  memory.cnt  = 0x4
[    0.010799]  memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x0
[    0.010800]  memory[0x1] [0x0000000000100000-0x00000000bffd9fff], 0x00000000bfeda000 bytes on node 0 flags: 0x0
[    0.010801]  memory[0x2] [0x0000000100000000-0x000000023fffffff], 0x0000000140000000 bytes on node 0 flags: 0x0
[    0.010802]  memory[0x3] [0x0000000240000000-0x000000043fffffff], 0x0000000200000000 bytes on node 1 flags: 0x0
[    0.010803]  reserved.cnt  = 0x7
[    0.010804]  reserved[0x0] [0x0000000000000000-0x00000000000fffff], 0x0000000000100000 bytes on node 0 flags: 0x0
[    0.010806]  reserved[0x1] [0x0000000001000000-0x000000000340cfff], 0x000000000240d000 bytes on node 0 flags: 0x0
[    0.010807]  reserved[0x2] [0x0000000034f31000-0x000000003678ffff], 0x000000000185f000 bytes on node 0 flags: 0x0
[    0.010808]  reserved[0x3] [0x00000000bffe0000-0x00000000bffe3d7d], 0x0000000000003d7e bytes on node 0 flags: 0x0
[    0.010809]  reserved[0x4] [0x000000023fffb000-0x000000023fffffff], 0x0000000000005000 bytes flags: 0x0
[    0.010810]  reserved[0x5] [0x000000043fff9000-0x000000043fffdfff], 0x0000000000005000 bytes flags: 0x0
[    0.010811]  reserved[0x6] [0x000000043fffe000-0x000000043fffffff], 0x0000000000002000 bytes on node 1 flags: 0x0

以上就是 Linux 內存中 NUMA 機制的初始化大概過程。

總結

在現代服務器的非統一內存訪問(NUMA)是一種用于多處理器硬件架構下,識別和保存每個 CPU 核和內存條之間的連接拓撲非常的重要。因為 CPU 只是和它直連的內存訪問速度最快,訪問和其它 CPU 連接的內存速度將會大大下降。

Linux 通過固件讀取 ACPI 規范中的 SRAT 和 SLIT 表識別 NUMA 信息,在系統啟動過程中,經一系列函數調用完成 NUMA 初始化,將信息保存到numa_meminfo,并使 memblock 分配器關聯 NUMA 信息。最后通過 e820 讀取內存布局,再結合 ACPI 獲取的 NUMA 信息完成內存識別及相關設置。

當內核有了硬件 NUMA 信息的拓撲圖后,我們在應用側就可以通過 numactl 等命令來優化程序的性能了!

不過最后要補充說一點,關于 NUMA 綁定并不是有益無害。在業界也有不同的聲音。比如 Oracal 的技術大咖們認為綁定 NUMA 可能在全局內存并未用盡的情況下出現內存分配錯誤,導致系統出現劇烈抖動。

責任編輯:武曉燕 來源: 開發內功修煉
相關推薦

2019-08-05 13:40:52

LinuxUbuntu硬件規格

2018-10-10 14:02:30

Linux系統硬件內核

2024-12-31 10:47:10

2009-09-25 10:48:07

Linux硬件信息操作系統

2009-03-27 18:27:48

2014-01-13 15:00:51

InxiLinux硬件

2015-09-11 15:56:52

內核構建Linux

2022-08-03 11:00:20

Linux內核

2019-05-24 14:15:30

Linux硬件信息命令

2009-12-11 15:47:54

Linux硬件信息

2021-08-23 06:59:38

Linux內核代碼

2016-01-04 15:17:50

Linux命令行硬件

2025-11-27 07:24:52

2024-03-20 15:36:54

2015-12-21 13:34:31

LinuxGPU顯卡硬件

2023-04-19 08:13:02

EpollLinux

2021-01-26 09:14:19

Linux內核模塊

2021-05-21 14:11:15

機器人系統技術

2009-02-16 20:16:52

Linux網卡硬件查看

2015-05-25 19:37:17

InxiLinux
點贊
收藏

51CTO技術棧公眾號

678在线观看视频| 成人av黄色| 久久se精品一区二区| 国产精品专区h在线观看| 欧美电影免费看| 日韩欧美国产精品| 国产三级在线免费观看| 亚洲精品成人天堂一二三| 青青青青在线视频| 国产一区二区导航在线播放| 久久伊人资源站| 亚洲每日在线| 国产一区二区三区四区五区在线| 黄色不卡一区| 欧美有码在线观看| av成人资源网| 欧美激情视频一区| 日本成人精品| 久久伊人精品天天| 成人av在线播放| 日韩一区二区三区国产| 99久久er| 中文字幕日韩高清| 免费成人毛片| 久久影视免费观看| 999久久精品| 欧美一区二区大胆人体摄影专业网站| 99精品在免费线中文字幕网站一区| 精品国产网站地址| 日本少妇精品亚洲第一区| 欧美成人免费一级人片100| 亚洲高清福利| 日本一区二区三级电影在线观看| 久久久久久久久久久久久久一区| 亚洲日韩成人| 一本久久a久久精品vr综合| 精品一区二区在线播放| 国内精品视频一区二区三区| 欧美国产激情二区三区| 午夜视频99| 欧美三级一区二区| free性欧美| 久久成年人免费电影| 国产日韩欧美一区二区三区| 香蕉国产精品偷在线观看不卡| 亚洲成人a级网| 奇米视频888战线精品播放| av在线中文| 肉色丝袜一区二区| 日韩欧亚中文在线| 国产内射老熟女aaaa| yw在线观看| 久久99热这里只有精品国产| av在线亚洲一区| 日韩美女av在线免费观看| 欧美天天在线| 特级西西444| 国产精品视频免费看| 桃乃木香奈av在线| 精品国产凹凸成av人导航| 疯狂欧洲av久久成人av电影| 国产一区视频在线播放| 粉嫩av国产一区二区三区| 男男激情在线| 欧美另类变人与禽xxxxx| 不卡亚洲精品| 国产精品自产拍在线观| 精品一区二区成人精品| 成人亚洲一区二区三区| 日韩欧美不卡在线观看视频| 亚洲三区欧美一区国产二区| av噜噜色噜噜久久| 久久综合色婷婷| 91在线网址| 欧美精品久久久久a| 国产日韩亚洲| 天天色综合4| 亚洲国产成人精品久久久国产成人一区| 精品国内亚洲2022精品成人| 欧美大香线蕉线伊人久久国产精品| 国产精品色一区二区三区| 欧美大胆的人体xxxx| 日本韩国在线不卡| 国产精品一区二区不卡| 黄色网址在线播放| 高清视频欧美一级| 国产一区二区三区免费观看| 欧美白人做受xxxx视频| 欧美激情在线观看| 国产乱理伦片在线观看夜一区| 久久久久久久久亚洲精品| 欧美猛交ⅹxxx乱大交视频| 日精品一区二区| 日本国产在线| 91精品国产91久久久久| 国产精品1区二区.| 米奇777四色精品人人爽| 欧美孕妇性xx| 国产伦精品一区二区三区视频免费| 亚洲欧美亚洲| 久久久精品动漫| 日韩欧美午夜| 亚洲精品影院| 国产在线精品免费| 特级西西444www大精品视频| 亚洲日本久久| 在线观看精品视频| 欧美国产一区视频在线观看| 日本h片在线看| 色欧美片视频在线观看在线视频| 亚洲www色| 97视频在线播放| 97视频在线观看成人| 一区二区三区日本久久久| 国产精品一区二| 亚洲一区二区三区自拍| 北岛玲日韩精品一区二区三区| 久久久久久尹人网香蕉| 日日夜夜精品免费视频| 在线观看免费国产小视频| 国外成人性视频| 国产三级一区二区三区| 欧美日韩视频免费看| 亚洲中文字幕无码一区二区三区| 日韩一区二区视频在线观看| 欧美阿v一级看视频| 三区在线观看| 亚洲最大的网站| 亚洲图片欧美色图| 精品香蕉视频| 国产真实伦在线观看| 热99精品里视频精品| 亚洲国产岛国毛片在线| 国产一区精品二区| 精品99在线视频| 久久精品免费播放| 99re亚洲国产精品| 日本免费一区二区视频| 国产精品亚洲二区在线观看| 精品国偷自产在线视频99| 91视频在线看| 精品素人av| 91天堂在线| 91国产在线免费观看| 欧美午夜一区二区三区免费大片| 亚洲国产日本| 国产偷倩在线播放| 免费cad大片在线观看| 正在播放国产一区| 国产精品高清亚洲| 久久综合国产| aaa大片在线观看| 国产精品88久久久久久妇女| 中文字幕日韩av综合精品| 久久久高清一区二区三区| 神马午夜久久| 国产在线观看黄| 日韩精品一区二区三区外面| 亚洲电影中文字幕| 国内外成人在线视频| 欧美亚洲黄色| 三级短视频在线| 99免费在线观看视频| 欧美不卡一区二区三区| 成人sese在线| 欧美先锋资源| 在线播放免费av| 男人日女人逼逼| 国产精品成人v| 欧美日本在线一区| 成人精品视频一区二区三区| 一区二区三区视频免费观看| h视频网站在线观看| 天天爱天天做天天操| 国内久久久精品| 欧美日韩国产经典色站一区二区三区 | 亚州欧美日韩中文视频| 欧美影院一区二区| 国产日韩精品一区| 日韩午夜电影| 色噜噜成人av在线| 91欧美视频在线| 欧美精品亚洲精品| 久久久久久亚洲精品中文字幕| 欧美日本一区二区三区| 综合激情婷婷| 欧美xoxoxo| 四虎av在线| 欧美综合自拍| 综合激情网站| 精品少妇3p| 米奇精品一区二区三区| 精品一区二区国产| 国产偷国产偷亚洲清高网站| 亚洲精品国产动漫| 欧美日本在线观看| 精品写真视频在线观看| 最新精品在线| 成年人黄视频在线观看| 日本成人黄色网址|