[轉載] 廖威雄: 學習Linux必備的硬件基礎一網打盡

我在 Linux閱碼場 (原名linuxer) 微信公衆號發表的文章,由於版權原因,通過轉載分享此博客,原文鏈接爲:

《廖威雄: 學習Linux必備的硬件基礎一網打盡》: https://mp.weixin.qq.com/s/7EzQ3LDtdLc3EjtMnfJHfA


作者簡介:
    廖威雄,目前就職於珠海全志科技股份有限公司從事linux嵌入式系統(Tina Linux)的開發,主要負責文件系統和存儲的開發和維護,兼顧linux測試系統的設計和持續集成的維護。
    拆書幫珠海百島分舵的組織長老,二級拆書家,熱愛學習,熱愛分享。
內容簡介:
	出來混,遲早要還的.....
	本文詳細論述大學時候的基本功,MMU,CACHE, TLB,  Page Fault, 進程切換........

案情回溯

某一個夜黑風高的晚上,宋寶華老師組織的微信羣一片祥和寧靜。我刷着手機,心血來潮往微信羣中提出一個疑惑:

宋老師,cache是一個程序維護一份還是所有程序維護一份?你昨天說進程調度損耗還包括cache命中的問題,那如果一個進程一份cache不就好了? 

正所謂一石激起千層浪,這個傻逼竟然問這麼弱智的問題?!宋老師急怒攻心,就差扯着我的衣領大吼:

別問這麼傻的問題了看書!!你這樣真吐血!

在宋老師的淫威之下瑟瑟發抖,於是狠下心來,翻箱倒櫃找出了封印多年的《計算機操作系統》,於是便有了此文。

本文儘可能從基礎部分講起,適合完全沒學過計算機操作系統的小白,也適合亂七八糟學過一些但沒理清脈絡的讀者;不適合完全掌握計算機操作系統原理的大牛。

本人水平有限,若存在理解錯的地方,歡迎提出。

存儲結構

經典存儲結構圖

結構圖要點解析:

  1. 從L0到L6的7個層次,都是硬件設備,並不是軟件的概念。尤其注意圖中的高速緩存,常稱爲CPU cache,與我們常說的Page cache是不一樣的,前者是實在硬件設備,後者是軟件上的概念
  2. 金字塔越往上,速度越快,價格也越高。出於成本考慮,實際產品中價格越高的存儲器實際使用容量越小,例如寄存器以個計數,1級緩存單位是KB,3級緩存單位是MB,內存幾GB,最底層的磁盤卻可達到TB級別
  3. 磁盤是非易失性存儲器,而磁盤以上的都是易失性存儲器。這也意味着掉電後,磁盤數據依然存在,。於此相反,內存是易失性存儲器,掉電則數據丟失。
  4. 上層存儲器的數據來自下層,且是直接下層,例如L1高速緩存的數據直接來自於L2高速緩存

結合b、c和d三點,我們初步形成一個認識:

每次從上電開始,只有磁盤有數據。CPU都是從磁盤讀取原始數據,然後根據一些算法挑選數據往上傳遞,例如從磁盤選部分數據放到內存,從內存提取部分數據到高速緩存。

本章總結圖

Ps. 後面章節逐漸完善此圖,讓章節之間,知識之間構建聯繫

什麼是頁?什麼是頁表?什麼是快表?什麼又是MMU

“頁”是什麼?

在瞭解"頁"之前,務必初步瞭解"虛擬存儲器"。

虛擬存儲器

那麼,什麼又是虛擬存儲器呢?《計算機操作系統 第三版》有這麼一句話:

“(虛擬存儲器是)具有請求調入功能和置換功能,能從邏輯上對內存容量加以擴充的一種存儲系統”

本文關注的重點是:從邏輯上對內存容量加以擴充。什麼是邏輯上擴充內存容量呢?

例如,在舊一點的32位cpu的手機中有且只有2G內存,但是每一個進程在執行過程中都彷彿手機有4G內存,且每個進程都能獨佔4G內存。注意了,是每一個進程都獨佔4G內存,每一個!每一個!

這就是從邏輯上對內存進行擴充,但這也是赤裸裸的欺騙。

實際物理內存明明只有2G,頁表的機制讓每個進程都彷彿有4G。進程被欺騙了,但進程可爽了。爲什麼爽呢?對應用來說,你告訴我有4G內存啊,我不管你實際有多少,我需要用到4G的內存時,你要給到我!於是內核就苦逼了。

我們把APP訪問到的4G虛擬內存地址叫做:虛擬地址

我們把內核實際管理的2G物理內存地址叫做:物理地址

先形成這樣一個初步認識:CPU訪問虛擬地址,MMU把虛擬地址轉爲物理地址,CPU再通過物理地址訪問物理內存。

(Ps. MMU是CPU中的一個硬件模塊,硬件模塊!硬件模塊!專門負責虛擬地址到物理地址的轉換,下文會有更詳細的介紹)

清楚了什麼是虛擬地址,什麼是虛擬存儲器,我們再來看看,“頁”是什麼?

“把APP的虛擬地址空間切分爲若干個大小相等的片,每一片,就是我們說的頁(Page)”

注意,這裏說的是虛擬地址空間,虛擬地址空間!虛擬地址空間!在Linux上,頁大小通常爲4K。每一個頁都有編號,從0開始,如第0頁,第1頁等。

”把物理內存也按"頁"的大小切分爲若干大小相等的片,每一片,就是我們說的頁框(frame)“

頁框就是用來裝頁的呀,就像相框用來裝相片,務必大小一致!

頁框也叫頁幀、物理塊(≠I/O概念上的塊),由於契合相框的形象,本文統一稱爲頁框。因此,我們說:“頁是內存管理的基本單位”

內存管理就是把物理內存劃分爲一個一個的頁(框),進程在申請內存時,內核就以頁爲單位,把進程的一個個(虛擬)頁裝入到多個可能不連續的(物理)頁框中。

我們以一張圖來形象描述頁和頁框的關係:

上圖除了描述頁與頁框的關係,還隱藏了兩個重要的信息:

  1. 一個進程的頁並不是全部映射到物理內存頁框中
    Linux內核只有在萬不得已得情況下才會真正爲進程分配物理內存。例如進程1中的白色部分,由於進程還沒使用,因此白色部分並不會指向物理內存的頁框。
  2. 多個進程的頁可以映射到共同的物理內存頁框中
    上圖中進程1與進程2共用藍色頁框。這些共享的頁框一般是動態庫,例如所有進程使用相同的C庫指令。物理內存空間有限,內核沒必要爲每個進程單獨維護一份C庫指令。

頁表是什麼?

頁表

從頁與頁框的圖,我們知道虛擬的進程頁與物理內存頁框有映射關係,而且是離散映射的。那麼是什麼記錄了這種映射關係?是頁表。頁表記錄了“頁”與“頁框”的對應關係。

我們以一張圖來形象描述頁表:

上圖有以下幾個要點:

  1. 內核爲每一個進程維護一份頁表,一對一!
  2. 頁表記錄了進程頁與內存頁框之間的對應關係。
  3. 進程的頁離散存儲在物理內存的頁框中。例如進程第1頁存放在物理第2號頁框中,第2頁卻放在第4頁框。
  4. 只有在萬不得已情況下,內核才真正爲進程頁分配物理內存。例如第0頁,第3頁因爲進程還沒真正使用,是沒有頁框號的。
  5. 進程的頁,不管有沒使用,都完整記錄在頁表中。例如從第0頁到最後的第1048575頁,都記錄在進程A的頁表中。

多級頁表

是否思考過上圖最後一頁爲什麼是第1048575頁?

以32位CPU有4G虛擬內存爲例,以linux的4K頁大小計算:

虛擬頁數量 = 4G/4K = 1M ( 1048576)

從0開始算,因此最後一個頁號是1048576 - 1 = 1028575。

一個頁表項(就是頁表的一行)通常只佔4Byte,因此描述一份4G虛擬地址空間大小的頁表,就有1048576*4B= 4M。而且由於頁表是一個表的結構,且換算頁表項地址是通過表內偏移實現,因此存放頁表的物理頁框必須連續。也就是說,一個進程還沒開始跑就要先佔用4M的內存存放頁表?這麼浪費,還要是連續物理地址的內存?不能忍!爲了解決此問題,於是設計了2級頁表,甚至多級頁表。

多級頁表,簡單來說就是對那1級頁表需要的4M連續內存再次分頁,再使用另外一個頁表保存分頁的記錄,內核只需要記錄最上一層的頁表,通過多次頁表的轉換,取得真正的物理頁框號。因此,最上一層的頁表就可以很小,且支持離散存儲。

篇幅有限,不展開多級頁表,只需要瞭解個概念即可,即使不理解也不影響本文的討論。

“快表”是什麼?

頁表存在於內存中,咱們暫時忽略高速緩存,那麼CPU每次獲取數據都需要2次訪問內存:

  1. 一次訪問內存的頁表,獲取物理地址
  2. 第二次根據物理地址獲取真實數據

內存訪問速度雖然比磁盤要快,但跟CPU比依然不在一個數量級,CPU得浪費非常非常多時間等待內存。爲了提高極致提高訪問頁表的速度,於是有了快表。

快表,又名TLB(Translation Lookaside Buffer),是單獨的一組寄存器,也有說是高速緩存,用於記錄頁表中正在頻繁使用的頁表項。

“由於程序和數據的訪問往往具有侷限性(局部性原理),因此,據統計,快表命中概率可達90%以上”

局部性原理是什麼?後面還會有更詳細的介紹。在這裏,我們要有個認識即可:

快表是爲了從概率命中的角度加速虛擬地址到物理地址的轉換,設計的一組高速存儲硬件模塊。

1個CPU多核之間共享Cache,但是一個核卻有獨佔一個快表。

由上一章《存儲結構》我們知道, 寄存器的速度最接近於CPU,或者說,完全跟得上CPU的節奏,但很貴,因此:

  1. 快表容量有限,通常只能記錄16~512個頁表項
  2. 轉換虛擬地址到物理地址時,優先從快表尋找
  3. 如果快表中找不到對應頁表項,則從內存頁表中獲取,同時更新快表
  4. 更新快表時,如果快表已滿,則淘汰一個最老的且已被認爲不再使用的頁表項

“MMU”是什麼?

本章到這,我們已經知道,什麼是"頁",什麼是"頁表",什麼是"快表",也知道了他們都是爲了從虛擬地址向物理地址轉換服務。但我們似乎忽略了一個問題,誰來負責執行這項頻繁的地址轉換工作?CPU?不不,CPU已經夠忙的了。這就到了我們勤勤懇懇的MMU表現的時候了。

MMU(MemoryManagememt Unit),內存管理單元。是CPU內的一個硬件模塊,硬件!硬件!負責從虛擬地址轉換物理地址,並提供硬件機制的內存訪問權限檢查。

MMU轉換虛擬地址到物理地址是其內的硬件電路做的,硬件電路!硬件電路!

我們需要形成個認識即可,下文會有更詳細的介紹:

CPU需要訪問進程的虛擬地址,於是把虛擬地址發送給MMU,由MMU內的硬件電路實現訪問快表、頁表,最終得到的物理地址。

本章總結圖

Ps. 請試試對比總結圖1,並結合本章知識解剖此圖

Ps. 此處的CPU core是指運算單元,而非類似Cortex-A7等 的core,因爲MMU、TLB、CPU Cache等也歸屬於Cortex core。

什麼是頁面調入和頁面置換?如何置換頁?

什麼是頁面調入和頁面置換?

頁面調入

在第3章"什麼是頁"的探討中提到:

Linux內核只有在萬不得已得情況下才會實際爲進程分配物理內存

這個結論同樣適用於開始執行程序時的加載程序,例如一個可執行程序100M,這100M指令、數據必須要加載到內存CPU纔可訪問。但是物理內存容量有限,不可能爲了這個程序,一執行立馬爲程序分配100M物理內存,否則你多執行幾個程序不就沒物理內存了麼?

因此,這100M的程序只是邏輯上"加載"到了虛擬內存空間,爲數據指定了虛擬頁號,實際上還沒爲進程的頁分配物理頁框。在程序指令需要CPU讀取這100M數據時,內核才"磨磨蹭蹭"的真正分配物理頁框,而且是程序要什麼內核才加載什麼,且一次只加載一部分。

這個從下層獲取進程頁面的操作就叫"頁面調入"。

頁面置換

在第2章《存儲結構》中有提到,實際產品中,越上層價格越貴,因此出於成本考慮,實際使用容量越小。因此,上層只能從下層挑選一部分頁通過頁面調入加載到上層。

挑選什麼數據加載到上層?這是由一些算法決定的,例如常見的LRU算法。算法下文繼續討論,本節我們繼續探討,什麼是頁面置換?

上層存儲容量有限,如果上層本身已經放滿數據了,要調入新的頁,只能淘汰舊的頁。

這個淘汰舊頁,擁抱新頁的過程就是"頁面置換"。

淘汰的舊頁不都是直接丟棄,例如髒文件數據就會回刷,不常用的頁會置換到交換分區等。

缺頁中斷

CPU/內核中有2個需要調入頁面和頁面置換的地方:

  1. 從磁盤加載數據到內存
  2. 從內存加載數據到CPU高速緩存

前者是內核軟件實現的置換算法,軟件!軟件!後者是CPU硬件實現的置換算法,硬件!硬件!

那麼,我們所說的缺頁中斷是怎麼一回事呢?就是內核提供的軟件實現頁面調入和頁面置換的中斷處理代碼。

在進程所要訪問的頁如果不在內存時,由MMU觸發一次缺頁中斷,執行內核提供的中斷處理程序,將數據通過頁面調入和頁面置換的方式,從磁盤加載到內存。由於上層的數據來自下層,且只是下層的一個拷貝,因此當內存都沒有對應數據時,上層的高速緩存也不可能有這些數據。

行文到此其實已經暴露了我在《案情回溯》中的提問有什麼不對。我的提問:

" 宋老師,cache是一個程序維護一份還是所有程序維護一份?你昨天說進程調度損耗還包括cache命中的問題,那如果一個進程一份cache不就好了? "

提問有哪裏不對呢?

  1. CPU cache是一個物理設備,而不是軟件層面的Pace Cache類似的概念。因此cache不是用"份"的量詞來描述的,這不是軟件概念。
  2. 一個CPU中多個核共用CPU cache,且cache的頁面調入是物理算法實現的。硬件算法只挑選最活躍的頁進入高速緩存,這不是軟件所能控制的。

如何置換頁

局部性原理

在探討"如何置換頁"之前,我們必須瞭解什麼是"局部性原理"。

程序運行有以下3個特點:

時間局部性:如果一個數據/指令正在被訪問,那麼在近期它很可能還會被再次訪問
空間局部性:在最近的將來將用到的信息很可能與現在正在使用的信息在空間地址上是臨近的
順序局部性:在典型程序中,除轉移類指令外,大部分指令是順序進行的

簡單來說,對同一個進程而言,CPU訪問了某個邏輯地址的數據/指令,則CPU在將來很有可能再次訪問這個虛擬地址或相鄰的一小片連續地址,這就是局部性原理。

根據"局部性原理"我們知道什麼地址的數據是CPU在將來的短時間內會訪問的,因此我們就可以把這些數據緩存到更高速的存儲設備中。

高速緩存容量有限,爲了保證CPU儘可能從高速緩存中獲取數據(內存速度<高速緩存),就是我們所說的提高Cache命令率,我們就要儘可能確保高速緩存中的數據是CPU將要用的。

同樣的,內存容量有限,且遠小於磁盤,但速度遠大於磁盤,爲了提高CPU獲取數據的速率,我們就要儘可能保證內存中數據是CPU將要用的。

CPU優先從高速緩存獲取數據,在高速緩存沒有命中時,再去內存獲取,如果內存也沒命中,則必須從磁盤中調入。因此,頁面置換儘可能保證:內存的數據是CPU將要用的,而高速緩存的數據來自內存,其數據是CPU很可能"立刻即刻馬上"要用的。

因此,我們就需要根據"局部性原理",淘汰Cache/內存中被認爲CPU不再使用的頁,騰出空間存放被認爲馬上要用的頁。

LRU置換算法

目前常見的頁面置換算法有3種:

  • FIFO:先入先出,從時間維度,淘汰最早使用的頁
  • LRU:最近最少使用(LeastRecently Used),從時間維度,淘汰最久沒用的頁面
  • LFU:最近最不經常使用(LeastFrequently Used),從頻率維度,淘汰使用次數最少的

本文主要介紹LRU算法,假設場景如下:

剛上電,此時Cache是空的,數據全部在內存。根據LRU算法從內存獲取數據到Cache。某個進程首先開始執行,其執行過程中需要訪問到的指令/數據的虛擬地址所在的頁順序依次是:1,2,4,2,3,1

根據上述場景,Cache內數據的變化演示如圖:

  1. CPU執行進程指令,首先需要訪問第1頁,然而Cache是空的,無第1頁緩存,因此觸發第1次缺頁。
  2. 接下來的第2頁,第4頁,都由於Cache沒命中且Cache還有空餘,觸發第2、3次缺頁,而不會淘汰頁。
  3. 第4次需要訪問第2頁,此時第2頁已經在Cache中,Cache命中。不缺頁,但會調整頁順序。
  4. 第5次需要訪問第3頁,Cache不命中,觸發缺頁。但此時由於Cache已經滿了,則按照LRU算法,淘汰最久沒使用的頁,因此淘汰第1頁。
  5. 第6次需要訪問第4頁,此時第4頁已經在Cache中,Cache命中。不缺頁,但會調整頁順序。

本章總結圖

5.CPU尋找頁面的過程

CPU獲取數據主要有兩步:

  1. 通過虛擬地址獲取物理地址
  2. 根據物理地址獲取數據

本章主要分析這兩步過程,其中【步驟a】-【步驟i】爲獲取物理地址的過程;【步驟A】-【步驟D】爲根據物理地址獲取數據過程。

獲取物理地址

參考圖如下:

【a】CPU向MMU發送虛擬地址

【b】MMU查詢快表TLB

快表命中:從快表獲取物理地址,由MMU繼續根據物理地址匹配數據頁【步驟A】
快表不命中:查詢頁表【步驟c】

【c】從高速緩存查詢頁表

"高速緩存"緩存頁框,而頁表存儲於頁框中,因此讀取頁表實際上也是讀頁(頁表的物理地址有單獨的寄存器保存)
高速緩存命中:從高速緩存獲取物理地址,並更新快表,進入【步驟A】
高速緩存不命中:查詢內存中的頁表【步驟d】

【d】從內存中查詢頁表

頁表保存了所有虛擬地址的映射關係,而不管頁是否有映射的物理頁框。因此從內存頁表中肯定能“命中”頁。從頁表獲取虛擬地址的映射關係後,進入【步驟e】

【e】把查詢的頁表項記錄到高速緩存,進入【步驟f】

【f】MMU從高速緩存中獲取頁表項

虛擬地址有分配物理頁框:轉換物理地址並更新快表,由MMU繼續根據物理地址匹配數據頁【步驟A】
虛擬地址沒分配物理頁框:觸發缺頁中斷【步驟g】

【g】進入缺頁中斷處理程序

【h】爲虛擬頁分配物理頁框

如果無空閒物理頁框,則根據LRU算法選擇需要淘汰的頁,要淘汰的頁如果是髒頁則回刷,否則直接丟棄或者置換到磁盤的交換分區中。
然後,從磁盤中獲取頁信息更新到物理頁框,更新內存頁表。

【i】缺頁中斷處理的最後

修改CPU寄存器,使得重新啓動導致缺頁的指令,返回【步驟a】重新執行。

根據物理地址獲取實際數據

參考圖如下:

【A】MMU獲取物理地址後,根據物理地址查詢高速緩存

高速緩存命中:CPU直接從高速緩存獲取數據【步驟D】
高速緩存不命中:查詢物理內存【步驟B】

【B】根據物理地址,獲取物理內存中的數據

【C】硬件實現把數據頁記錄到高速緩存中

【D】CPU直接從高速緩存中獲取數據

最理想(Cache和TLB命中)情況下尋找頁面過程

大多時候都會命中,在命中時,CPU只需要通過高速緩存和TLB即可快速獲取數據。

參考圖如下:

【a】CPU向MMU發送虛擬地址

【b】MMU查詢快表TLB

快表命中:從快表獲取物理地址,由MMU繼續根據物理地址匹配數據頁【步驟A】

【A】MMU獲取物理地址後,根據物理地址查詢高速緩存

高速緩存命中:CPU直接從高速緩存獲取數據【步驟D】

【D】CPU直接從高速緩存中獲取數據

本章總結圖

用3句代碼小結

我們以3句C代碼的操作流程,對前面章節做一次小結。

char *p = malloc(4 * 1024 * 1024);
memset(p, 'g', 1024);
p[1] = '\0';

爲了方便理解,假設此3行代碼編譯後執行的設備爲32位LinuxPC,假設頁大小爲4K,且只有1級頁表。頁表項結構爲:

第1句:char *p = malloc(4 * 1024 * 1024);

頁表情況

假設malloc返回p的值是 0x10240011,表示虛擬地址 [0x10240011, 0x10640011) 的4M空間被這次malloc申請成功。那麼其對應的虛擬頁號和頁內偏移如何計算呢?

爲了方便計算,我們把16進制的邏輯地址轉爲10進制的邏輯地址,則:

開始虛擬地址:0x10240011 => 270794769
結束虛擬地址:0x10640011(0x10260011) => 274989073

如何計算1級頁表的頁號和頁內偏移呢?(多級頁表換算更復雜,此處爲了簡化,只使用1級頁表)

一級頁表頁號 = 地址 / 頁大小 【求整】
一級頁表頁內偏移 = 地址 % 頁大小【求餘】

因此計算的虛擬頁號爲:

開始虛擬地址:270794769 / ( 4 * 1024) = 66112
結束虛擬地址:274989073 / ( 4 * 1024) = 67136

虛擬頁內偏移爲:

開始虛擬地址:270794769 % ( 4 * 1024) = 17 = 0x11
結束虛擬地址:274989073 % ( 4 * 1024) = 17 = 0x11

我們以這樣一張圖描述執行代碼後的頁表情況:

上圖要點解析:

  1. malloc申請的空間地址是虛擬地址,虛擬地址!虛擬地址!
  2. 剛申請時並沒有立刻分配頁框,因此頁表上並沒有對應頁框號

6.2.第2句:memset(p, 'g', 1024);

第2句代碼把p指向的地址1K大小內存設置爲'g'

頁表情況

上圖要點解析:

  1. 由於只初始化了1K的數據量,在例子中只涉及1個頁,且虛擬頁號爲:66112
  2. 查詢頁表發現第66112頁並沒有對應物理頁框,於是爲其分配了第4097頁框
  3. CPU執行指令,把虛擬地址0x10240011開始的1K內存初始化爲'g',因此虛擬頁映射的內存物理頁框偏移0x11到0x411被寫入'g'

6.2.2.CPU尋找頁面過程

【a】CPU向MMU發送虛擬地址0x10240011,轉換出虛擬頁號爲第66112頁,偏移爲0x11

【b】MMU查詢快表TLB,快表不命中

【c】從高速緩存查詢頁表,高速緩存不命中

【d】從內存中查詢頁表,內存中有進程的完整頁表

【e】把查詢的頁表項記錄到高速緩存

【f】MMU從高速緩存中獲取頁表項,發現虛擬地址沒分配物理頁框,觸發缺頁中斷

【g】進入缺頁中斷處理程序

【h】爲第66112號虛擬頁分配第4097頁框,更新內存頁表

【i】缺頁中斷處理的最後,修改CPU寄存器,使得重新啓動導致缺頁的指令

【A】MMU根據物理頁框號4097查詢高速緩存,發現沒有對應頁框緩存

【B】根據物理地址,獲取物理內存中的數據

【C】硬件實現把第4097頁框加載到高速緩存中

【D】CPU根據物理地址0x01001011,把1K大小的'g'寫入高速緩存中,高速緩存再在合適時候同步到內存中

第3句:p[1] = '\0';

把p[1]的字節寫入'\0'

頁表情況

上圖要點解析:

a.由於上一行代碼已經訪問過對應物理地址,因此TLB和CPU Cache都會命中

CPU尋找頁面過程

【a】CPU向MMU發送虛擬地址 0x10240012,虛擬頁號爲第66112頁,偏移爲0x12

【b】MMU查詢快表TLB快表命中,從快表獲取物理地址爲0x01001012,頁框號爲4097,偏移爲0x12。

【A】MMU獲取物理地址後,根據物理地址查詢高速緩存。高速緩存命中,CPU直接從高速緩存獲取數據

【D】CPU把高速緩存內物理地址爲0x01001012的1字節內容改爲'\0',高速緩存再在合適時候同步到內存中

進程切換和花銷

進程切換時內核要做什麼?

進程切換也叫進程上下文切換。什麼叫進程上下文?

“切換時,一個進程存儲在處理器各寄存器中的中間數據叫做進程的上下文”

所以進程的切換實質上就是被中止運行進程與待運行進程上下文的切換,簡單來說就是把正在CPU中執行的程序的所有信息保存在進程的堆棧中,騰出CPU以及緊缺的CPU寄存器給待執行進程。

進程切換(進場上下文切換)時,內核需要保存舊進程的什麼?需要恢復新進程的什麼?

  1. 保存處理器PC寄存器的值到被中止進程的私有堆棧;  
    PC寄存器指向存放的是下一步要訪問的內存地址
  2. 保存處理器PSW寄存器的值到被中止進程的私有堆棧;  
    PSW寄存器反映處理器的狀態及某些計算結果以及控制指令的執行
  3. 保存處理器其他寄存器的值到被中止進程的私有堆棧;
  4. 保存處理器SP寄存器的值到被中止進程的進程控制塊;
    SP寄存器指向進程私有堆棧棧頂
  5. 刷掉部分TLB和Cache;
    參考網友分析文,其提到TLB和Cache在進程切換時會flush部分TLB和Cache
  6. 自待運行進程的進程控制塊取SP值並存入處理器的寄存器SP;  
  7. 自待運行進程的私有堆棧恢復處理器各寄存器的值;   
  8. 自待運行進程的私有堆棧中彈出PSW值並送入處理器的PSW;
  9. 自待運行進程的私有堆棧中彈出PC值並送入處理器的PC

總結起來,就兩個步驟:

  1. 保存
    把各個寄存器保存在進程私有堆棧中,把私有堆棧指針保存在進程控制塊(struct task)中
  2. 恢復
    從進程控制塊(struct task)中獲取私有堆棧指針,再從私有堆棧中彈出之前保存的各種寄存器

爲什麼說大量進程切換花銷大?

進程切換花銷主要包含直接花銷和間接花銷的2個方面。

  1. 直接花銷
    CPU寄存器需要保存和加載,系統調度器的代碼需要執行。
  2. 間接花銷
    TLB和Cache由於進程切換導致不命中,前期觸發大量的缺頁中斷。

因此,當存在大量的進程切換時,CPU需要做大量的進程上下文切換工作和缺頁中斷,這些花銷是非常可觀的。

本文參考資料

參考書

《計算機操作系統 第三版》

參考鏈接

存儲結構

https://blog.csdn.net/u013471946/article/details/41456055

頁的調入、置換、缺頁、DMA、Cache

http://blog.sina.com.cn/s/blog_a018ffa90101smj8.html
https://baike.baidu.com/item/CPU緩存/3728308?fr=aladdin
http://blog.chinaunix.net/uid-13246637-id-5185352.html
https://blog.csdn.net/zssmcu/article/details/6836869
https://blog.csdn.net/chinesedragon2010/article/details/5922324

TLB

https://baike.baidu.com/item/TLB/2339981?fr=aladdin
http://www.wowotech.net/process_management/context-switch-tlb.html

涉及工具

思維導圖

XMind(https://www.xmind.cn

演示圖

ProcessOn在線畫圖(https://www.processon.com

演示圖分享鏈接

存儲器層次結構
根據物理地址獲取實際數據
獲取物理地址
LRU缺頁算法
小結代碼
虛擬地址與物理地址的映射
頁表
總結圖1
總結圖2
總結圖3
總結圖4
最理想情況下CPU獲取數據

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章