TLB緩存是個神馬鬼,如何查看TLB miss?

介紹TLB以前,咱們先來回顧一個操做系統裏的基本概念,虛擬內存。php

虛擬內存

在用戶的視角里,每一個進程都有本身獨立的地址空間,A進程的4GB和B進程4GB是徹底獨立不相關的,他們看到的都是操做系統虛擬出來的地址空間。可是呢,虛擬地址最終仍是要落在實際內存的物理地址上進行操做的。操做系統就會經過頁表的機制來實現進程的虛擬地址到物理地址的翻譯工做。其中每一頁的大小都是固定的。這一段我不想介紹的太過於詳細,對這個概念不熟悉的同窗回去翻一下操做系統的教材。 redis

頁表管理有兩個關鍵點,分別是頁面大小和頁表級數緩存

  • 1.頁面大小

在Linux下,咱們經過以下命令能夠查看到當前操做系統的頁大小數據結構

# getconf PAGE_SIZE
4096

能夠看到當前個人Linux機器的頁表是4KB的大小。ide

  • 2.頁表級數函數

    • 頁表級數越少,虛擬地址到物理地址的映射會很快,可是須要管理的頁表項會不少,能支持的地址空間也有限。
    • 相反頁表級數越多,須要的存儲的頁表數據就會越少,並且能支持到比較大的地址空間,可是虛擬地址到物理地址的映射就會越慢。

32位系統的虛擬內存實現:二級頁表

爲了幫助你們回憶這段知識,我舉個例子。若是想支持32位的操做系統下的4GB進程虛擬地址空間,假設頁表大小爲4K,則共有2的20次方頁面。若是採用速度最快的1級頁表,對應則須要2的20次方個頁表項。一個頁表項假如4字節,那麼一個進程就須要(1048576*4=)4M的內存來存頁表項。
若是是採用2級頁表,如圖1,則建立進程時只須要有一個頁目錄就能夠了,佔用(1024*4)=4KB的內存。剩下的二級頁表項只有用到的時候纔會再去申請。 工具

file

64位系統的虛擬內存實現:四級頁表

如今的操做系統須要支持的但是48位地址空間(理論上能夠支持64位,但其實如今只支持到了48位,也足夠用了),並且要支持成百上千的進程,若是不採用分級頁表的方式,則建立進程時就須要爲其維護一個2的36次方個頁表項(64位Linux目前只使用了地址中的48位的,在這裏面,最後12位都是頁內地址,只有前36位纔是用來尋找頁表的), 2^36 *4Byte=32GB,這個更不能忍了。 也必須和32位系統同樣,進一步提升頁表的級數。 性能

Linux在v2.6.11之後,最終採用的方案是4級頁表,分別是:spa

  • PGD:page Global directory(47-39), 頁全局目錄
  • PUD:Page Upper Directory(38-30),頁上級目錄
  • PMD:page middle directory(29-21),頁中間目錄
  • PTE:page table entry(20-12),頁表項

file

這樣,一個64位的虛擬空間,初始建立的時候只須要維護一個2^9 大小的一個頁全局目錄就夠了,如今的頁表數據結構被擴展到了8byte。這個頁全局目錄僅僅須要(2^9 *8=)4K,剩下的中間頁目錄、頁表項只須要在使用的時候再分配就行了。Linux就是經過這種方式支持起(2^48 =)256T的進程地址空間的。操作系統

頁錶帶來的問題

上面終於費勁扒了半天Linux虛擬內存的實現,我終於能夠開始說我想說的重點了。
雖然建立一個支持256T的地址空間的進程在初始的時候只須要4K的頁全局目錄,可是,這也帶來了額外的問題,頁表是存在內存裏的。那就是一次內存IO光是虛擬地址到物理地址的轉換就要去內存查4次頁表,再算上真正的內存訪問,最壞狀況下須要5次內存IO才能獲取一個內存數據!!

TLB應運而生

和CPU的L一、L二、L3的緩存思想一致,既然進行地址轉換須要的內存IO次數多,且耗時。那麼幹脆就在CPU裏把頁表儘量地cache起來不就好了麼,因此就有了TLB(Translation Lookaside Buffer),專門用於改進虛擬地址到物理地址轉換速度的緩存。其訪問速度很是快,和寄存器至關,比L1訪問還快。

我原本想實際看一下TLB的信息,但翻遍了Linux的各類命令,也沒有找到像sysfs這麼方便查看L一、L二、L3大小的方法。僅僅提供下圖供你們參考吧! (誰要是找到了查看TLB的命令,別忘了分享給飛哥啊,謝謝!)

file

有了TLB以後,CPU訪問某個虛擬內存地址的過程以下

  • 1.CPU產生一個虛擬地址
  • 2.MMU從TLB中獲取頁表,翻譯成物理地址
  • 3.MMU把物理地址發送給L1/L2/L3/內存
  • 4.L1/L2/L3/內存將地址對應數據返回給CPU

因爲第2步是相似於寄存器的訪問速度,因此若是TLB能命中,則虛擬地址到物理地址的時間開銷幾乎能夠忽略。若是想了解TLB更詳細的工做機制,請參考《深刻理解計算機系統-第9章虛擬內存》

工具

既然TLB緩存命中很重要,那麼有什麼工具可以查看你的系統裏的命中率呢? 還真有

# perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses -p $PID
 Performance counter stats for process id '21047':  

           627,809 dTLB-loads  
             8,566 dTLB-load-misses          #    1.36% of all dTLB cache hits  
         2,001,294 iTLB-loads  
             3,826 iTLB-load-misses          #    0.19% of all iTLB cache hits

擴展

由於TLB並非很大,只有4k,並且如今邏輯核又形成會有兩個進程來共享。因此可能會有cache miss的狀況出現。並且一旦TLB miss形成的後果可比物理地址cache miss後果要嚴重一些,最多可能須要進行5次內存IO才行。建議你先用上面的perf工具查看一下你的程序的TLB的miss狀況,若是確實不命中率很高,那麼Linux容許你使用大內存頁,不少大牛包括PHP7做者鳥哥也這樣建議。這樣將會大大減小頁表項的數量,因此天然也會下降TLB cache miss率。所要承擔的代價就是會形成必定程度的內存浪費。在Linux裏,大內存頁默認是不開啓的。


file


開發內功修煉之CPU篇專輯:


個人公衆號是「開發內功修煉」,在這裏我不是單純介紹技術理論,也不僅介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提升你的技術實踐能力。歡迎你來關注個人公衆號,也請分享給你的好友~~~

相關文章
相關標籤/搜索