CPU 的上下文切換分三種:進(jìn)程上下文切換、線(xiàn)程上下文切換、中斷上下文切換
。
(資料圖片僅供參考)
上一任務(wù)的CPU上下文保存在哪?
我們知道因?yàn)镃PU過(guò)于昂貴,其性能與其他儲(chǔ)存設(shè)備有數(shù)量級(jí)的差距,為了充分壓榨其性能,計(jì)算機(jī)將CPU的時(shí)間進(jìn)行分片,讓各個(gè)程序在CPU上輪轉(zhuǎn)執(zhí)行,被剝奪執(zhí)行權(quán)的程序,等后面CPU繼續(xù)執(zhí)行它的時(shí)候,這時(shí)需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)保存相關(guān)信息,以便之后恢復(fù)繼續(xù)執(zhí)行,這個(gè)其實(shí)就是進(jìn)程。
CPU上下文會(huì)被保存在進(jìn)程的內(nèi)核空間(kernel space)上。OS在給每個(gè)進(jìn)程分配虛擬內(nèi)存空間時(shí),會(huì)分配一個(gè)內(nèi)核空間,這部分內(nèi)存只能由內(nèi)核代碼訪問(wèn)。OS在切換CPU上下文前,會(huì)先將當(dāng)前CPU的通用寄存器、PC等進(jìn)程現(xiàn)場(chǎng)信息保存在進(jìn)程的內(nèi)核空間上,待下次切換時(shí),再取出重新裝載到CPU上,以恢復(fù)任務(wù)的運(yùn)行。
進(jìn)程上下文切換
內(nèi)核空間和用戶(hù)空間
我們知道為了限制不同的指令的訪問(wèn)能力,提升安全,Linux 按照特權(quán)等級(jí),把進(jìn)程的運(yùn)行空間分為內(nèi)核空間
和用戶(hù)空間
。進(jìn)程既可以在用戶(hù)空間運(yùn)行,又可以在內(nèi)核空間中運(yùn)行。進(jìn)程在用戶(hù)空間運(yùn)行時(shí),被稱(chēng)為進(jìn)程的用戶(hù)態(tài)
,而陷入內(nèi)核空間的時(shí)候,被稱(chēng)為進(jìn)程的內(nèi)核態(tài)
。
常見(jiàn)的內(nèi)核操作:分配內(nèi)存、IO操作、創(chuàng)建子進(jìn)程……
常見(jiàn)的用戶(hù)態(tài)空間程序:數(shù)據(jù)庫(kù)、web服務(wù)器、shell腳本、Java程序或者其他常見(jiàn)語(yǔ)言的程序……
我們一起看下Linux整體架構(gòu)圖:
top命令查看CPU資源
在linux系統(tǒng)使用top
命令查看cpu時(shí),能看到用戶(hù)態(tài)和內(nèi)核態(tài)占用的cpu資源其中各項(xiàng)數(shù)據(jù)表示內(nèi)容:
系統(tǒng)調(diào)用
對(duì)于一個(gè)進(jìn)程來(lái)說(shuō),比如web服務(wù)的進(jìn)程,一般是運(yùn)行在用戶(hù)態(tài)的,但是當(dāng)需要訪問(wèn)內(nèi)存、磁盤(pán)等硬件設(shè)備的時(shí)候需要先進(jìn)入到內(nèi)核態(tài)中,也就是從用戶(hù)態(tài)到內(nèi)核態(tài)的轉(zhuǎn)變,而這種轉(zhuǎn)變需要借助系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)。系統(tǒng)調(diào)用是內(nèi)核向用戶(hù)進(jìn)程提供服務(wù)的唯一方法。
比如查看文件時(shí),需要執(zhí)行多次系統(tǒng)調(diào)用:open()打開(kāi)文件,read()讀取文件內(nèi)容,write()將文件內(nèi)容輸出到控制臺(tái),最后close()關(guān)閉文件等。系統(tǒng)調(diào)用的過(guò)程如下:
我們可以發(fā)現(xiàn)一次系統(tǒng)調(diào)用的過(guò)程,其實(shí)是發(fā)生了兩次 CPU 上下文切換
(用戶(hù)態(tài)-內(nèi)核態(tài)-用戶(hù)態(tài))。
需要注意的是:系統(tǒng)調(diào)用過(guò)程中,不涉及虛擬內(nèi)存等進(jìn)程用戶(hù)態(tài)的資源,也不會(huì)切換進(jìn)程,也就是系統(tǒng)調(diào)用過(guò)程中一直是同一個(gè)進(jìn)程在運(yùn)行。系統(tǒng)調(diào)用過(guò)程也通常稱(chēng)為特權(quán)模式切換。
進(jìn)程上下文切換 和 系統(tǒng)調(diào)用的區(qū)別?
需要注意的是:進(jìn)程是由內(nèi)核來(lái)管理和調(diào)度的,進(jìn)程的切換只能發(fā)生在內(nèi)核態(tài),保存上下文和恢復(fù)上下文的過(guò)程并不免費(fèi),需要消耗一定資源
進(jìn)程切換的常見(jiàn)場(chǎng)景
進(jìn)程切換時(shí)需要切換上下文,換句話(huà)說(shuō),只有在進(jìn)程調(diào)度的時(shí)候,才需要切換上下文。Linux 為每個(gè) CPU 都維護(hù)了一個(gè)就緒隊(duì)列,將活躍進(jìn)程(即正在運(yùn)行和正在等待 CPU 的進(jìn)程)按照優(yōu)先級(jí)和等待 CPU 的時(shí)間排序,然后選擇最需要 CPU 的進(jìn)程,也就是優(yōu)先級(jí)最高和等待 CPU 時(shí)間最長(zhǎng)的進(jìn)程來(lái)運(yùn)行。進(jìn)程切換的場(chǎng)景有:
線(xiàn)程上下文切換
對(duì)操作系統(tǒng)來(lái)說(shuō),進(jìn)程是資源分配的基本單位,而線(xiàn)程則是任務(wù)調(diào)度的基本單位。內(nèi)核中的任務(wù)調(diào)度實(shí)際是在調(diào)度線(xiàn)程,進(jìn)程只是給線(xiàn)程提供虛擬內(nèi)存、全局變量等資源。線(xiàn)程上下文切換時(shí),共享相同的虛擬內(nèi)存和全局變量等資源不需要修改。而線(xiàn)程自己的私有數(shù)據(jù),如棧和寄存器等,上下文切換時(shí)需要保存。
關(guān)于進(jìn)程和線(xiàn)程的區(qū)別:
因此線(xiàn)程上下文切換有兩種情況:
中斷上下文切換
上下文切換有時(shí)也因硬件中斷而觸發(fā)。硬件中斷是指硬件設(shè)備(如鍵盤(pán)、鼠標(biāo)、調(diào)試解調(diào)器、系統(tǒng)時(shí)鐘)給內(nèi)核發(fā)送的一個(gè)信號(hào),該信號(hào)表示一個(gè)事件(如按鍵、鼠標(biāo)移動(dòng)、從網(wǎng)絡(luò)連接接收到數(shù)據(jù))發(fā)生了。
為了快速響應(yīng)硬件的事件,中斷處理會(huì)打斷進(jìn)程的正常調(diào)度和執(zhí)行,然后調(diào)用中斷處理程序,響應(yīng)設(shè)備事件。在打斷其他進(jìn)程時(shí),需要先將進(jìn)程當(dāng)前的狀態(tài)保存下來(lái),等中斷結(jié)束后,進(jìn)程仍然可以恢復(fù)回來(lái)。
跟進(jìn)程上下文不同,中斷上下文切換不涉及進(jìn)程的用戶(hù)態(tài)。所以,即便中斷過(guò)程打斷了一個(gè)正處在用戶(hù)態(tài)的進(jìn)程,也不需要保存和恢復(fù)這個(gè)進(jìn)程的虛擬內(nèi)存、全局變量等用戶(hù)態(tài)資源。中斷上下文,只包括內(nèi)核態(tài)中斷服務(wù)程序執(zhí)行所必需的狀態(tài),也就是 CPU 寄存器、內(nèi)核堆棧、硬件中斷參數(shù)等。
中斷上下文切換并不涉及到進(jìn)程的用戶(hù)態(tài)。所以即便中斷過(guò)程打斷了一個(gè)正處在用戶(hù)態(tài)的進(jìn)程,也不需要保存和恢復(fù)這個(gè)進(jìn)程的虛擬內(nèi)存、全局變量等用戶(hù)態(tài)資源。中斷上下文,其實(shí)只包括內(nèi)核態(tài)中斷服務(wù)程序執(zhí)行所必須的狀態(tài),包括 CPU 寄存器、內(nèi)核堆棧、硬件中斷參數(shù)等。
對(duì)同一個(gè) CPU 來(lái)說(shuō),中斷處理比進(jìn)程擁有更高的優(yōu)先級(jí),所以中斷上下文切換不會(huì)與進(jìn)程上下文切換同時(shí)發(fā)生。并且,由于中斷會(huì)打斷正常進(jìn)程的調(diào)度和執(zhí)行,所以大部分中斷處理程序都短小精悍,以便可以盡快完成。
上下文切換的消耗
上下文切換通常是計(jì)算密集型的。也就是說(shuō),它需要相當(dāng)可觀的處理器時(shí)間,在每秒幾十上百次的切換中,每次切換都需要納秒量級(jí)的時(shí)間。所以,上下文切換對(duì)系統(tǒng)來(lái)說(shuō)意味著消耗大量的 CPU 時(shí)間,事實(shí)上,可能是操作系統(tǒng)中時(shí)間消耗最大的操作。
Linux相比與其他操作系統(tǒng)(包括其他類(lèi) Unix 系統(tǒng))有很多的優(yōu)點(diǎn),其中有一項(xiàng)就是,其上下文切換和模式切換的時(shí)間消耗非常少。
根據(jù)Tsuna的測(cè)試報(bào)告,每次上下文切換都需要幾十納秒到數(shù)微妙的CPU時(shí)間,這個(gè)時(shí)間還是相當(dāng)可觀的。不管是哪種場(chǎng)景導(dǎo)致的上下文切換,你都應(yīng)該知道:
補(bǔ)充:vmstat命令查看整體CPU上下文切換情況
上面已經(jīng)介紹到CPU上下文切換分為進(jìn)程上下文切換、線(xiàn)程上下文切換、中斷上下文切換,那么過(guò)多的上下文切換會(huì)把CPU的時(shí)間消耗在寄存器、內(nèi)核棧以及虛擬內(nèi)存等數(shù)據(jù)的保存和恢復(fù)上,縮短進(jìn)程真正運(yùn)行的時(shí)間,成為系統(tǒng)性能大幅下降的一個(gè)因素
所以我們可以使用vmstat這個(gè)工具來(lái)查詢(xún)系統(tǒng)的上下文切換情況,vmstat是一個(gè)常用的系統(tǒng)性能分析工具,可以用來(lái)分析CPU上下文切換和中斷的次數(shù)執(zhí)行如下的命令:vmstat 5
(每隔5s輸出一組數(shù)據(jù))該命令輸出信息中,各個(gè)字段以及含義:
procs:procs 中有 r 和 b 列,它報(bào)告進(jìn)程統(tǒng)計(jì)信息。在上面的輸出中,在運(yùn)行隊(duì)列(r)中有兩個(gè)進(jìn)程在等待 CPU 并有零個(gè)休眠進(jìn)程(b)。通常,它不應(yīng)該超過(guò)處理器(或核心)的數(shù)量,如果你發(fā)現(xiàn)異常,最好使用 top 命令進(jìn)一步地排除故障。
memory:memory 下有報(bào)告內(nèi)存統(tǒng)計(jì)的 swpd、free、buff 和 cache 列。你可以用 free -m 命令看到同樣的信息。在上面的內(nèi)存統(tǒng)計(jì)中,統(tǒng)計(jì)數(shù)據(jù)以千字節(jié)表示,這有點(diǎn)難以理解,最好添加 M 參數(shù)來(lái)看到以兆字節(jié)為單位的統(tǒng)計(jì)數(shù)據(jù)。
swap:swap 有 si 和 so 列,用于報(bào)告交換內(nèi)存統(tǒng)計(jì)信息。你可以用 free -m 命令看到相同的信息。
I/O:I/O 有 bi 和 bo 列,它以“塊讀取”和“塊寫(xiě)入”的單位來(lái)報(bào)告每秒磁盤(pán)讀取和寫(xiě)入的塊的統(tǒng)計(jì)信息。如果你發(fā)現(xiàn)有巨大的 I/O 讀寫(xiě),最好使用 iotop 和 iostat 命令來(lái)查看。
system:system 有 in 和 cs 列,它報(bào)告每秒的系統(tǒng)操作。
CPU:CPU 有 us、sy、id 和 wa 列,報(bào)告(所用的) CPU 資源占總 CPU 時(shí)間的百分比。如果你發(fā)現(xiàn)異常,最好使用 top 和 free 命令。
補(bǔ)充:pidstat命令查看進(jìn)程的CPU上下文切換情況
執(zhí)行如下的命令:pidstat
,查看進(jìn)程的CPU上下文切換情況如果沒(méi)有安裝,yum install sysstat
安裝即可
在結(jié)果中你能看到如下內(nèi)容:
參考資料:
《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》
《Linux性能優(yōu)化實(shí)戰(zhàn)》
http://ifeve.com/context-switch-definitionhttps://www.it610.com/article/1289356670568308736.htm
這是一口君的新書(shū),感謝大家支持!
精彩文章合集
文章推薦
關(guān)鍵詞: