掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
標(biāo)準(zhǔn)服務(wù)器技術(shù)是網(wǎng)絡(luò)功能虛擬化(NFV)實(shí)現(xiàn)的一個(gè)關(guān)鍵因素,了解一些x86架構(gòu)的基礎(chǔ)知識(shí)對(duì)大家后續(xù)了解電信云關(guān)鍵技術(shù),尤其是掌握虛擬化技術(shù)原理和關(guān)鍵優(yōu)化方案是必須具備的。本文接著上篇從x86架構(gòu)的中斷和異常、IO架構(gòu)等部分進(jìn)行闡述講解。

綠園網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)公司于2013年創(chuàng)立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。
程序的執(zhí)行往往不只是按順序執(zhí)行那么簡(jiǎn)單,一些異常和中斷會(huì)打斷順序執(zhí)行的程序流,轉(zhuǎn)而進(jìn)入一條完全不同的執(zhí)行路徑。中斷提供給外部設(shè)備一種“打斷CPU當(dāng)前執(zhí)行任務(wù),并響應(yīng)自身服務(wù)”的手段。中斷(interrupt)是異步的事件,典型的比如由I/O設(shè)備觸發(fā);異常(exception)是同步的事件,典型的比如處理器執(zhí)行某條指令時(shí)發(fā)現(xiàn)出錯(cuò)了等等,其實(shí)異常的本質(zhì)就是同步中斷。
中斷通常被定義為一個(gè)打斷CPU芯片指令執(zhí)行的事件,該事件對(duì)應(yīng)到CPU芯片內(nèi)部或者外部的電路產(chǎn)生的電子信號(hào)。
中斷信號(hào)可以被劃分為同步中斷和異步中斷:
對(duì)于Intel的CPU而言,它將同步中斷稱作異常,而將異步中斷稱作中斷。
通常中斷(即異步中斷)由時(shí)鐘定時(shí)器或者其他I/O設(shè)備產(chǎn)生,如鍵盤(pán)接收到敲擊某個(gè)按鍵的信號(hào)后產(chǎn)生的中斷信號(hào)。而異常(即同步中斷)則通常由于編程錯(cuò)誤或者由CPU檢測(cè)到異常條件需要內(nèi)核進(jìn)行處理而產(chǎn)生,如上面講到的Page Fault Exception(缺頁(yè)異常),異??梢杂沙绦蛲ㄟ^(guò)int或者sysenter指令主動(dòng)產(chǎn)生。
對(duì)于Intel x86 CPU而言,它將中斷和異常進(jìn)行了如下歸類:
中斷,即異步中斷,中斷信息隨著CPU的時(shí)鐘信號(hào)傳遞到CPU內(nèi)部。中斷分為可屏蔽中斷和不可屏蔽中斷兩類。
異常,即同步中斷,中斷信號(hào)在CPU執(zhí)行完某個(gè)指令后產(chǎn)生并接收到。處理器檢測(cè)到的異常,即當(dāng)CPU執(zhí)行指令的時(shí)候檢測(cè)到硬件上存在一些異常條件的時(shí)候就會(huì)產(chǎn)生該信號(hào)。這種類型的異常根據(jù)產(chǎn)生時(shí)在內(nèi)核堆棧中保存的EIP寄存器的值(即異常恢復(fù)后CPU重新執(zhí)行的位置)進(jìn)行細(xì)分:
我們?cè)趯?xiě)程序時(shí),經(jīng)常會(huì)在容易產(chǎn)生錯(cuò)誤的地方進(jìn)行異常拋出,然后針對(duì)拋出的異常定義執(zhí)行策略。這類編程產(chǎn)生的異常,由程序主動(dòng)執(zhí)行int或者int3之類的指令產(chǎn)生。CPU像處理Traps一樣處理這些程序主動(dòng)產(chǎn)生的異常,該類異常通常被稱為軟件中斷(software interrupt)。這類異常主要有兩種用途:實(shí)現(xiàn)系統(tǒng)調(diào)用和通知某個(gè)debugger特定的事件發(fā)生。
這些異?;蛑袛嘤?~255的數(shù)字唯一標(biāo)識(shí),也就是經(jīng)常說(shuō)的中斷信號(hào)量。對(duì)于不可屏蔽中斷和異常來(lái)說(shuō),相應(yīng)的中斷信號(hào)量是固定的,而可屏蔽中斷對(duì)應(yīng)的中斷信號(hào)量則可以通過(guò)設(shè)置中斷控制器來(lái)更改。
計(jì)算機(jī)所處理的任務(wù)其實(shí)只有兩種:CPU運(yùn)算和I/O操作。這部分內(nèi)容是后續(xù)學(xué)習(xí)計(jì)算虛擬化中I/O虛擬化的基礎(chǔ)。I/O(輸入/輸出)是CPU訪問(wèn)外部設(shè)備的方法。設(shè)備通常通過(guò)寄存器和設(shè)備RAM將自身功能展現(xiàn)給CPU,CPU通過(guò)讀/寫(xiě)這些寄存器和RAM完成對(duì)設(shè)備的訪問(wèn)及其他操作。按訪問(wèn)方式的不同,x86架構(gòu)的I/O分為如下兩類:
即通過(guò)I/O端口訪問(wèn)設(shè)備寄存器。x86有65536個(gè)8位的I/O端口,編號(hào)為0x0~0xFFFF。CPU將端口號(hào)作為設(shè)備端口的地址,進(jìn)而對(duì)設(shè)備進(jìn)行訪問(wèn)。這65536個(gè)端口構(gòu)成了64KB的I/O端口地址空間。I/O端口地址空間是獨(dú)立的,不是線性地址空間或物理地址空間的一部分。需要使用特定的操作命令I(lǐng)N/OUT對(duì)端口進(jìn)行訪問(wèn),此時(shí)CPU通過(guò)一個(gè)特殊的芯片管腳標(biāo)識(shí)這是一次I/O端口訪問(wèn),于是芯片組知道地址線上的地址是I/O端口號(hào)并相應(yīng)地完成操作。此外,2個(gè)或4個(gè)連續(xù)的8位I/O端口可以組成16位或32位的I/O端口。
即通過(guò)內(nèi)存訪問(wèn)的形式訪問(wèn)設(shè)備寄存器或設(shè)備RAM。MMIO要占用CPU的物理地址空間,它將設(shè)備寄存器或設(shè)備RAM映射到物理地址空間的某段地址,然后使用MOV等訪存指令訪問(wèn)此段地址,即可訪問(wèn)到映射的設(shè)備。MMIO方式訪問(wèn)設(shè)備也需要進(jìn)行線性地址到物理地址的轉(zhuǎn)換,但是這個(gè)轉(zhuǎn)換過(guò)程中的MMIO地址不可緩存到TLB中。MMIO是一種更普遍、更先進(jìn)的I/O訪問(wèn)方式,很多CPU 架構(gòu)都沒(méi)有Port I/O,采用統(tǒng)一的MMIO方式。
直接內(nèi)存訪問(wèn)(Direct Memory Access,后文簡(jiǎn)稱為DMA)是所有現(xiàn)代計(jì)算機(jī)的重要特色。DMA允許設(shè)備繞開(kāi)CPU直接向內(nèi)存中復(fù)制或讀取數(shù)據(jù)。如果設(shè)備向內(nèi)存復(fù)制數(shù)據(jù)都經(jīng)過(guò)CPU,則CPU會(huì)有大量中斷負(fù)載,中斷過(guò)程中,CPU對(duì)其他任務(wù)來(lái)講無(wú)法使用,不利于系統(tǒng)性能的提高。通過(guò)DMA,CPU只負(fù)責(zé)初始化這個(gè)傳輸動(dòng)作,而傳輸動(dòng)作本身由DMA 控制器(簡(jiǎn)稱為DMAC)來(lái)實(shí)行和完成。在實(shí)現(xiàn)DMA傳輸時(shí),由DMAC直接控制總線,在DMA傳輸前,CPU要把總線控制權(quán)交給DMAC,結(jié)束DMA傳輸后,DMAC立即把總線控制權(quán)交回給CPU。
一個(gè)完整的DMA 傳輸過(guò)程的基本流程如下:
由此可見(jiàn),DMA無(wú)須CPU直接控制傳輸,也沒(méi)有中斷處理方式那樣保留現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng)的過(guò)程,通過(guò)硬件(DMAC)為RAM與I/O設(shè)備開(kāi)辟了一條直接傳送數(shù)據(jù)的通路,極大地提高了CPU效率。需要注意的是,DMA操作訪問(wèn)的必須是連續(xù)的物理內(nèi)存。DMA 傳輸?shù)倪^(guò)程如下圖所示。
DMA技術(shù)
進(jìn)程是什么呢?大白話講,進(jìn)程就是應(yīng)用程序的啟動(dòng)實(shí)例。比如我們運(yùn)行一個(gè)游戲,打開(kāi)一個(gè)軟件,就是開(kāi)啟了一個(gè)進(jìn)程。進(jìn)程擁有代碼和打開(kāi)的文件資源、數(shù)據(jù)資源、獨(dú)立的內(nèi)存空間。
線程又是什么呢?線程從屬于進(jìn)程,是程序的實(shí)際執(zhí)行者。一個(gè)進(jìn)程至少包含一個(gè)主線程,也可以有更多的子線程。線程擁有自己的棧空間。
進(jìn)程示意圖
對(duì)操作系統(tǒng)來(lái)說(shuō),線程是最小的執(zhí)行單元,進(jìn)程是最小的資源管理單元。無(wú)論進(jìn)程還是線程,都是由操作系統(tǒng)所管理的。線程一般具有五種狀態(tài):初始化>>>可運(yùn)行>>>運(yùn)行中>>>阻塞>>>銷毀。線程不同狀態(tài)之間的轉(zhuǎn)化均需要CPU開(kāi)銷來(lái)完成。
協(xié)程英文Coroutines,是一種比線程更加輕量級(jí)的存在。正如一個(gè)進(jìn)程可以擁有多個(gè)線程一樣,一個(gè)線程也可以擁有多個(gè)協(xié)程。最重要的是,協(xié)程不是被操作系統(tǒng)內(nèi)核所管理,而完全是由程序所控制(也就是在用戶態(tài)執(zhí)行)。這樣帶來(lái)的好處就是性能得到了很大的提升,不會(huì)像線程切換那樣消耗資源。
協(xié)程示意圖
在Python語(yǔ)言中有個(gè)生成器的概念,里面有個(gè)關(guān)鍵字yield,當(dāng)程序執(zhí)行到y(tǒng)ield關(guān)鍵字時(shí),會(huì)暫停在那一行,等到主線程調(diào)用send方法發(fā)送了數(shù)據(jù),協(xié)程才會(huì)接到數(shù)據(jù)繼續(xù)執(zhí)行。但是,yield讓程序暫停,和線程的阻塞是有本質(zhì)區(qū)別的。通過(guò)yield關(guān)鍵字的暫停完全由程序控制,線程的阻塞狀態(tài)是由操作系統(tǒng)內(nèi)核來(lái)進(jìn)行切換。大家可以在Python腳本中寫(xiě)入如下代碼并執(zhí)行體驗(yàn)下:
- def consume():
- while True:
- # consume等待接收數(shù)據(jù)
- number = yield
- print("我要執(zhí)行啦。。。。開(kāi)始計(jì)數(shù):",number)
- consumer = consume()
- next(consumer)
- for num in range(0,100):
- print("開(kāi)始執(zhí)行:",num)
- consumer.send(num)
協(xié)程Python代碼
NFV關(guān)鍵技術(shù):X86架構(gòu)基礎(chǔ)(上篇)
【本文為專欄作者“移動(dòng)Labs”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】
戳這里,看該作者更多好文

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流