一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

page struct的三種存放方式

Linux閱碼場(chǎng) ? 來(lái)源:Linuxer ? 2020-08-03 16:33 ? 次閱讀

隨著硬件能力的提升,系統(tǒng)內(nèi)存容量變得越來(lái)越大。尤其是在服務(wù)器上,過(guò)T級(jí)別的內(nèi)存容量也已經(jīng)不罕見(jiàn)了。

如此海量?jī)?nèi)存給內(nèi)核帶來(lái)了很多挑戰(zhàn),其中之一就是page struct存放在哪里。

page struct的三種存放方式

在內(nèi)核中,我們將物理內(nèi)存按照頁(yè)大小進(jìn)行管理。這樣每個(gè)頁(yè)就對(duì)應(yīng)一個(gè)page struct作為這個(gè)頁(yè)的管理數(shù)據(jù)結(jié)構(gòu)。

隨著內(nèi)存容量的增加,相對(duì)應(yīng)的page struct也就增加。而這部分內(nèi)存和其他的內(nèi)存略有不同,因?yàn)檫@部分內(nèi)存不能給到頁(yè)分配器。也就是必須在系統(tǒng)能夠正常運(yùn)行起來(lái)之前就分配好。

在內(nèi)核中我們可以看到,為了應(yīng)對(duì)這樣的變化進(jìn)化出了幾個(gè)不同的版本。有幸的是,這部分內(nèi)容我們現(xiàn)在還能在代碼中直接看到,因?yàn)檫@個(gè)實(shí)現(xiàn)是通過(guò)內(nèi)核配置來(lái)區(qū)分的。我們通過(guò)查找_pfn_to_page的定義就能發(fā)現(xiàn)一下幾種memory model:

CONFIG_FLATMEM

CONFIG_SPARSEMEM

CONFIGSPARSEMEMVMEMMAP

接下來(lái)讓小編給各位看官一一道來(lái)。

1) FLATMEM

在這種情況下,宏_pfn_to_page的定義是:

#define__pfn_to_page(pfn)(mem_map+((pfn)-ARCH_PFN_OFFSET))

而這個(gè)mem_map的定義是

structpage*mem_map;

所以在這種情況下,page struct就是一個(gè)大數(shù)組,所有的人都按照自己的物理地址有序得挨著。

2) SPARSEMEM

雖然第一種方式非常簡(jiǎn)單直觀,但是有幾個(gè)非常大的缺點(diǎn):

內(nèi)存如果有空洞,那么中間可能會(huì)有巨大的page struct空間浪費(fèi)

所有的page struct內(nèi)存都在一個(gè)NUMA節(jié)點(diǎn)上,會(huì)耗盡某一個(gè)節(jié)點(diǎn)內(nèi)存,甚至是分配失敗

且會(huì)產(chǎn)生夸NUMA訪問(wèn)導(dǎo)致性能下降

所以第二種方式就是將內(nèi)存按照一定粒度,如128M,劃分了section,每個(gè)section中有個(gè)成員指定了對(duì)應(yīng)的page struct的存儲(chǔ)空間。

這樣就解決了上述的幾個(gè)問(wèn)題:

如果有空洞,那么對(duì)應(yīng)的 page struct就不會(huì)占用空間

每個(gè)section對(duì)應(yīng)的page struct是屬于本地NUMA的

怎么樣,是不是覺(jué)得很完美。這一部分具體的實(shí)現(xiàn)可以可以看函數(shù)sparse_init()函數(shù)。

有了這個(gè)基礎(chǔ)知識(shí),我們?cè)賮?lái)看這種情況下_pfn_to_page的定義:

#define __pfn_to_page(pfn) ({ unsigned long __pfn = (pfn); struct mem_section *__sec = __pfn_to_section(__pfn); __section_mem_map_addr(__sec) + __pfn; })

就是先找到pfn對(duì)應(yīng)的section,然后在section中保存的地址上翻譯出對(duì)應(yīng)pfn的page struct。

既然講到了這里,我們就要對(duì)sparsemem中重要的組成部分mem_section多說(shuō)兩句。

先來(lái)一張mem_section的整體圖解:

這是一個(gè) NRSECTIONROOTS x SECTIONSPERROOT的二維數(shù)組。其中每一個(gè)成員就代表了我們剛才提到的128M內(nèi)存。

當(dāng)然最開(kāi)始它不是這個(gè)樣子的。

其實(shí)最開(kāi)始這個(gè)數(shù)組是一個(gè)靜態(tài)數(shù)組。很明顯這么做帶來(lái)的問(wèn)題是這個(gè)數(shù)組定義太大太小都不合適。所以后來(lái)引進(jìn)了CONFIGSPARSEMEMEXTREME編譯選項(xiàng),當(dāng)設(shè)置為y時(shí),這個(gè)數(shù)組就變成了動(dòng)態(tài)的。

如果上面這個(gè)算作是空間上的限制的話,那么接下來(lái)就是一個(gè)時(shí)間上的限制了。

在系統(tǒng)初始化時(shí),每個(gè)mem_section都要和相應(yīng)的內(nèi)存空間關(guān)聯(lián)。在老版本上,這個(gè)步驟通過(guò)對(duì)整個(gè)數(shù)組接待完成。原來(lái)的版本上問(wèn)題不大,因?yàn)檎麄€(gè)數(shù)組的大小還沒(méi)有很大。但隨著內(nèi)存容量的增加,這個(gè)數(shù)值就變得對(duì)系統(tǒng)有影響了。如果系統(tǒng)上確實(shí)有這么多內(nèi)存,那么確實(shí)需要初始化也就忍了。但是在內(nèi)存較小的系統(tǒng)上,哪怕沒(méi)有這么多內(nèi)存,還是要挨個(gè)初始化,那就浪費(fèi)了太多的時(shí)間。

commit c4e1be9ec1130fff4d691cdc0e0f9d666009f9aeAuthor: Dave Hansen Date: Thu Jul 6 15:36:44 2017 -0700 mm, sparsemem: break out of loops earl

Dave在這個(gè)提交中增加了對(duì)系統(tǒng)最大存在內(nèi)存的跟蹤,來(lái)減少不必要的初始化時(shí)間。

瞧,內(nèi)核代碼一開(kāi)始其實(shí)也沒(méi)有這么高大上不是。

3) SPARSEMEM_VMEMMAP

最后要講的,也是當(dāng)前x86系統(tǒng)默認(rèn)配置的內(nèi)存模型是SPARSEMEM_VMEMMAP。那為什么要引入這么一個(gè)新的模型呢?那自然是sparsemem依然有不足。

細(xì)心的朋友可能已經(jīng)注意到了,前兩種內(nèi)存模型在做pfn到page struct轉(zhuǎn)換是有著一些些的差異。為了看得清,我們把這兩個(gè)定義再拿過(guò)來(lái)對(duì)比一下:

先看看FLATMEM時(shí)的定義:

#define__pfn_to_page(pfn)(mem_map+((pfn)-ARCH_PFN_OFFSET))

再來(lái)看看使用SPASEMEM后的定義:

#define __pfn_to_page(pfn) ({ unsigned long __pfn = (pfn); struct mem_section *__sec = __pfn_to_section(__pfn); __section_mem_map_addr(__sec) + __pfn; })

更改后,需要先找到section,然后再?gòu)膕ection->memmap的內(nèi)容中換算出page的地址。

不僅計(jì)算的內(nèi)容多了,更重要的是還有一次訪問(wèn)內(nèi)存的操作

可以想象,訪問(wèn)內(nèi)存和單純計(jì)算之間的速度差異那是巨大的差距。

既然產(chǎn)生了這樣的問(wèn)題,那有沒(méi)有辦法解決呢?其實(shí)說(shuō)來(lái)簡(jiǎn)單,內(nèi)核開(kāi)發(fā)者利用了我們常見(jiàn)的一個(gè)內(nèi)存單元來(lái)解決這個(gè)問(wèn)題。

頁(yè)表

是不是很簡(jiǎn)單粗暴?如果我們能夠通過(guò)某種方式將page struct線性映射到頁(yè)表,這樣我們不就能又通過(guò)簡(jiǎn)單的計(jì)算來(lái)?yè)Q算物理地址和page struct了么?

內(nèi)核開(kāi)發(fā)者就是這么做的,我們先來(lái)看一眼最后那簡(jiǎn)潔的代碼:

#define__pfn_to_page(pfn)(vmemmap+(pfn))

經(jīng)過(guò)內(nèi)核開(kāi)發(fā)這的努力,物理地址到page struct的轉(zhuǎn)換又變成如此的簡(jiǎn)潔。不需要訪問(wèn)內(nèi)存,所以速度的問(wèn)題得到了解決。

但是天下沒(méi)有免費(fèi)的午餐,世界哪有這么美好,魚(yú)和熊掌可以兼得的情況或許只有在夢(mèng)境之中。為了達(dá)到如此簡(jiǎn)潔的轉(zhuǎn)化,我們是要付出代價(jià)的。為了實(shí)現(xiàn)速度上的提升,我們付出了空間的代價(jià)。

至此引出了計(jì)算機(jī)界一個(gè)經(jīng)典的話題:

時(shí)間和空間的轉(zhuǎn)換

話不多說(shuō),也不矯情了,我們來(lái)看看內(nèi)核中實(shí)現(xiàn)的流程。

既然是利用了頁(yè)表進(jìn)行轉(zhuǎn)換,那么自然是要構(gòu)建頁(yè)表在做這樣的映射。這個(gè)步驟主要由函數(shù)vmemmap_populate()來(lái)完成,其中還區(qū)分了有沒(méi)有大頁(yè)的情況。我們以普通頁(yè)的映射為例,看看這個(gè)實(shí)現(xiàn)。

int __meminit vmemmap_populate_basepages(unsigned long start, unsigned long end, int node){ unsigned long addr = start; pgd_t *pgd; p4d_t *p4d; pud_t *pud; pmd_t *pmd; pte_t *pte; for (; addr < end; addr += PAGE_SIZE) { pgd = vmemmap_pgd_populate(addr, node); if (!pgd) return -ENOMEM; p4d = vmemmap_p4d_populate(pgd, addr, node); if (!p4d) return -ENOMEM; pud = vmemmap_pud_populate(p4d, addr, node); if (!pud) return -ENOMEM; pmd = vmemmap_pmd_populate(pud, addr, node); if (!pmd) return -ENOMEM; pte = vmemmap_pte_populate(pmd, addr, node); if (!pte) return -ENOMEM; vmemmap_verify(pte, node, addr, addr + PAGE_SIZE); } return 0;}

內(nèi)核代碼的優(yōu)美之處就在于,你可能不一定看懂了所有細(xì)節(jié),但是從優(yōu)美的結(jié)構(gòu)上能猜到究竟做了些什么。上面這段代碼的工作就是對(duì)每一個(gè)頁(yè),按照層級(jí)去填充頁(yè)表內(nèi)容。其中具體的細(xì)節(jié)就不在這里展開(kāi)了,相信有興趣的同學(xué)會(huì)自行去探索。

那這么做的代價(jià)究竟是多少呢?

以x86為例,每個(gè)section是128M,那么每個(gè)section的page struct正好是2M,也就是一個(gè)大頁(yè)。

(128M / 4K) * 64 = (128 * (1 < 20) / (1 < 12)) * 64 = 2M

假如使用大頁(yè)做頁(yè)表映射,那么每64G才用掉一個(gè)4K頁(yè)表做映射。

128M * 512 = 64G

所以在使用大頁(yè)映射的情況下,這個(gè)損耗的級(jí)別在百萬(wàn)分之一。還是能夠容忍的。

好了,我們終于沿著內(nèi)核發(fā)展的歷史重走了一遍安放page struct之路。相信大家在這一路上領(lǐng)略了代碼演進(jìn)的樂(lè)趣,也會(huì)對(duì)以后自己代碼的設(shè)計(jì)有了更深的思考。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9596

    瀏覽量

    86970
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40525
  • PAGE
    +關(guān)注

    關(guān)注

    0

    文章

    11

    瀏覽量

    20260

原文標(biāo)題:page結(jié)構(gòu)體,何處安放你的靈魂?

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    信號(hào)隔離器三種供電方式的區(qū)別

    信號(hào)隔離器是一重要的信號(hào)隔離裝置,其供電方式主要有獨(dú)立供電、回路供電和輸出回路供電三種。以下是這三種供電方式的詳細(xì)區(qū)別: 一、獨(dú)立供電 1
    的頭像 發(fā)表于 04-17 16:23 ?138次閱讀
    信號(hào)隔離器<b class='flag-5'>三種</b>供電<b class='flag-5'>方式</b>的區(qū)別

    redis三種集群方案詳解

    在Redis中提供的集群方案總共有三種(一般一個(gè)redis節(jié)點(diǎn)不超過(guò)10G內(nèi)存)。
    的頭像 發(fā)表于 03-31 10:46 ?390次閱讀
    redis<b class='flag-5'>三種</b>集群方案詳解

    三種太赫茲波的產(chǎn)生方式

    本文簡(jiǎn)單介紹了三種太赫茲波的產(chǎn)生方式。 太赫茲波(THz)是一電磁波,在電磁波譜上位于紅外與微波之間。太赫茲光子能量在1-10 meV范圍之間,在光譜分析、醫(yī)療成像、移動(dòng)通信方面都有非常廣闊
    的頭像 發(fā)表于 02-17 09:09 ?1060次閱讀
    <b class='flag-5'>三種</b>太赫茲波的產(chǎn)生<b class='flag-5'>方式</b>

    示波器的三種觸發(fā)模式

    示波器的觸發(fā)方式不僅影響波形捕捉的時(shí)機(jī),還決定了顯示的波形是否穩(wěn)定。 常見(jiàn)的觸發(fā)模式有三種: 單次觸發(fā) (Single)、 正常觸發(fā) (Normal)和 自動(dòng)觸發(fā) (Auto)。下面將對(duì)這三種觸發(fā)
    的頭像 發(fā)表于 01-07 11:04 ?4744次閱讀
    示波器的<b class='flag-5'>三種</b>觸發(fā)模式

    systemd journal收集日志的三種方式

    隨著 systemd 成了主流的 init 系統(tǒng),systemd 的功能也在不斷的增加,比如對(duì)系統(tǒng)日志的管理。Systemd 設(shè)計(jì)的日志系統(tǒng)好處多多,這里筆者就不再贅述了,本文筆者主要介紹 systemd journal 收集日志的三種方式
    的頭像 發(fā)表于 10-23 11:50 ?611次閱讀
    systemd journal收集日志的<b class='flag-5'>三種</b><b class='flag-5'>方式</b>

    I2S有左對(duì)齊,右對(duì)齊跟標(biāo)準(zhǔn)的I2S三種格式,那么這三種格式各有什么優(yōu)點(diǎn)呢?

    大家好,關(guān)于I2S格式,有兩個(gè)疑問(wèn)請(qǐng)教一下 我們知道I2S有左對(duì)齊,右對(duì)齊跟標(biāo)準(zhǔn)的I2S三種格式,那么這三種格式各有什么優(yōu)點(diǎn)呢? 而且對(duì)于標(biāo)準(zhǔn)的I2S格式,32FS傳輸16bit的數(shù)據(jù),48fs傳輸24bit的數(shù)據(jù),最低位會(huì)移動(dòng)到右聲道,是否意味著該數(shù)據(jù)被丟棄了?還是有
    發(fā)表于 10-21 08:23

    Windows管理內(nèi)存的三種主要方式

    Windows操作系統(tǒng)提供了多種方式來(lái)管理內(nèi)存,以確保系統(tǒng)資源的有效利用和性能的優(yōu)化。以下是關(guān)于Windows管理內(nèi)存的三種主要方式的詳細(xì)闡述,包括堆內(nèi)存管理、虛擬內(nèi)存管理以及共享內(nèi)存管理,每種
    的頭像 發(fā)表于 10-12 17:09 ?2029次閱讀

    隔離開(kāi)關(guān)的三種連鎖方式介紹

    的必要手段。通過(guò)連鎖機(jī)制,可以有效防止在斷路器未斷開(kāi)的情況下對(duì)隔離開(kāi)關(guān)進(jìn)行操作,從而避免潛在的安全隱患。 隔離開(kāi)關(guān)的三種連鎖方式 隔離開(kāi)關(guān)與斷路器之間的閉鎖:這種閉鎖方式確保了在斷路器未斷開(kāi)之前,隔離開(kāi)關(guān)無(wú)
    的頭像 發(fā)表于 09-19 11:54 ?2138次閱讀

    shell腳本執(zhí)行的三種方式及區(qū)別

    在Linux系統(tǒng)中,Shell腳本是一非常實(shí)用的工具,用于自動(dòng)化執(zhí)行一系列命令。Shell腳本可以大大提高工作效率,簡(jiǎn)化復(fù)雜的任務(wù)。在這篇文章中,我們將介紹Shell腳本執(zhí)行的三種方式及其區(qū)別
    的頭像 發(fā)表于 08-30 15:24 ?1882次閱讀

    typedef struct和直接struct的區(qū)別

    使用方式和靈活性上存在一些區(qū)別。下面詳細(xì)解釋這兩方式的區(qū)別和用法。 直接使用 struct 當(dāng)你直接使用 struct 關(guān)鍵字定義一個(gè)結(jié)構(gòu)
    的頭像 發(fā)表于 08-20 10:58 ?3379次閱讀

    簡(jiǎn)述三種esp32的開(kāi)發(fā)方式是什么

    ESP32是一款由樂(lè)鑫(Espressif)推出的低功耗、高性能的Wi-Fi和藍(lán)牙雙模無(wú)線通信芯片,廣泛應(yīng)用于物聯(lián)網(wǎng)、智能家居、智能硬件等領(lǐng)域。本文將詳細(xì)介紹三種ESP32的開(kāi)發(fā)方式:Arduino
    的頭像 發(fā)表于 08-20 09:11 ?6653次閱讀

    常用的pwm跟蹤控制方式是哪三種

    PWM(脈寬調(diào)制)跟蹤控制是一廣泛應(yīng)用于電機(jī)控制、電源管理、通信等領(lǐng)域的技術(shù)。它通過(guò)調(diào)整脈沖的寬度來(lái)控制輸出信號(hào)的占空比,從而實(shí)現(xiàn)對(duì)系統(tǒng)的精確控制。常用的PWM跟蹤控制方式主要有三種:增量式PWM
    的頭像 發(fā)表于 08-14 10:34 ?2098次閱讀

    計(jì)算機(jī)網(wǎng)絡(luò)中的三種通信方式

    計(jì)算機(jī)網(wǎng)絡(luò)中的三種通信方式,即單工通信、半雙工通信和全雙工通信,是理解和設(shè)計(jì)高效網(wǎng)絡(luò)架構(gòu)的基礎(chǔ)。每種通信方式都有其獨(dú)特的特性、應(yīng)用場(chǎng)景及優(yōu)缺點(diǎn)。以下是對(duì)這三種通信
    的頭像 發(fā)表于 08-07 15:00 ?4409次閱讀

    逆變電路的三種調(diào)壓方式

    路的三種調(diào)壓方式:脈寬調(diào)制(PWM)調(diào)壓、相位控制調(diào)壓和頻率調(diào)制調(diào)壓。 1. 脈寬調(diào)制(PWM)調(diào)壓 脈寬調(diào)制是一通過(guò)改變脈沖寬度來(lái)調(diào)整輸出電壓的調(diào)壓方式。在PWM調(diào)壓中,逆變電路的
    的頭像 發(fā)表于 08-02 16:59 ?3722次閱讀

    交流電力控制電路三種控制方式

    交流電力控制電路是現(xiàn)代電力系統(tǒng)的重要組成部分,它涉及到對(duì)交流電的控制和調(diào)節(jié)。在實(shí)際應(yīng)用中,交流電力控制電路的控制方式多種多樣,但主要可以分為三種:電壓控制、電流控制和功率控制。下面,我們將詳細(xì)介紹
    的頭像 發(fā)表于 06-16 11:19 ?5064次閱讀