2020-11-25(《深入理解计算机系统》多级页表详解)
一、端到端地址翻譯示例
從圖上看,TLBI占了t位,而TLBT占了n-p-t位。
上節我們剛把TLB開了個頭,多說無益,還是具體來玩個實際例子吧,具體來做一個端到端(虛擬地址到物理地址)的地址翻譯示例,來統籌下之前講的知識點。先來做如下約定:
1、老規矩,存儲器按字節尋址,訪問也按一字節訪問;
2、虛擬地址14位長(n=14),物理地址12位長(m=12),位數少點玩起來方便;
3、頁面大小是64字節(P=64),也就是說(p=6)
4、TLB是四路組相聯,總共16個條目;
5、L1 d-cache是物理尋址、直接映射的,行大小為4字節,總共有16個組。
這里得先貼出各個單元內的數據快照,以便分析,首先是TLB。
先看上面的圖,要明確一點,引入TLB就是為了進一步分級VPN的,而分解方式跟VPN本身的頁表邏輯可能沒有對應關系!
由于頁面大小64字節,p=6,因此虛擬頁偏移VPO占用6位,既然是6位,再看虛擬地址是14位長(事先約定的,所以不是32位),剩下VPN是8位,也就是說TLB需要處理28也就是256個VPN值。而TLB是四路組相聯,從上到下0~3這四路,由VPN的低兩位——TLBI來標識;而TLB的四組中每組有四個條目,要處理總共256個VPN,它們被分成四路,也就是說每組還要對口處理64個VPN(256÷4=64)……注意到剩了6位給TLBT,他就是所謂的標記位,正剛好就能區分26=64個VPN,因此不管某個VPN被映射到哪一組,在同一組內是不會出現VPN重復歧義現象的,由TLBI確定組,再由TLBT確定標記位,于是8位VPN就這樣通過6+2的方式被TLB分解和存儲!
好,那假設現在CPU要讀取虛擬地址0x03d4處的值會出現什么情況?我們先把0x03d4分解成VPN+VPO形式:
轉換成14位的0x03d4:
| 000011 | 11010100 |
轉化成VPN+VPO:
| 0 0 0 0 1 1 1 1 | 0 1 0 1 0 0 |
實踐發現,VPN和VPO的值與0x03d4已經完全沒關系了,這是16進制表示法的弱點,雖然方便,但不如二進制來的直觀。好了,接下來我們看看物理內存中頁表的情況:
我們既然都知道物理地址是由PPN+PPO組成的,而頁偏移PPO和VPO又是等價已知的,現在通過查看頁表又曉得VPN的0x0F是對應的PPN是0D,那物理地址不已經出來了么等于0x0D14!如果你是CPU你這么做就傻X了,還查什么頁表啊!頁表存儲在物理內存中,直接訪問內存會消耗大量時間,MMU里明明有TLB緩存都不知道用么?好接下來看看VPN的0x0F是如何被TLB分解的:
哇咔咔,還記得之前分析的TLBI兩位和TLBT六位的結論么?忘了自己去看加粗字,現在用上了。兩個量居然都是0x03。再回看TLB的圖,先找組索引TLBI的0x03剛好是第四排,而標記位TLBT的0x03剛好是該組第二個條目,并且其有效位是1,因此PPN順利取出了0D!
如果TLB里沒有怎么辦?那就是TLB不命中,這時候才直接去物理內存中找PTE,就跟第一個想法一樣的——奇慢!
好了,物理地址0x0D14到是獲得了,你該不會想又跑到物理主存中去取值吧?別忘了這還有L1高速緩存呢:
行大小為4字節,總共16個組,怎么看?當然還是得先從物理地址0x0D14開始看,別忘了,先按物理地址的格式來分解:
分解后發現,組索引CI的值是0x05,也就是L1緩存里索引5,這一行,其中標記位為0D,與物理地址中CT的值0x0D匹配;最后看偏移量OO是0x0,沒有偏移,于是終于得到我們查詢了半天的數值:0x36,于是MMU將其返回給CPU——注意,此例中完全沒有物理內存的訪問過程!
2020-11-26所補充
對上面的補充:
【0】寫在前面-為什么需要虛擬存儲器?
0.1)定義:虛擬存儲器其實就是借用了磁盤地址空間,還記得當初我們安裝CentOS,劃分的swap 文件系統嗎?
0.2)VM簡化了鏈接和加載、代碼和數據共享,以及應用程序的存儲器分配:(摘自CSAPP)
(1) 簡化鏈接: 每個進程都擁有獨立的虛擬地址空間, 且空間范圍一致;(它是可重定向目標文件使用相對物理地址的前提)
(2) 簡化加載: 加載器從不實際拷貝任何數據從磁盤到存儲器。每個頁初次被調用哦時, 要么是CPU取指時引用, 要么是一條正在執行的指令引用一個存儲器位置時引用,VM系統會按需自動調入數據頁;
(3) 簡化共享: 多個虛擬頁面可以映射到同一個共享物理頁面上;
(4) 簡化存儲器分配: 當需要額外的堆空間, os分配連續的虛擬存儲器頁面,這些VP可以映射都任意的物理頁面,這些物理頁面可以任意分散在存儲器中;
0.3)我還想多問一句,為什么有了高速緩存,還需要TLB-translation lookaside buffer,翻譯后備緩沖器呢?
**Reason: **
引入局部性原則: (摘自CSAPP)
局部性原則保證了在任意時刻, 程序將往往在一個較小的活動頁面集合上工作,這個集合
叫做工作集(working set)或者常駐集(resident set)。
換句話說, 局部性原則揭示了一個現象:在一段時間內,我們會反復調入或調入同一個或
幾個虛擬頁頁面;而且,每次CPU產生一個VA時, MMU就必須查閱PTE,
以便將VA翻譯為PA, 注意是每次,所以開銷很大;
解決方法: 為了消除這樣的開銷,在MMU中包括了一個關于PTE的小緩存,稱為翻譯后備緩沖器;
關鍵點: 所有的地址翻譯步驟都是在芯片上的MMU中執行的, 因此執行速度非常快;
你要知道計算機中共有7級存儲結構,訪問CPU中的存儲空間(MMU)的速度比訪問緩存的速度可是快了幾個數量級的。
【1】說了這么多,看個荔枝(以下TLB + 頁表 + 高速緩存 是我們手動模擬的)(圖片摘自CSAPP):
【2】題目:說有虛擬地址 0x03d7, 虛擬存儲器系統如何將其翻譯成物理地址和訪問緩存的。
【3】解答:將以上虛擬地址用二進制表示,如下:
我們看到:
VPN=bit13~bit6 =0x0f;
VPO=bit5~bit0 = 0x17;
TLBT(行索引or標記)=bit13~bit8=0x03;
(這里,為什么我管標記叫做行索引,說到本質,叫其行索引,并沒有什么不妥,
因為本實例中,cache采用的是直接映射,即每個組就只有一行,所以行索引在此處無意;
但若cache是采用組相聯映射或全相聯映射的話,每組就有多行,行索引就起到作用了);
TLBI(組索引)=bit7~bit6=0x3;
相關聲明declaration寫在前面:
d1) 我們這里是考慮命中的情況,當然,如果不命中, MMU需要從主存中取出相應的PTE;
d2) PS: 命中與否,是看TLB中是否有請求的PTE;
d3)虛擬地址14位,而物理地址12位;
翻譯過程: (干貨)
(1) MMU(MMU存在于CPU中,是硬件)從虛擬地址中抽取VPN=0x0f;
(2) 再從VPN中抽取出TLBT(行索引)=0x03, TLBI(組索引)=0x3,用于索引翻譯后備存儲器TLB;
(3) 帶著TLBT和TLBI 查看TLB,發現第3組, 有標記位03(當然,這是手動設置的,便于模擬),且有效位=1,故命中;
(4) 命中后,將PPN=0D返回給MMU;
(5) MMU將PPN=0x0D=bit11~bit6 和 虛擬地址的VPO=0x17=bit5~bit0 連接起來,形成物理地址PA 》》 0x357
6) 如上圖所示:我們得到了CT-Cache Tag=0x0D, CI-Cache Index=0x5, CO-Cache Offset=0x3;即得到了緩存標記CT=0x0d,緩存組索引CI=0x5,緩存偏移CO=0x3;
(7) 依據CT、CI、CO,查詢高速緩存(c圖), 第5組的標記位-0x0D, 故命中;
(8) 在看緩存偏移是0x3,所以取出塊3字節0x1D;
對于CT + CI + CO, 我再說的明白一點: CT就是行索引, CI就是組索引, CO就是塊索引;
二、多級頁表
多級頁表作用:通過只為進程實際使用的那些虛擬地址內存區請求頁表來減少內存使用量(出自《深入理解Linux內核》第三版51頁)
在解釋多級頁表之前,先來梳理下概念,免得后面的內容看暈:
1、頁表:緩存了很多頁面信息(有效位+物理頁號)的表;
2、各頁面信息分別由頁表中每個PTE記錄,
3、頁面:就是對應虛擬存儲器(磁盤空間)中各空間
4、頁號(PN):MMU根據虛擬頁號VPN索引頁表對應的具體PTE,從中提取出其中的物理頁號PPN,一般都是數組直接對應關系
好了,既然概念解釋清楚了,那么頁表大小頁面大小應該不會再搞混了吧:頁面大小對應虛擬存儲器每個分頁大小,而PET的大小就是存儲一條對應地址翻譯信息所占用的空間大小,那么頁表大小就是該頁表內所有PTE大小的總和。
我們再來回憶下,一個32位系統,有232個地址,每個地址標識一個字節的數據,那么地址能訪問到的數據就涵蓋了232字節,也就是(22) * (210) * (210) * (210)B數據,也就是4GB數據。
如果我們每個末級頁面的大小是4kB,那么4GB的數據就被分割成1M個頁面(注意單位是”個“不是字節,說的頁面個數呢!這里按210進階,不是103),好,如果我們又知道每個PTE的空間開銷是占4字節大小,也就是說頁表中處理每個頁面都需要占用4B,處理1M個頁面的頁表自然就要在物理內存中占用4MB的空間……教材上確實沒分析得這么明顯,我如此講解應該立馬知道,4MB駐留空間是腫么得來了吧!天~4MB大小的頁表,檢索起來效率一定很低,如何設計操作系統才能把頁表縮小以改進性能呢?(注意不是在討論頁表里每一項頁面所映射的4kB空間)
好了好了,先否定掉剛才4MB末級頁表規模的提案,因為現在有另一個假設也是4MB,那就是,如果我們把4GB總的虛擬存儲器空間,先等分成一份份4MB大小(而不是之前的4kB大小),那就會分出1k份出來,也就是1024份空間。如果我們有一個專門的頁表(I),其中剛好有1024個PTE,就剛好能標識這1024份空間。但是呢,總覺得這1024個4MB的末級頁面空間(注意不是頁表空間)每個都太大了,也就是VPO太大了,難以精確定位其偏移量,于是我們聯想到之前在設計單級頁表結構中,末級頁面大小本來想分成4KB(就是一個頁面能緩存的空間大小),如果我們把每份4MB空間再細分成1024個末級頁面映射,完全可以在每份4MB空間中再設立另一個專門的頁表(II),其中也剛好有1024個PTE,就剛好可以把末級頁面映射成4KB大小。而且既然(I)中每個PTE對應一份4MB空間,而每份空間又對應一個(II),那么(I)中每一個PTE就可以和某一個(II)建立聯系,于是多級頁表的概念產生了!……也許當年最早的os設計者就是沿著這種思路思考出來二級頁表的概念:
先不管最左邊那些亂七八糟的虛存分配,先看最右邊,從VP0~VP2047這2k個頁(注意是頁不是字節!),我們發現,每一個頁VPx都被二級頁表中的一個PTE所對應,而一個完整的二級表有1024個PTE分別對應1024個VP,圖中所謂的2k個頁需要兩個二級頁表才能對應完成。而我們又知道一個末級頁面是4KB大小,那1024個末級頁面總共就是4MB大小,也就說每個二級頁表都對應4MB大小的數據!好了,再看一級頁表,它每個PTE對應的就是這樣一個二級頁表,也就是說,一級頁表每個PTE都對應4MB大小的數據,那么總共1024個PTE的一級頁表,剛好可以完整對應4GB大小的空間!
我們發現,所謂的兩級頁表層次結構,是不是很像三維數組int PT[1024] [1024] [1024]?由于末尾是int型占4字節,末級頁面大小就是1024個4字節也就是4kB。
好了,為啥要整二級頁表呢?最起碼有三點好處。其一,如果一級頁表的PTE為空,那就不存在對應下標的二級頁表,能節省大量潛在的空間;其二,只有一級頁表需要一直保存在物理內存中,二級頁表則不然,只有經常使用的需要保存在物理內存——還是為了節省空間^^,其三,也就是上面提過的問題,這樣每個頁表都只有1024個PTE,由于每個PTE本身只占用4B大小,因此每個頁表就只占用4kB空間了!——空間空間還是為了空間!
插一句,上面說的如此設計每個頁表只占4kB,和我們說的每個末級頁面只占4kB,概念上完全是兩回事,但如此設計卻顯得優雅。頁表和頁面的概念在這里灰常灰常容易搞混!切記不要搞混!切忌搞混!萬萬不能搞混!重要的事情說三遍!!
節省空間固然好,但如何在頁表中查找PTE呢?比如我的頁面大小是4KB,回憶下上節虛擬地址的結構是VPN+VPO,其中VPO是頁面偏移,要滿足4KB偏移大小,VPO就需要12位(212=1k*4),那么VPN就剩下32-12=20位可用,10位剛好可表示1024個值,于是我用10位去標識一級頁表中1024個PTE,再用10位去標識每個一級頁表PTE中存儲的二級頁表中的1024個PTE,于是這樣劃分的虛擬地址就能將上圖的頁表層次結構全部標識清楚:
有沒有瞬間覺得虛擬地址被玩壞的感覺?k級虛擬地址對應k級頁表,多么高大上又樸實無華簡易的思想!
總結
以上是生活随笔為你收集整理的2020-11-25(《深入理解计算机系统》多级页表详解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 条件跳转指令总结
- 下一篇: 2020-11-27(switch的优化