從系統的角度分析影響程式執行效能的因素

2022-09-07 17:15:20 字數 3911 閱讀 2927

從使用者的角度到系統底層的順序來看,linux系統包含以下幾個部分:

應用程式:linux系統能夠執行的程式,用於完成使用者所希望的功能

shell程式:用於執行使用者所寫的或者自帶的應用程式

檔案系統:用於組織磁碟上的檔案,規定了檔案的組織和儲存方式

系統呼叫和公用函式庫:作業系統提供的功能函式以及一些庫函式

核心模組:作業系統的核心,具有虛擬記憶體、多工、共享庫、需求載入、可執行程式和網路功能。核心模組分為幾個部分,包含程序管理,儲存管理嗎,檔案系統管理,裝置和驅動管理,網路通訊等

程式的執行過程在作業系統中被抽象成一種任務的執行,也就是程序。程序在linux下的表示形式是task_struct資料結構,叫做程序控制塊。

(1)程序控制塊(task_struct)

程序控制塊包含了和程序相關的資料內容,包括程序的狀態,程序雙向鍊錶的管理,以及控制台tty、檔案系統fs的描述、程序開啟檔案的檔案描述符files、記憶體管理的描述mm,還有程序間通訊的訊號signal的描述等。

當作業系統建立乙個新的程序時,就會為這個程序建立乙個程序控制塊,標識這個程序的存在,並為這個程序分配相應的棧空間,將程序控制塊掛載到相應的佇列上(程序的狀態佇列,阻塞,就緒等)。

(2)程序的建立

linux下的程序,除了0號程序是通過硬編碼方式來初始化程序描述符,其餘都是通過複製父程序的程序描述符來完成初始化的。

初始狀態下,linux在start_kernel中通過硬編碼方式初始化第乙個程序的程序描述符。後續的使用者態程序和核心執行緒通過複製0號程序來完成。

(3)程序的切換

程序在切換前需要決定下乙個執行的程序,這需要程序排程的功能。

程序排程需要:

程序的上下文包含:

在程序狀態結束、用完時間片、從系統呼叫或者中斷結束時返回使用者態時會發生程序排程。

程序的切換過程:

首先程序通過中斷或者系統呼叫進入核心態,儲存cpu現場,通過更換cs:eip暫存器切換為核心堆疊,將程式的下乙個執行位址設定成系統呼叫程式或者中斷處理程式的入口位址,之後儲存現場,執行程式。

執行完成後會檢查對應是否需要程序排程的標誌。程序的上下文切換,包含更換頁表暫存器的切換(更換為新程序的位址空間),更換核心堆疊(換為新程序的核心堆疊),載入新程序的程序控制塊和cpu上下文(儲存在task_struct的thread變數中),之後沿著新程序在之前程序排程時呼叫的schedule函式的呼叫棧返回到中斷程式的結束位置,返回使用者態。

中斷的主要功能是平衡cpu和外設之間的速度差異,處理器速度一般比外設速度快很多,只有當外設處理好之後cpu才轉過來處理外設。中斷就是用於在cpu處理其他事情時通知cpu來處理外設。

中斷分為硬體中斷和軟體中斷,硬體中斷用於外設準備好後之後的處理。而軟體中斷則是指令產生的中斷呼叫,分為故障、陷阱和退出。在發生中斷時,程序進入核心態,將當前執行到的位置的狀態儲存,將指令流切換成中斷處理程式的執行,在執行完成後才會將儲存的暫存器狀態恢復,返回並繼續之前的執行。

每個中斷由0-255之間的數字來標識對應的中斷向量。通過中斷向量就可找到對應的中斷處理程式。

在中斷處理前,需要儲存cpu上下文在堆疊中,以便中斷處理結束後恢復現場繼續執行。

中斷的硬體處理過程:

確定中斷向量號

從中斷向量表中獲取中斷處理程式的位址

檢查是否由使用者態進入了核心態,如果是,則需要將堆疊切換成核心堆疊

在核心堆疊中儲存eflags,cs,eip暫存器的內容。將中斷處理程式的入口裝載。開始執行。

處理完成後,呼叫iret指令,彈出之前儲存的內容。如果程序是使用者態被中斷的,就恢復到使用者態,否則再裝載ss和esp暫存器,返回之前的核心棧。

中斷用於裝置的處理,而系統呼叫是建立在中斷基礎上的應用,作業系統提供了很多功能,相對於使用者自己寫的程式更加穩定,安全,包括程序的建立,資源的分配,記憶體分配等。使用者程式通過呼叫相關的命令,發出中斷,陷入核心態,核心程式呼叫相應的系統呼叫處理程式來完成使用者程式所希望的功能。

檔案系統

在磁碟上不同的檔案系統有不同的組織方式,包括空閒塊,已分配的塊,目錄檔案,資源檔案等。其中有乙個超級塊結構記錄了檔案系統的相關資訊,如空閒塊和分配塊的位置,數量等。

而乙個作業系統可以掛載多個不同的檔案系統,這是通過核心的虛擬檔案系統(vfs)完成的,對使用者程式隱去各種不同檔案系統的實現細節,為使用者程式提供乙個統一的、抽象的、虛擬的檔案系統介面。當檔案系統掛載到作業系統時,作業系統在核心中建立乙個vfs超級塊,將磁碟上的超級塊讀取進來,初始化vfs超級塊。

每個程序通過open系統呼叫來與具體的檔案建立連線。該連線用乙個file資料結構來表示,結構中有個型別為file_operations的指標域f_op。將指標域f_op設定成指向某個具體的檔案系統所提供的一組操作函式。當核心將乙個索引節點裝入記憶體是,會在file_operations資料結構中存放乙個指向這些檔案操作的指標。之後read,write等系統呼叫就會通過這個指標來操作實際檔案系統上的內容了。

核心維持乙個系統開啟檔案表,其中儲存的是inode節點,代表的是各個檔案,而程序儲存了乙個程序開啟檔案表,其中儲存了各個inode節點的索引,之後就可以通過檔案描述符訪問系統開啟檔案表(訪問檔案)了。

裝置驅動

裝置在核心中是以檔案的形式存在的,相應的,對應的操作也就被初始化為裝置驅動程式中對應的函式。

linux作業系統採用虛擬記憶體的管理方式,使得程序之間不會互相干擾。使用者程序部分分段儲存內容可由棧、堆、bss段、資料段、**段組成。 在將應用程式載入到記憶體空間執行時,作業系統負責**段、資料段和bss段的載入,並在記憶體中為這些段分配空間。棧也由作業系統分配和管理;堆由程式設計師自己管理,即顯式地申請和釋放空間。

linux系統會不時的進行頁面交換操作,以保持盡可能多的空閒物理記憶體,即使並沒有什麼事情需要記憶體,linux也會交換出暫時不用的記憶體頁面。這可以避免等待交換所需的時間。

linux進行頁面交換是有條件的,不是所有頁面在不用時都交換到虛擬記憶體,linux核心根據」最近最經常使用「演算法,僅僅將一些不經常使用的頁面檔案交換到虛擬記憶體。

交換空間的頁面在使用時會首先被交換到物理記憶體,如果此時沒有足夠的物理記憶體來容納這些頁面,它們又會被馬上交換出去,如此以來,虛擬記憶體中可能沒有足夠空間來儲存這些交換頁面,最終會導致linux出現假死機、服務異常等問題,linux雖然可以在一段時間內自行恢復,但是恢復後的系統已經基本不可用了。

當程序讀寫檔案時,首先呼叫open系統呼叫,通過系統呼叫陷入到核心,之後查詢中斷向量表後呼叫對應的中斷處理程式,執行sys_open函式,這個函式會在磁碟上找到對應的檔案控制塊,根據不同檔案系統的open函式來建立file檔案型別,儲存在系統開啟檔案表中,這個結構中儲存了檔案對應的資訊,包括大小型別,讀寫指標等。程序也有乙個程序開啟檔案表,其中儲存的是系統開啟檔案表的索引。

之後程序使用read系統呼叫即可對file資料結構進行相關操作,依據返回的檔案描述符就能找到對應的file檔案。之後通過file檔案中的file_operation資料結構儲存的函式指標呼叫相關函式。

影響程式表現的因素有很多:

比如io密集型的程式會受到cpu核心數的影響,需要頻繁讀取的程式會受到cache命中率的影響,多執行緒程式會受到切換執行緒的頻率的影響,此外還有記憶體大小等。

舉例:(1)多執行緒程式若需要頻繁切換執行緒,應該考慮使用執行緒池或者協程,執行緒池是為了減少執行緒的建立和銷毀,執行緒也需要有執行緒描述符和相關的執行緒堆疊來維持執行緒的執行環境。協程則是將核心執行緒拆分成多個使用者級執行緒,也就是說核心不知道協程的存在,切換協程只是將當前執行緒的執行映像儲存,切換到另乙個執行映像,卻不需要核心態的幫助。

(2)陣列的遍歷過程,盡量按照儲存順序訪問,這樣cache的命中率最高,防止直接從記憶體中讀取,這樣相對於從cache中讀取會慢很多。

當然具體的程式需要具體分析,比如多執行緒程式,對於io密集型執行緒,執行緒的個數最好是cpu核心數的兩倍,對於cpu密集型,最好是cpu核心數減一或者加一,這都是需要根據程式的需求來確定的。

從系統的角度分析影響程式執行效能的因素

目錄1.2 記憶體管理 1.3 檔案管理 1.4 驅動裝置程式 1.5 具體例子 2.影響應用程式效能表現的因素 作業系統按照功能可以劃分為程序管理 記憶體管理 檔案管理以及裝置管理,而linux核心也對此進行了實現 程序管理可以說是作業系統核心中最為核心的部分,其主要完成的一些功能可以概述為如下幾...

hello程式的執行過程 從計算機系統角度

2 初始時,shell程式執行它的指令,等待我們輸入乙個命令。當我們在鍵盤上輸入字串 hello 後,shell程式將字元讀入cpu的暫存器中,再把它存放到主存中。3 當我們敲回車鍵時,結束命令的輸入,然後shell程式執行一系列指令來載入可執行的hello檔案,這些指令將hello目標檔案中的 和...

23 從物理執行的角度透視 spark job

即使採用pipeline的方式,函式f對依賴的rdd中的資料操作也會有兩種方式 1,f record f作用於集合的每一條記錄,每次只作用於一條記錄 2,f records f一次性作用於集合的全部資料 spark的實現,是採用第一種方式,為什麼採用第一種方式,原因 1,無需等待,可以最大化的使用集...