在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux CPU的性能應該如何優(yōu)化

Wildesbeast ? 來源:今日頭條 ? 作者:底層軟件架構 ? 2020-01-18 08:52 ? 次閱讀

Linux系統(tǒng)中,由于成本的限制,往往會存在資源上的不足,例如 CPU、內存、網(wǎng)絡、IO 性能。本文,就對 Linux 進程和 CPU 的原理進行分析,總結出 CPU 性能優(yōu)化的方法。

1. 分析手段

在理解平均負載之前,先要理清楚 Linux 下的進程狀態(tài)。

1.1. 進程狀態(tài)

1.1.1. R (TASK_RUNNING),可執(zhí)行狀態(tài)

只有在該狀態(tài)的進程才可能在 CPU 上運行。而同一時刻可能有多個進程處于可執(zhí)行狀態(tài),這些進程的 task_struct 結構(進程控制塊)被放入對應 CPU 的可執(zhí)行隊列中(一個進程最多只能出現(xiàn)在一個 CPU 的可執(zhí)行隊列中)。進程調度器的任務就是從各個 CPU 的可執(zhí)行隊列中分別選擇一個進程在該 CPU 上運行。

很多操作系統(tǒng)教科書將正在 CPU 上執(zhí)行的進程定義為 RUNNING 狀態(tài)、而將可執(zhí)行但是尚未被調度執(zhí)行的進程定義為READY狀態(tài),這兩種狀態(tài)在linux下統(tǒng)一為 TASK_RUNNING 狀態(tài)。

1.1.2. S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態(tài)

處于這個狀態(tài)的進程因為等待某某事件的發(fā)生(比如等待 socket 連接、等待信號量),而被掛起。這些進程的 task_struct 結構被放入對應事件的等待隊列中。當這些事件發(fā)生時

(由外部中斷觸發(fā)、或由其他進程觸發(fā)),對應的等待隊列中的一個或多個進程將被喚醒。通過 ps 命令我們會看到,一般情況下,進程列表中的絕大多數(shù)進程都處于 TASK_INTERRUPTIBLE 狀態(tài)(除非機器的負載很高)。畢竟 CPU 就這么一兩個,進程動輒幾十上百個,如果不是絕大多數(shù)進程都在睡眠,CPU 又怎么響應得過來。

1.1.3. D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)

與 TASK_INTERRUPTIBLE 狀態(tài)類似,進程處于睡眠狀態(tài),但是此刻進程是不可中斷的。

不可中斷,指的并不是 CPU 不響應外部硬件的中斷,而是指進程不響應異步信號。

絕大多數(shù)情況下,進程處在睡眠狀態(tài)時,總是應該能夠響應異步信號的。否則你將驚奇的發(fā)現(xiàn),kill -9 竟然殺不死一個正在睡眠的進程了!于是我們也很好理解,為什么 ps 命令看到的進程幾乎不會出現(xiàn) TASK_UNINTERRUPTIBLE 狀態(tài),而總是 TASK_INTERRUPTIBLE 狀態(tài)。

而 TASK_UNINTERRUPTIBLE 狀態(tài)存在的意義就在于,內核的某些處理流程是不能被打斷的。如果響應異步信號,程序的執(zhí)行流程中就會被插入一段用于處理異步信號的流程(這個插入的流程可能只存在于內核態(tài),也可能延伸到用戶態(tài)),于是原有的流程就被中斷了。

(參見《linux 內核異步中斷淺析》) 在進程對某些硬件進行操作時(比如進程調用 read 系統(tǒng)調用對某個設備文件進行讀操作,而 read 系統(tǒng)調用最終執(zhí)行到對應設備驅動的代碼,并與對應的物理設備進行交互),可能需要使用 TASK_UNINTERRUPTIBLE 狀態(tài)對進程進行保護,以避免進程與設備交互的過程被打斷,造成設備陷入不可控的狀態(tài)。這種情況下的 TASK_UNINTERRUPTIBLE 狀態(tài)總是非常短暫的,通過 ps 命令基本上不可能捕捉到。

1.1.4. T (TASK_STOPPED or TASK_TRACED),暫停狀態(tài)或跟蹤狀態(tài)

向進程發(fā)送一個 SIGSTOP 信號,它就會因響應該信號而進入 TASK_STOPPED 狀態(tài)(除非該進程本身處于 TASK_UNINTERRUPTIBLE 狀態(tài)而不響應信號)。(SIGSTOP 與 SIGKILL 信號一樣,是非常強制的。不允許用戶進程通過 signal 系列的系統(tǒng)調用重新設置對應的信號處理函數(shù)。)

向進程發(fā)送一個 SIGCONT 信號,可以讓其從 TASK_STOPPED 狀態(tài)恢復到 TASK_RUNNING 狀態(tài)。

當進程正在被跟蹤時,它處于 TASK_TRACED 這個特殊的狀態(tài)。“正在被跟蹤”指的是進程暫停下來,等待跟蹤它的進程對它進行操作。比如在 gdb 中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處于 TASK_TRACED 狀態(tài)。而在其他時候,被跟蹤的進程還是處于前面提到的那些狀態(tài)。

對于進程本身來說,TASK_STOPPED 和 TASK_TRACED 狀態(tài)很類似,都是表示進程暫停下來。而 TASK_TRACED 狀態(tài)相當于在 TASK_STOPPED 之上多了一層保護,處于 TASK_TRACED 狀態(tài)的進程不能響應 SIGCONT 信號而被喚醒。只能等到調試進程通過 ptrace 系統(tǒng)調用執(zhí)行 PTRACE_CONT、PTRACE_DETACH 等操作(通過 ptrace 系統(tǒng)調用的參數(shù)指定操作),或調試進程退出,被調試的進程才能恢復 TASK_RUNNING 狀態(tài)。

1.1.5. Z (TASK_DEAD - EXIT_ZOMBIE),退出狀態(tài),進程成為僵尸進程

進程在退出的過程中,處于 TASK_DEAD 狀態(tài)。在這個退出過程中,進程占有的所有資源將被回收,除了 task_struct 結構(以及少數(shù)資源)以外。于是進程就只剩下 task_struct 這么個空殼,故稱為僵尸。之所以保留 task_struct,是因為 task_struct 里面保存了進程的退出碼、以及一些統(tǒng)計信息。而其父進程很可能會關心這些信息。比如在 shell 中,$?變量就保存了最后一個退出的前臺進程的退出碼,而這個退出碼往往被作為 if 語句的判斷條件。

當然,內核也可以將這些信息保存在別的地方,而將 task_struct 結構釋放掉,以節(jié)省一些空間。但是使用 task_struct 結構更為方便,因為在內核中已經建立了從 pid 到 task_struct 查找關系,還有進程間的父子關系。釋放掉 task_struct,則需要建立一些新的數(shù)據(jù)結構,以便讓父進程找到它的子進程的退出信息。

父進程可以通過 wait 系列的系統(tǒng)調用(如 wait4、waitid)來等待某個或某些子進程的退出,并獲取它的退出信息。然后 wait 系列的系統(tǒng)調用會順便將子進程的尸體(task_struct)也釋放掉。

子進程在退出的過程中,內核會給其父進程發(fā)送一個信號,通知父進程來“收尸”。這個信號默認是 SIGCHLD,但是在通過 clone 系統(tǒng)調用創(chuàng)建子進程時,可以設置這個信號。

1.2. 平均負載

單位時間內,系統(tǒng)處于可運行狀態(tài)和不可中斷狀態(tài)的平均進程數(shù),也就是平均活躍進程數(shù),它和 CPU 使用率并沒有直接關系。

既然是平均的活躍進程數(shù),那么最理想的,就是每個cpu 上都剛好運行著一個進程,這樣每個 cpu 都得到了充分利用,比如當平均負載 2時,意味著什么呢?

1、 在只有2 個 CPU的系統(tǒng)上,意味著所有的 CPU都剛好被完全占用

2、 在 4 個CPU的系統(tǒng)上,意味著 CPU 有 50%的空閑

3、 而在只有 1 個CPU 的系統(tǒng)上,則意味著有一半的進程競爭不到 CPU

1.2.1. 平均負載多少合理?

平均負載最理想的情況是等于 CPU 個數(shù)。查看系統(tǒng) CPU 的命令如下:

cat /proc/cpuinfo

Figure 1 四核 CPU 查看平均負載的命令:

給了我們三個不同時間間隔的平均值,給我們提供了分析系統(tǒng)負載趨勢的數(shù)據(jù)來源,讓我們更全面、更立體地理解目前的負載情況。

· 1 分鐘、5 分鐘、15 分鐘 的三個值基本相同,或者相差不大,說明系統(tǒng)負載很平

· 如果1 分鐘的值遠小于15 分鐘 的值,說明系統(tǒng)最近 1 分鐘的負載在減少,而過去

15 分鐘內卻有很大的負載

· 如果1 分鐘 的值遠大于 15 分鐘的值,就說明最近 1 分鐘的負載在增加。一旦 1 分鐘的平均負載接近或超過了 CPU 的個數(shù),就意味著系統(tǒng)正在發(fā)生過載的問題。

uptime 命令在有些嵌入式設備中,會被裁減掉,但是可以通過 proc 文件系統(tǒng)來獲取。命令:

cat /proc/loadavg

很顯然,當前命令展示的平均負載在 CPU 為 4 個時候已經過載

1.2.2. 平均負載與 CPU 使用率

平均負載不僅包括了正在使用 CPU 的進程,還包括了等待 CPU 和等待 I/O 的進程。

CPU 使用率是指單位時間內 CPU 繁忙情況的統(tǒng)計,跟平均負載并不一定完全對應。比如:

· CPU 密集型進程,使用大量 CPU 會導致平均負載升高,此時這兩者是一致的;

· I/O 密集型進程,等待 I/O 也會導致平均負載升高,但 CPU 使用率不一定很高

· 大量等待 CPU 的進程調度也會導致平均負載升高,此時的 CPU 使用率也會比較高。

1.3. CPU 上下文切換

在每個任務運行前, CPU 都需要知道任務從哪里加載、又從哪里開始運行、也就是說,需要系統(tǒng)事先給他設置好 CPU 寄存器和程序計數(shù)器(Program Counter, PC)

· CPU 寄存器:是 CPU 內置的容量小、但速度極快的內存。

· 程序計數(shù)器:是用來存儲 CPU 正在執(zhí)行的指令位置、或者即將執(zhí)行的下一條指令位置。

它們都是 CPU 在運行任何任務前,比如的依賴環(huán)境,因此也被叫做 CPU 上下文。

· 上下文切換:就是先把前一個任務的 CPU 上下文(也就是 CPU 寄存器和程序計數(shù)器)保存起來,然后加載新任務的上下文到這些寄存器和程序計數(shù)器,最后再跳轉到程序計數(shù)器所指的新位置,運行新任務。

· CPU 的上下文切換可以分為進程上下文切換、線程上下文切換以及中斷上下文切換。

1.3.1. 進程上下文切換

Linux 按照特權等級,把進程的運行空間分為內核空間和用戶空間

· 內核空間(Ring 0)具有最高權限,可以直接訪問所有資源。

· 用戶空間(Ring 3)只能訪問受限資源,不能直接訪問內存等硬件設備,必須通過系統(tǒng)調用陷入到內核中,才能訪問這些特權資源。

1.3.2. 進程上下文切換和系統(tǒng)調用的區(qū)別

進程是由內核來管理和調度的,進程的切換只能發(fā)生在內核態(tài)。所以,進程的上下文不僅包括了虛擬內存、棧、全局變量等用戶空間的資源,還包括了內核堆棧、寄存器等內核空間的狀態(tài)。

系統(tǒng)調用過程中,并不涉及到虛擬內存等進程用戶態(tài)的資源,也不會切換進程。

· 進程上下文切換,是指從一個進程切換到另一個進程進行。

· 系統(tǒng)調用過程中一直是同一個進程在運行。

因此,進程的上下文切換比系統(tǒng)調用時多了一步:在保存當前進程的內核狀態(tài)和 CPU 寄存器之前,需要先把該進程的虛擬內存、棧等保存下來;而加載了下一個進程的內核態(tài)后,還需要刷新進程的虛擬內存和用戶棧。

1.3.3. 什么時候會切換進程上文

· 進程執(zhí)行終止,它之前使用的 CPU 會釋放出來,這時再從就緒隊列里,拿一個新的進程過來運行。

· 當某個進程的時間片耗盡了,就會被系統(tǒng)掛起,切換到其他正在等待 CPU 的進程進行

· 進程在系統(tǒng)資源不足(比如內存不足)時,等到資源滿足后才可以運行,這個時候進程也會被掛起,并由系統(tǒng)調度其他進程運行。

· 當進程通過睡眠函數(shù) sleep 這樣的方法將自己主動掛起時,自然也會重新調度。

· 當有優(yōu)先級更高的進程運行時,為了保證高優(yōu)先級進程的運行,當前進程會被掛起,由高優(yōu)先級進程來運行。

· 發(fā)生硬件中斷時,CPU 上的進程會被中斷掛起,轉而執(zhí)行內核中的中斷程序服務。

1.3.4. 線程上下文切換

線程和進程的區(qū)別

· 線程是調度的基本單位,而進程則是資源擁有的基本單位。

· 當進程只有一個線程時,可以認為進程就等于線程。

· 當進程擁有多個線程時,這些線程會共享相同的虛擬內存和全局變量等資源。這些資源在上下文切換時是不需要修改的。

· 線程也有自己的私有數(shù)據(jù),比如棧和寄存器等,這些在上下文切換時也是需要保存的。

線程的上下文切換兩種情況

· 前后兩個線程屬于不同進程。此時,因為資源不共享,所以切換過程就跟進程上下文切換是一樣的。

· 前后兩個線程屬于同一個進程。此時,因為虛擬內存是共享的,所以在切換時,虛擬內存這些資源就保持不動,只需要切換線程的私有數(shù)據(jù)、寄存器等不共享的數(shù)據(jù)。

1.3.5. 中斷上下文切換

中斷處理會打斷進程的正常調度和執(zhí)行。在打斷其他進程時,需要將進程當前的狀態(tài)保存下來,中斷結束后,進程仍然可以從原來的狀態(tài)恢復運行。

進程上下文切換和中斷上下文切換的區(qū)別

· 中斷上下文切換并不涉及到進程的用戶態(tài)。所以,即便中斷過程打斷了一個正處在用戶態(tài)的進程,也不需要保存和恢復這個進程的虛擬內存、全局變量等用戶態(tài)資源。中斷上下文,其實只包括內核態(tài)中斷服務程序執(zhí)行所必須的狀態(tài),包括 CPU 寄存器、內核堆棧、硬件中斷參數(shù)等。

· 對同一個 CPU 來說,中斷處理比進程擁有更高的優(yōu)先級。

進程上下文切換和中斷上文切換的相同之處

· 都需要消耗 CPU,切換次數(shù)過多會耗費大量 CPU,甚至嚴重降低系統(tǒng)的整體性能。

1.3.6. CPU 上下文切換小結

· CPU 上下文切換,是保證 Linux 系統(tǒng)正常工作的核心功能之一,一般情況下不需要我們特別關注。

· 但過多的上下文切換,會把 CPU 時間消耗在寄存器、內核棧以及虛擬內存等數(shù)據(jù)的保存和恢復上,從而縮短進程真正運行的時間,導致系統(tǒng)的整體性能大幅下降

1.3.7. 如何查看系統(tǒng)的上下文切換

常用的系統(tǒng)性能分析工具,主要用來分析系統(tǒng)的內存使用情況,也常用來分析

CPU 上下文切換和中斷次數(shù)。

Figure 2 每隔 2 秒輸出一組數(shù)據(jù)

需要特別關注的四列內容:

· cs (context switch):每秒上下文切換的次數(shù)。

· in (interrupt):每秒中斷的次數(shù)。

· r (Running or Runnable) :就緒隊列的長度,也就是正在運行和等待 CPU 的進程數(shù)。

· b (Blocked):處在不可中斷睡眠狀態(tài)的進程數(shù)。

在嵌入式 Linux 設備中,一般 vmstat 工具是不存在的。所以如果想要 vmstat 工具,可以自己實現(xiàn)代碼,他的原理是獲取/proc/diskstats 和/proc/slabinfo 的信息組合而成。實現(xiàn)代碼見 procps 工具

vmstat 只給出了系統(tǒng)總體的上下文切換情況,并不能查看每個進程的上下文切換情況。

:查看某個進程中線程的上下文切換情況,下圖查看的是 hicore 進程中所有的線程上下文切換情況。

關注兩列內容:

1. 自愿上下文切換:進程無法獲取所需資源,導致的上下文切換。比如, I/O、內存等系統(tǒng)資源不足時。

2. 非自愿上下文切換:進程由于時間片已到等原因,被系統(tǒng)強制調度,進而發(fā)生的上下文切換。比如,大量進程都在爭搶 CPU 時。

1.3.9. Procps 工具

procps 是一組命令行和全屏工具,是由內核動態(tài)生成的一個 “偽” 文件系統(tǒng),可以提供進程表中條目狀態(tài)的信息。該文件系統(tǒng)為內核數(shù)據(jù)結構提供了一個簡易接口,procps 程序通常就集中在這個描述了系統(tǒng)進程運行狀態(tài)的數(shù)據(jù)結構上。

procps 包括以下程序:

· free - 報告系統(tǒng)中可用內存和已用內存的數(shù)量

· kill - 基于 PID,向進程發(fā)送信號

· pgrep - 根據(jù)名稱或其他屬性列出進程

· pkill - 根據(jù)名稱或其他屬性向進程發(fā)送信號

· pmap - 報告進程的內存映射

· ps - 報告進程信息

· pwdx - 報告進程的當前目錄

· skill - pgrep/pkill 的過時版本

· slabtop - 實時顯示內核 slab 緩存信息

· snice - Renice 一個進程

· sysctl -運行時內核參數(shù)的讀或寫

· tload - 系統(tǒng)負載均值的可視化

· top - 正運行進程的實時動態(tài)視圖

· uptime - 顯示系統(tǒng)的已運行時間和負載情況

· vmstat - 報告虛擬內存統(tǒng)計信息

· w - 報告登錄用戶,以及他們正在做什么

· watch - 定期執(zhí)行程序,顯示全屏輸出官網(wǎng)地址:http://procps.sourceforge.net/

1.3.10. sysstat 工具

在嵌入式 Linux 設備中同樣也不存在該工具,busybox 中也沒有相關命令。需要安裝 Linux 性能監(jiān)控工具 sysstat,他是一個工具集,包括 sar、sadf、mpstat、iostat、pidstat 等,這些工具可以監(jiān)控系統(tǒng)性能和使用情況。各工具的作用如下:

1. iostat - 提供 CPU 統(tǒng)計,存儲 I/O 統(tǒng)計(磁盤設備,分區(qū)及網(wǎng)絡文件系統(tǒng))

2. mpstat - 提供單個或組合 CPU 相關統(tǒng)計

3. pidstat - 提供 Linux 進程級別統(tǒng)計:I/O、CPU、內存等

4. sar - 收集、報告、保存系統(tǒng)活動信息:CPU、內存、磁盤、中斷、網(wǎng)絡接口、TTY、內核表等

5. sadc - 系統(tǒng)活動數(shù)據(jù)收集器,作為 sar 后端使用

6. sa1 - 收集系統(tǒng)活動日常數(shù)據(jù),并二進制格式存儲,它作為 sadc 的工具的前端,可以通過 cron 來調用

7. sa2 - 生成系統(tǒng)每日活動報告,同樣可作為 sadc 的工具的前端,可以通過 cron 來調用

8. sadf - 可以以 CSV、XML 格式等顯示 sar 收集的性能數(shù)據(jù),這樣非常方便的將系統(tǒng)數(shù)據(jù)導入到數(shù)據(jù)庫中,或導入到 Excel 中來生成圖表

9. nfsiostat-sysstat: 提供 NFS I/O 統(tǒng)計

10. cifsiostat: 提供 CIFS 統(tǒng)計

sysstat 功能強大,功能也在不斷的增強,每個版本提供了不同的功能,可以到 sysstat 官網(wǎng)了 解 工 具 最 先 發(fā) 展 情 況 和 獲 得 相 應 的 幫 助 手 冊 。 官 網(wǎng) 地 址 :

1.3.11. 中斷

中斷是一種異步的事件處理機制,可以提高系統(tǒng)的并發(fā)處理能力。中斷處理程序會打斷其他進程的運行,為了減少對正常進程運行調度的影響,中斷處理程序就需要盡可能快地運行。

Linux 將中斷處理過程分成了兩個階段,也就是上半部和下半部。

· 上半部用來快速處理中斷,它在中斷禁止模式下運行,主要處理跟硬件緊密相關的或時間敏感的工作。

· 下半部用來延時處理上半部未完成的工作,通常以內核線程的方式運行。

/proc/interrupts:查看硬中斷發(fā)生的類型

硬件中斷發(fā)生頻繁,是件很消耗 CPU 資源的事情,Linux 默認情況下是將所有的硬件中斷都綁定在 CPU0 上,在多核 CPU 條件下如果有辦法把大量硬件中斷分配給不同的

CPU (core) 處理顯然能很好的平衡性能。

1.3.13. 根據(jù)上下文切換的類型做具體分析

· 自愿上下文切換變多,說明進程都在等待資源,有可能發(fā)生 I/O 等其他問題

· 非自愿上下文切換變多,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸

· 中斷次數(shù)變多,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。

1.4. CPU 使用率

/proc/stat,提供的是系統(tǒng)的 CPU 和任務統(tǒng)計信息。這個信息非常的原始

CPU 使用率相關的重要指標

· 第一列:user(us),代表用戶態(tài) CPU 時間。

· 第二列:nice(ni),代表低優(yōu)先級用戶態(tài) CPU 時間,也就是進程的 nice 值被調整為 1-

19 之間時的 CPU 時間。nice 可取值范圍是 -20 到 19, 數(shù)值越大,優(yōu)先級反而越低

· 第三列:system (sys),代表內核態(tài) CPU 時間。

· 第四列:idle(us),代表空閑時間。注意,這里它不包括等待 I/O 的時間(iowait)。

· 第五列:iowait(wa),代表等待 I/O 的 CPU 時間。

· 第六列:irq(hi),代表處理硬中斷的 CPU 時間

· 第七列:softirq(si),代表處理軟中斷的 CPU 時間。

真正查看 CPU 使用率的命令是通過 top 命令

1.5. 軟中斷

提供了軟中斷的運行情況。

· 注意軟中斷的類型,也就是第一列內容。

· 注意同一種軟中斷在不同 CPU 上的分布情況,也就是同一行內容。

· 軟中斷實際上是以內核線程的方式運行的,每個 CPU 都對應一個軟中斷內核線程,這個軟中斷內核線程就叫做 ksoftirqd/CPU 編號

2. 優(yōu)化方法

2.1 CPU 使用率

CPU 使用率描述了非空閑時間占總 CPU 時間的百分比,根據(jù) CPU 上運行任務的不同,又被分為用戶 CPU、系統(tǒng) CPU、等待 I/O CPU、軟中斷和硬中斷等。

· 用戶 CPU 使用率,包括用戶態(tài) CPU 使用率(user) 和低優(yōu)先級用戶態(tài) CPU 使用率 (nice),表示 CPU 在用戶態(tài)運行的時間百分比。用戶 CPU 使用率高,通常說明有應用程序比較繁忙。

· 系統(tǒng) CPU 使用率,表示 CPU 在內核態(tài)運行的時間百分比(不包括中斷)。系統(tǒng) CPU 使用率高,說明內核比較繁忙。

· 等待 I/O 的 CPU 使用率,通常也稱為 iowait,表示等待 I/O 的時間百分比。iowait 高,通常說明系統(tǒng)與硬件設備的 I/O 交互時間比較長。

· 軟中斷和硬中斷的 CPU 使用率,分別表示內核調用軟中斷處理程序、硬中斷處理程序的時間百分比。它們的使用率高,通常說明系統(tǒng)發(fā)生了大量的中斷。

2.2 平均負載(Load Average)

平均負載,也就是系統(tǒng)的平均活躍進程數(shù),它反映了系統(tǒng)的整體負載情況,主要包括三個數(shù)值,分別指過去 1 分鐘、過去 5 分鐘和過去 15 分鐘的平均復制子。

理想情況下,平均負載等于邏輯 CPU 個數(shù),這表示每個 CPU 都恰好被充分利用。如果平均負載大于邏輯 CPU 個數(shù),就表示負載比較重了。

2.3 進程上下文切換

· 無法獲取資源而導致的自愿上下文切換。

· 被系統(tǒng)強制調度導致的非自愿上下文切換。

2.4 CPU 緩存的命中率

由于 CPU 發(fā)展的速度遠快于內存的發(fā)展, CPU 的處理速度就比內存的訪問速度快得多。這樣,CPU 在訪問內存的時候,免不了要等待內存的響應。為了協(xié)調這兩者巨大的性能差距,CPU 緩存(通常是多級緩存)就出現(xiàn)了。

根據(jù)不斷增長的熱點數(shù)據(jù),這些緩存按照大小不同分為 L1、L2、L3 等三級緩存,其中

L1 和 L2 常用在單核中,L3 則用在多核中。

從 L1 到 L3,三級緩存的大小依次增大,相應的,性能依次降低(當然比內存還是好

得多)。而它們的命中率,衡量的是 CPU 緩存的復用情況,命中率越高,則表示性能越好。

2.5 tcmalloc 替換 ptmalloc

2.5.1 ptmalloc

Ptmalloc 采用主-從分配區(qū)的模式,當一個線程需要分配資源的時候,從鏈表中找到一個沒加鎖的分配區(qū),在進行內存分配。

小內存分配

在 ptmalloc 內部,內存塊采用 chunk 管理,并且將大小相似的 chunk 用鏈表管理,一個鏈表被稱為一個 bin。前 64 個 bin 里,相鄰的 bin 內的 chunk 大小相差 8 字節(jié),稱為 small bin,后面的是 large bin,large bin 里的 chunk 按先大小,再最近使用的順序排列,每次分配都找一個最小的能夠使用的 chunk。

Chunk 的結構如上所示,A 位表示是不是在主分配區(qū),M 表示是不是 mmap 出來的,P 表示上一個內存緊鄰的 chunk 是否在使用,如果沒在使用,則 size of previous

chunk 是上一個 chunk 的大小,否則無意義(而且被用作被分配出去的內存了),正式根據(jù)

P 標記位和 size of previous chunk 在 free 內存塊的時候來進行 chunk 合并的。當然,如果 chunk 空閑,mem 里還記錄了一些指針用于索引臨近大小的 chunk 的,實現(xiàn)原理就不復述了,知道大致作用就行。

在 free 的時候,ptmalloc 會檢查附近的 chunk,并嘗試把連續(xù)空閑的 chunk 合并成一個大的 chunk,放到 unstored bin 里。但是當很小的 chunk 釋放的時候,ptmalloc 會把它并入 fast bin 中。同樣,某些時候,fast bin 里的連續(xù)內存塊會被合并并加入到一個 unsorted bin 里,然后再才進入普通 bin 里。所以 malloc 小內存的時候,是先查找 fast

bin,再查找 unsorted bin,最后查找普通的 bin,如果 unsorted bin 里的 chunk 不合適,則會把它扔到 bin 里。

大內存分配

Ptmalloc 的分配的內存頂部還有一個 top chunk,如果前面的 bin 里的空閑 chunk 都不足以滿足需要,就是嘗試從 top chunk 里分配內存。如果 top chunk 里也不夠,就要從操作系統(tǒng)里拿了。

還有就是特別大的內存,會直接從系統(tǒng) mmap 出來,不受 chunk 管理,這樣的內存在回收的時候也會 munmap 還給操作系統(tǒng)。

簡而言之,就是:

小內存: [獲取分配區(qū)(arena)并加鎖] -》 fast bin -》 unsorted bin -》 small bin -》 large bin

-》 top chunk -》 擴展堆

大內存: 直接 mmap

總結

釋放的時候,幾乎是和分配反過來,再加上可一些 chunk 合并和從一個 bin 轉移到另一個 bin 的操作。并且如果頂部有足夠大的空閑 chunk,則收縮堆頂并還給操作系統(tǒng)。

介于此,對于 ptmalloc 的內存分配使用有幾個注意事項:

1. Ptmalloc 默認后分配內存先釋放,因為內存回收是從 top chunk 開始的。

2. 避免多線程頻繁分配和釋放內存,會造成頻繁加解鎖。

3. 不要分配長生命周期的內存塊,容易造成內碎片,影響內存回收。

2.5.2 Tcmalloc

具體實現(xiàn)原理不加以贅述,可自行百度學習之,總結以下特點。

· Tcmalloc 占用更少的額外空間。例如,分配 N 個 8 字節(jié)對象可能要使用大約 8N * 1.01

字節(jié)的空間。即,多用百分之一的空間。Ptmalloc2 使用最少 8 字節(jié)描述一個 chunk。

· 更快。小對象幾乎無鎖, 》32KB 的對象從 CentralCache 中分配使用自旋鎖。 并且》32KB 對象都是頁面對齊分配,多線程的時候應盡量避免頻繁分配,否則也會造成自旋鎖的競爭和頁面對齊造成的浪費。

2.6 思維導圖

3. 分析工具

從 CPU 的性能指標出發(fā)。當你要查看某個性能指標時,要清楚知道哪些工具可以做到。

4. 思路

性能優(yōu)化并不是沒有副作用的,通常情況下 Linux 系統(tǒng)是不需要特意調整某些指標。往往性能優(yōu)化會帶來整體系統(tǒng)的復雜度的上升,降低了可移植性,也可能在調整某個指標的時候導致其他指標異常。

并不是所有的性能問題都需要去優(yōu)化,需要對瓶頸點進行優(yōu)化。比如當前系統(tǒng)有瓶頸,用戶 CPU 使用率升高了 10%,而系統(tǒng)系統(tǒng) CPU 使用率卻升高了 50%,這個時候就應該首先優(yōu)化系統(tǒng) CPU 使用率。

4.1 應用程序優(yōu)化

從應用程序的角度來說,降低 CPU 使用率最好的方法是,排除所有不必要的工作,只保留最核心的邏輯。比如減少循環(huán)層次、減少遞歸、減少動態(tài)內存分配等等。

常見的幾種應用程序的性能優(yōu)化方法:

· 編譯器優(yōu)化:很多編譯器都會提供優(yōu)化選項,適當開啟它們,在編譯階段你就可以獲得編譯器的幫助,來提升性能。目前設備采用的優(yōu)化選項為 Os,相當于 O2.5

· 算法優(yōu)化:使用異步處理,可以避免程序因為等待某個資源而一直阻塞,從而提升程序的并發(fā)處理能力。

· 多線程代替多進程:線程的上下文切換并不切換進程地址空間,因此可以降低上下文切換的成本。目前設備采用的是多線程模式。

· 使用 buffer:經常訪問的數(shù)據(jù),可以放在內存中緩存起來,這樣在下次用時可以直接從內存中獲取,加快程序的處理速度。

· 小內存使用:小內存的申請,在保證棧空間不溢出的情況下,盡量采用棧上申請,少使用動態(tài)內存申請,提高程序運行效率。

4.2 系統(tǒng)優(yōu)化

從系統(tǒng)的角度來說,優(yōu)化 CPU 的運行,一方面要充分利用 CPU 緩存的本地性,加速緩存訪問;另一方面,就是要控制進程的 CPU 使用情況,減少進程間的相互影響。

常見的方法:

· CPU 綁定:把進程綁定到一個或者多個 CPU 上,可以提高 CPU 緩存的命中率,減少跨 CPU 調度帶來的上下文切換問題。

· 優(yōu)先級調整:使用 nice 調整進程的優(yōu)先級,正值調低優(yōu)先級,負值調高優(yōu)先級。

· 中斷負載均衡:無論是軟中斷還是硬中斷,它們的中斷處理程序都可能消耗大量的 CPU。

配置 smp_affinity,就可以把中斷處理過程自動負載均衡到其他 CPU 上

· 替換 ptmalloc:當前使用的 gblic 庫,其動態(tài)內存管理采

在Linux系統(tǒng)中,由于成本的限制,往往會存在資源上的不足,例如 CPU、內存、網(wǎng)絡、IO 性能。本文,就對 Linux 進程和 CPU 的原理進行分析,總結出 CPU 性能優(yōu)化的方法。

1. 分析手段

在理解平均負載之前,先要理清楚 Linux 下的進程狀態(tài)。

1.1. 進程狀態(tài)

1.1.1. R (TASK_RUNNING),可執(zhí)行狀態(tài)

只有在該狀態(tài)的進程才可能在 CPU 上運行。而同一時刻可能有多個進程處于可執(zhí)行狀態(tài),這些進程的 task_struct 結構(進程控制塊)被放入對應 CPU 的可執(zhí)行隊列中(一個進程最多只能出現(xiàn)在一個 CPU 的可執(zhí)行隊列中)。進程調度器的任務就是從各個 CPU 的可執(zhí)行隊列中分別選擇一個進程在該 CPU 上運行。

很多操作系統(tǒng)教科書將正在 CPU 上執(zhí)行的進程定義為 RUNNING 狀態(tài)、而將可執(zhí)行但是尚未被調度執(zhí)行的進程定義為READY狀態(tài),這兩種狀態(tài)在linux下統(tǒng)一為 TASK_RUNNING 狀態(tài)。

1.1.2. S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態(tài)

處于這個狀態(tài)的進程因為等待某某事件的發(fā)生(比如等待 socket 連接、等待信號量),而被掛起。這些進程的 task_struct 結構被放入對應事件的等待隊列中。當這些事件發(fā)生時

(由外部中斷觸發(fā)、或由其他進程觸發(fā)),對應的等待隊列中的一個或多個進程將被喚醒。通過 ps 命令我們會看到,一般情況下,進程列表中的絕大多數(shù)進程都處于 TASK_INTERRUPTIBLE 狀態(tài)(除非機器的負載很高)。畢竟 CPU 就這么一兩個,進程動輒幾十上百個,如果不是絕大多數(shù)進程都在睡眠,CPU 又怎么響應得過來。

1.1.3. D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)

與 TASK_INTERRUPTIBLE 狀態(tài)類似,進程處于睡眠狀態(tài),但是此刻進程是不可中斷的。

不可中斷,指的并不是 CPU 不響應外部硬件的中斷,而是指進程不響應異步信號。

絕大多數(shù)情況下,進程處在睡眠狀態(tài)時,總是應該能夠響應異步信號的。否則你將驚奇的發(fā)現(xiàn),kill -9 竟然殺不死一個正在睡眠的進程了!于是我們也很好理解,為什么 ps 命令看到的進程幾乎不會出現(xiàn) TASK_UNINTERRUPTIBLE 狀態(tài),而總是 TASK_INTERRUPTIBLE 狀態(tài)。

而 TASK_UNINTERRUPTIBLE 狀態(tài)存在的意義就在于,內核的某些處理流程是不能被打斷的。如果響應異步信號,程序的執(zhí)行流程中就會被插入一段用于處理異步信號的流程(這個插入的流程可能只存在于內核態(tài),也可能延伸到用戶態(tài)),于是原有的流程就被中斷了。

(參見《linux 內核異步中斷淺析》) 在進程對某些硬件進行操作時(比如進程調用 read 系統(tǒng)調用對某個設備文件進行讀操作,而 read 系統(tǒng)調用最終執(zhí)行到對應設備驅動的代碼,并與對應的物理設備進行交互),可能需要使用 TASK_UNINTERRUPTIBLE 狀態(tài)對進程進行保護,以避免進程與設備交互的過程被打斷,造成設備陷入不可控的狀態(tài)。這種情況下的 TASK_UNINTERRUPTIBLE 狀態(tài)總是非常短暫的,通過 ps 命令基本上不可能捕捉到。

1.1.4. T (TASK_STOPPED or TASK_TRACED),暫停狀態(tài)或跟蹤狀態(tài)

向進程發(fā)送一個 SIGSTOP 信號,它就會因響應該信號而進入 TASK_STOPPED 狀態(tài)(除非該進程本身處于 TASK_UNINTERRUPTIBLE 狀態(tài)而不響應信號)。(SIGSTOP 與 SIGKILL 信號一樣,是非常強制的。不允許用戶進程通過 signal 系列的系統(tǒng)調用重新設置對應的信號處理函數(shù)。)

向進程發(fā)送一個 SIGCONT 信號,可以讓其從 TASK_STOPPED 狀態(tài)恢復到 TASK_RUNNING 狀態(tài)。

當進程正在被跟蹤時,它處于 TASK_TRACED 這個特殊的狀態(tài)。“正在被跟蹤”指的是進程暫停下來,等待跟蹤它的進程對它進行操作。比如在 gdb 中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處于 TASK_TRACED 狀態(tài)。而在其他時候,被跟蹤的進程還是處于前面提到的那些狀態(tài)。

對于進程本身來說,TASK_STOPPED 和 TASK_TRACED 狀態(tài)很類似,都是表示進程暫停下來。而 TASK_TRACED 狀態(tài)相當于在 TASK_STOPPED 之上多了一層保護,處于 TASK_TRACED 狀態(tài)的進程不能響應 SIGCONT 信號而被喚醒。只能等到調試進程通過 ptrace 系統(tǒng)調用執(zhí)行 PTRACE_CONT、PTRACE_DETACH 等操作(通過 ptrace 系統(tǒng)調用的參數(shù)指定操作),或調試進程退出,被調試的進程才能恢復 TASK_RUNNING 狀態(tài)。

1.1.5. Z (TASK_DEAD - EXIT_ZOMBIE),退出狀態(tài),進程成為僵尸進程

進程在退出的過程中,處于 TASK_DEAD 狀態(tài)。在這個退出過程中,進程占有的所有資源將被回收,除了 task_struct 結構(以及少數(shù)資源)以外。于是進程就只剩下 task_struct 這么個空殼,故稱為僵尸。之所以保留 task_struct,是因為 task_struct 里面保存了進程的退出碼、以及一些統(tǒng)計信息。而其父進程很可能會關心這些信息。比如在 shell 中,$?變量就保存了最后一個退出的前臺進程的退出碼,而這個退出碼往往被作為 if 語句的判斷條件。

當然,內核也可以將這些信息保存在別的地方,而將 task_struct 結構釋放掉,以節(jié)省一些空間。但是使用 task_struct 結構更為方便,因為在內核中已經建立了從 pid 到 task_struct 查找關系,還有進程間的父子關系。釋放掉 task_struct,則需要建立一些新的數(shù)據(jù)結構,以便讓父進程找到它的子進程的退出信息。

父進程可以通過 wait 系列的系統(tǒng)調用(如 wait4、waitid)來等待某個或某些子進程的退出,并獲取它的退出信息。然后 wait 系列的系統(tǒng)調用會順便將子進程的尸體(task_struct)也釋放掉。

子進程在退出的過程中,內核會給其父進程發(fā)送一個信號,通知父進程來“收尸”。這個信號默認是 SIGCHLD,但是在通過 clone 系統(tǒng)調用創(chuàng)建子進程時,可以設置這個信號。

1.2. 平均負載

單位時間內,系統(tǒng)處于可運行狀態(tài)和不可中斷狀態(tài)的平均進程數(shù),也就是平均活躍進程數(shù),它和 CPU 使用率并沒有直接關系。

既然是平均的活躍進程數(shù),那么最理想的,就是每個cpu 上都剛好運行著一個進程,這樣每個 cpu 都得到了充分利用,比如當平均負載 2時,意味著什么呢?

1、 在只有2 個 CPU的系統(tǒng)上,意味著所有的 CPU都剛好被完全占用

2、 在 4 個CPU的系統(tǒng)上,意味著 CPU 有 50%的空閑

3、 而在只有 1 個CPU 的系統(tǒng)上,則意味著有一半的進程競爭不到 CPU

1.2.1. 平均負載多少合理?

平均負載最理想的情況是等于 CPU 個數(shù)。查看系統(tǒng) CPU 的命令如下:

cat /proc/cpuinfo

Figure 1 四核 CPU 查看平均負載的命令:

給了我們三個不同時間間隔的平均值,給我們提供了分析系統(tǒng)負載趨勢的數(shù)據(jù)來源,讓我們更全面、更立體地理解目前的負載情況。

· 1 分鐘、5 分鐘、15 分鐘 的三個值基本相同,或者相差不大,說明系統(tǒng)負載很平

· 如果1 分鐘的值遠小于15 分鐘 的值,說明系統(tǒng)最近 1 分鐘的負載在減少,而過去

15 分鐘內卻有很大的負載

· 如果1 分鐘 的值遠大于 15 分鐘的值,就說明最近 1 分鐘的負載在增加。一旦 1 分鐘的平均負載接近或超過了 CPU 的個數(shù),就意味著系統(tǒng)正在發(fā)生過載的問題。

uptime 命令在有些嵌入式設備中,會被裁減掉,但是可以通過 proc 文件系統(tǒng)來獲取。命令:

cat /proc/loadavg

很顯然,當前命令展示的平均負載在 CPU 為 4 個時候已經過載

1.2.2. 平均負載與 CPU 使用率

平均負載不僅包括了正在使用 CPU 的進程,還包括了等待 CPU 和等待 I/O 的進程。

CPU 使用率是指單位時間內 CPU 繁忙情況的統(tǒng)計,跟平均負載并不一定完全對應。比如:

· CPU 密集型進程,使用大量 CPU 會導致平均負載升高,此時這兩者是一致的;

· I/O 密集型進程,等待 I/O 也會導致平均負載升高,但 CPU 使用率不一定很高

· 大量等待 CPU 的進程調度也會導致平均負載升高,此時的 CPU 使用率也會比較高。

1.3. CPU 上下文切換

在每個任務運行前, CPU 都需要知道任務從哪里加載、又從哪里開始運行、也就是說,需要系統(tǒng)事先給他設置好 CPU 寄存器和程序計數(shù)器(Program Counter, PC)

· CPU 寄存器:是 CPU 內置的容量小、但速度極快的內存。

· 程序計數(shù)器:是用來存儲 CPU 正在執(zhí)行的指令位置、或者即將執(zhí)行的下一條指令位置。

它們都是 CPU 在運行任何任務前,比如的依賴環(huán)境,因此也被叫做 CPU 上下文。

· 上下文切換:就是先把前一個任務的 CPU 上下文(也就是 CPU 寄存器和程序計數(shù)器)保存起來,然后加載新任務的上下文到這些寄存器和程序計數(shù)器,最后再跳轉到程序計數(shù)器所指的新位置,運行新任務。

· CPU 的上下文切換可以分為進程上下文切換、線程上下文切換以及中斷上下文切換。

1.3.1. 進程上下文切換

Linux 按照特權等級,把進程的運行空間分為內核空間和用戶空間

· 內核空間(Ring 0)具有最高權限,可以直接訪問所有資源。

· 用戶空間(Ring 3)只能訪問受限資源,不能直接訪問內存等硬件設備,必須通過系統(tǒng)調用陷入到內核中,才能訪問這些特權資源。

1.3.2. 進程上下文切換和系統(tǒng)調用的區(qū)別

進程是由內核來管理和調度的,進程的切換只能發(fā)生在內核態(tài)。所以,進程的上下文不僅包括了虛擬內存、棧、全局變量等用戶空間的資源,還包括了內核堆棧、寄存器等內核空間的狀態(tài)。

系統(tǒng)調用過程中,并不涉及到虛擬內存等進程用戶態(tài)的資源,也不會切換進程。

· 進程上下文切換,是指從一個進程切換到另一個進程進行。

· 系統(tǒng)調用過程中一直是同一個進程在運行。

因此,進程的上下文切換比系統(tǒng)調用時多了一步:在保存當前進程的內核狀態(tài)和 CPU 寄存器之前,需要先把該進程的虛擬內存、棧等保存下來;而加載了下一個進程的內核態(tài)后,還需要刷新進程的虛擬內存和用戶棧。

1.3.3. 什么時候會切換進程上文

· 進程執(zhí)行終止,它之前使用的 CPU 會釋放出來,這時再從就緒隊列里,拿一個新的進程過來運行。

· 當某個進程的時間片耗盡了,就會被系統(tǒng)掛起,切換到其他正在等待 CPU 的進程進行

· 進程在系統(tǒng)資源不足(比如內存不足)時,等到資源滿足后才可以運行,這個時候進程也會被掛起,并由系統(tǒng)調度其他進程運行。

· 當進程通過睡眠函數(shù) sleep 這樣的方法將自己主動掛起時,自然也會重新調度。

· 當有優(yōu)先級更高的進程運行時,為了保證高優(yōu)先級進程的運行,當前進程會被掛起,由高優(yōu)先級進程來運行。

· 發(fā)生硬件中斷時,CPU 上的進程會被中斷掛起,轉而執(zhí)行內核中的中斷程序服務。

1.3.4. 線程上下文切換

線程和進程的區(qū)別

· 線程是調度的基本單位,而進程則是資源擁有的基本單位。

· 當進程只有一個線程時,可以認為進程就等于線程。

· 當進程擁有多個線程時,這些線程會共享相同的虛擬內存和全局變量等資源。這些資源在上下文切換時是不需要修改的。

· 線程也有自己的私有數(shù)據(jù),比如棧和寄存器等,這些在上下文切換時也是需要保存的。

線程的上下文切換兩種情況

· 前后兩個線程屬于不同進程。此時,因為資源不共享,所以切換過程就跟進程上下文切換是一樣的。

· 前后兩個線程屬于同一個進程。此時,因為虛擬內存是共享的,所以在切換時,虛擬內存這些資源就保持不動,只需要切換線程的私有數(shù)據(jù)、寄存器等不共享的數(shù)據(jù)。

1.3.5. 中斷上下文切換

中斷處理會打斷進程的正常調度和執(zhí)行。在打斷其他進程時,需要將進程當前的狀態(tài)保存下來,中斷結束后,進程仍然可以從原來的狀態(tài)恢復運行。

進程上下文切換和中斷上下文切換的區(qū)別

· 中斷上下文切換并不涉及到進程的用戶態(tài)。所以,即便中斷過程打斷了一個正處在用戶態(tài)的進程,也不需要保存和恢復這個進程的虛擬內存、全局變量等用戶態(tài)資源。中斷上下文,其實只包括內核態(tài)中斷服務程序執(zhí)行所必須的狀態(tài),包括 CPU 寄存器、內核堆棧、硬件中斷參數(shù)等。

· 對同一個 CPU 來說,中斷處理比進程擁有更高的優(yōu)先級。

進程上下文切換和中斷上文切換的相同之處

· 都需要消耗 CPU,切換次數(shù)過多會耗費大量 CPU,甚至嚴重降低系統(tǒng)的整體性能。

1.3.6. CPU 上下文切換小結

· CPU 上下文切換,是保證 Linux 系統(tǒng)正常工作的核心功能之一,一般情況下不需要我們特別關注。

· 但過多的上下文切換,會把 CPU 時間消耗在寄存器、內核棧以及虛擬內存等數(shù)據(jù)的保存和恢復上,從而縮短進程真正運行的時間,導致系統(tǒng)的整體性能大幅下降

1.3.7. 如何查看系統(tǒng)的上下文切換

常用的系統(tǒng)性能分析工具,主要用來分析系統(tǒng)的內存使用情況,也常用來分析

CPU 上下文切換和中斷次數(shù)。

Figure 2 每隔 2 秒輸出一組數(shù)據(jù)

需要特別關注的四列內容:

· cs (context switch):每秒上下文切換的次數(shù)。

· in (interrupt):每秒中斷的次數(shù)。

· r (Running or Runnable) :就緒隊列的長度,也就是正在運行和等待 CPU 的進程數(shù)。

· b (Blocked):處在不可中斷睡眠狀態(tài)的進程數(shù)。

在嵌入式 Linux 設備中,一般 vmstat 工具是不存在的。所以如果想要 vmstat 工具,可以自己實現(xiàn)代碼,他的原理是獲取/proc/diskstats 和/proc/slabinfo 的信息組合而成。實現(xiàn)代碼見 procps 工具

vmstat 只給出了系統(tǒng)總體的上下文切換情況,并不能查看每個進程的上下文切換情況。

:查看某個進程中線程的上下文切換情況,下圖查看的是 hicore 進程中所有的線程上下文切換情況。

關注兩列內容:

1. 自愿上下文切換:進程無法獲取所需資源,導致的上下文切換。比如, I/O、內存等系統(tǒng)資源不足時。

2. 非自愿上下文切換:進程由于時間片已到等原因,被系統(tǒng)強制調度,進而發(fā)生的上下文切換。比如,大量進程都在爭搶 CPU 時。

1.3.9. Procps 工具

procps 是一組命令行和全屏工具,是由內核動態(tài)生成的一個 “偽” 文件系統(tǒng),可以提供進程表中條目狀態(tài)的信息。該文件系統(tǒng)為內核數(shù)據(jù)結構提供了一個簡易接口,procps 程序通常就集中在這個描述了系統(tǒng)進程運行狀態(tài)的數(shù)據(jù)結構上。

procps 包括以下程序:

· free - 報告系統(tǒng)中可用內存和已用內存的數(shù)量

· kill - 基于 PID,向進程發(fā)送信號

· pgrep - 根據(jù)名稱或其他屬性列出進程

· pkill - 根據(jù)名稱或其他屬性向進程發(fā)送信號

· pmap - 報告進程的內存映射

· ps - 報告進程信息

· pwdx - 報告進程的當前目錄

· skill - pgrep/pkill 的過時版本

· slabtop - 實時顯示內核 slab 緩存信息

· snice - Renice 一個進程

· sysctl -運行時內核參數(shù)的讀或寫

· tload - 系統(tǒng)負載均值的可視化

· top - 正運行進程的實時動態(tài)視圖

· uptime - 顯示系統(tǒng)的已運行時間和負載情況

· vmstat - 報告虛擬內存統(tǒng)計信息

· w - 報告登錄用戶,以及他們正在做什么

· watch - 定期執(zhí)行程序,顯示全屏輸出官網(wǎng)地址:http://procps.sourceforge.net/

1.3.10. sysstat 工具

在嵌入式 Linux 設備中同樣也不存在該工具,busybox 中也沒有相關命令。需要安裝 Linux 性能監(jiān)控工具 sysstat,他是一個工具集,包括 sar、sadf、mpstat、iostat、pidstat 等,這些工具可以監(jiān)控系統(tǒng)性能和使用情況。各工具的作用如下:

1. iostat - 提供 CPU 統(tǒng)計,存儲 I/O 統(tǒng)計(磁盤設備,分區(qū)及網(wǎng)絡文件系統(tǒng))

2. mpstat - 提供單個或組合 CPU 相關統(tǒng)計

3. pidstat - 提供 Linux 進程級別統(tǒng)計:I/O、CPU、內存等

4. sar - 收集、報告、保存系統(tǒng)活動信息:CPU、內存、磁盤、中斷、網(wǎng)絡接口、TTY、內核表等

5. sadc - 系統(tǒng)活動數(shù)據(jù)收集器,作為 sar 后端使用

6. sa1 - 收集系統(tǒng)活動日常數(shù)據(jù),并二進制格式存儲,它作為 sadc 的工具的前端,可以通過 cron 來調用

7. sa2 - 生成系統(tǒng)每日活動報告,同樣可作為 sadc 的工具的前端,可以通過 cron 來調用

8. sadf - 可以以 CSV、XML 格式等顯示 sar 收集的性能數(shù)據(jù),這樣非常方便的將系統(tǒng)數(shù)據(jù)導入到數(shù)據(jù)庫中,或導入到 Excel 中來生成圖表

9. nfsiostat-sysstat: 提供 NFS I/O 統(tǒng)計

10. cifsiostat: 提供 CIFS 統(tǒng)計

sysstat 功能強大,功能也在不斷的增強,每個版本提供了不同的功能,可以到 sysstat 官網(wǎng)了 解 工 具 最 先 發(fā) 展 情 況 和 獲 得 相 應 的 幫 助 手 冊 。 官 網(wǎng) 地 址 :

1.3.11. 中斷

中斷是一種異步的事件處理機制,可以提高系統(tǒng)的并發(fā)處理能力。中斷處理程序會打斷其他進程的運行,為了減少對正常進程運行調度的影響,中斷處理程序就需要盡可能快地運行。

Linux 將中斷處理過程分成了兩個階段,也就是上半部和下半部。

· 上半部用來快速處理中斷,它在中斷禁止模式下運行,主要處理跟硬件緊密相關的或時間敏感的工作。

· 下半部用來延時處理上半部未完成的工作,通常以內核線程的方式運行。

/proc/interrupts:查看硬中斷發(fā)生的類型

硬件中斷發(fā)生頻繁,是件很消耗 CPU 資源的事情,Linux 默認情況下是將所有的硬件中斷都綁定在 CPU0 上,在多核 CPU 條件下如果有辦法把大量硬件中斷分配給不同的

CPU (core) 處理顯然能很好的平衡性能。

1.3.13. 根據(jù)上下文切換的類型做具體分析

· 自愿上下文切換變多,說明進程都在等待資源,有可能發(fā)生 I/O 等其他問題

· 非自愿上下文切換變多,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸

· 中斷次數(shù)變多,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。

1.4. CPU 使用率

/proc/stat,提供的是系統(tǒng)的 CPU 和任務統(tǒng)計信息。這個信息非常的原始

CPU 使用率相關的重要指標

· 第一列:user(us),代表用戶態(tài) CPU 時間。

· 第二列:nice(ni),代表低優(yōu)先級用戶態(tài) CPU 時間,也就是進程的 nice 值被調整為 1-

19 之間時的 CPU 時間。nice 可取值范圍是 -20 到 19, 數(shù)值越大,優(yōu)先級反而越低

· 第三列:system (sys),代表內核態(tài) CPU 時間。

· 第四列:idle(us),代表空閑時間。注意,這里它不包括等待 I/O 的時間(iowait)。

· 第五列:iowait(wa),代表等待 I/O 的 CPU 時間。

· 第六列:irq(hi),代表處理硬中斷的 CPU 時間

· 第七列:softirq(si),代表處理軟中斷的 CPU 時間。

真正查看 CPU 使用率的命令是通過 top 命令

1.5. 軟中斷

提供了軟中斷的運行情況。

· 注意軟中斷的類型,也就是第一列內容。

· 注意同一種軟中斷在不同 CPU 上的分布情況,也就是同一行內容。

· 軟中斷實際上是以內核線程的方式運行的,每個 CPU 都對應一個軟中斷內核線程,這個軟中斷內核線程就叫做 ksoftirqd/CPU 編號

2. 優(yōu)化方法

2.1 CPU 使用率

CPU 使用率描述了非空閑時間占總 CPU 時間的百分比,根據(jù) CPU 上運行任務的不同,又被分為用戶 CPU、系統(tǒng) CPU、等待 I/O CPU、軟中斷和硬中斷等。

· 用戶 CPU 使用率,包括用戶態(tài) CPU 使用率(user) 和低優(yōu)先級用戶態(tài) CPU 使用率 (nice),表示 CPU 在用戶態(tài)運行的時間百分比。用戶 CPU 使用率高,通常說明有應用程序比較繁忙。

· 系統(tǒng) CPU 使用率,表示 CPU 在內核態(tài)運行的時間百分比(不包括中斷)。系統(tǒng) CPU 使用率高,說明內核比較繁忙。

· 等待 I/O 的 CPU 使用率,通常也稱為 iowait,表示等待 I/O 的時間百分比。iowait 高,通常說明系統(tǒng)與硬件設備的 I/O 交互時間比較長。

· 軟中斷和硬中斷的 CPU 使用率,分別表示內核調用軟中斷處理程序、硬中斷處理程序的時間百分比。它們的使用率高,通常說明系統(tǒng)發(fā)生了大量的中斷。

2.2 平均負載(Load Average)

平均負載,也就是系統(tǒng)的平均活躍進程數(shù),它反映了系統(tǒng)的整體負載情況,主要包括三個數(shù)值,分別指過去 1 分鐘、過去 5 分鐘和過去 15 分鐘的平均復制子。

理想情況下,平均負載等于邏輯 CPU 個數(shù),這表示每個 CPU 都恰好被充分利用。如果平均負載大于邏輯 CPU 個數(shù),就表示負載比較重了。

2.3 進程上下文切換

· 無法獲取資源而導致的自愿上下文切換。

· 被系統(tǒng)強制調度導致的非自愿上下文切換。

2.4 CPU 緩存的命中率

由于 CPU 發(fā)展的速度遠快于內存的發(fā)展, CPU 的處理速度就比內存的訪問速度快得多。這樣,CPU 在訪問內存的時候,免不了要等待內存的響應。為了協(xié)調這兩者巨大的性能差距,CPU 緩存(通常是多級緩存)就出現(xiàn)了。

根據(jù)不斷增長的熱點數(shù)據(jù),這些緩存按照大小不同分為 L1、L2、L3 等三級緩存,其中

L1 和 L2 常用在單核中,L3 則用在多核中。

從 L1 到 L3,三級緩存的大小依次增大,相應的,性能依次降低(當然比內存還是好

得多)。而它們的命中率,衡量的是 CPU 緩存的復用情況,命中率越高,則表示性能越好。

2.5 tcmalloc 替換 ptmalloc

2.5.1 ptmalloc

Ptmalloc 采用主-從分配區(qū)的模式,當一個線程需要分配資源的時候,從鏈表中找到一個沒加鎖的分配區(qū),在進行內存分配。

小內存分配

在 ptmalloc 內部,內存塊采用 chunk 管理,并且將大小相似的 chunk 用鏈表管理,一個鏈表被稱為一個 bin。前 64 個 bin 里,相鄰的 bin 內的 chunk 大小相差 8 字節(jié),稱為 small bin,后面的是 large bin,large bin 里的 chunk 按先大小,再最近使用的順序排列,每次分配都找一個最小的能夠使用的 chunk。

Chunk 的結構如上所示,A 位表示是不是在主分配區(qū),M 表示是不是 mmap 出來的,P 表示上一個內存緊鄰的 chunk 是否在使用,如果沒在使用,則 size of previous

chunk 是上一個 chunk 的大小,否則無意義(而且被用作被分配出去的內存了),正式根據(jù)

P 標記位和 size of previous chunk 在 free 內存塊的時候來進行 chunk 合并的。當然,如果 chunk 空閑,mem 里還記錄了一些指針用于索引臨近大小的 chunk 的,實現(xiàn)原理就不復述了,知道大致作用就行。

在 free 的時候,ptmalloc 會檢查附近的 chunk,并嘗試把連續(xù)空閑的 chunk 合并成一個大的 chunk,放到 unstored bin 里。但是當很小的 chunk 釋放的時候,ptmalloc 會把它并入 fast bin 中。同樣,某些時候,fast bin 里的連續(xù)內存塊會被合并并加入到一個 unsorted bin 里,然后再才進入普通 bin 里。所以 malloc 小內存的時候,是先查找 fast

bin,再查找 unsorted bin,最后查找普通的 bin,如果 unsorted bin 里的 chunk 不合適,則會把它扔到 bin 里。

大內存分配

Ptmalloc 的分配的內存頂部還有一個 top chunk,如果前面的 bin 里的空閑 chunk 都不足以滿足需要,就是嘗試從 top chunk 里分配內存。如果 top chunk 里也不夠,就要從操作系統(tǒng)里拿了。

還有就是特別大的內存,會直接從系統(tǒng) mmap 出來,不受 chunk 管理,這樣的內存在回收的時候也會 munmap 還給操作系統(tǒng)。

簡而言之,就是:

小內存: [獲取分配區(qū)(arena)并加鎖] -》 fast bin -》 unsorted bin -》 small bin -》 large bin

-》 top chunk -》 擴展堆

大內存: 直接 mmap

總結

釋放的時候,幾乎是和分配反過來,再加上可一些 chunk 合并和從一個 bin 轉移到另一個 bin 的操作。并且如果頂部有足夠大的空閑 chunk,則收縮堆頂并還給操作系統(tǒng)。

介于此,對于 ptmalloc 的內存分配使用有幾個注意事項:

1. Ptmalloc 默認后分配內存先釋放,因為內存回收是從 top chunk 開始的。

2. 避免多線程頻繁分配和釋放內存,會造成頻繁加解鎖。

3. 不要分配長生命周期的內存塊,容易造成內碎片,影響內存回收。

2.5.2 Tcmalloc

具體實現(xiàn)原理不加以贅述,可自行百度學習之,總結以下特點。

· Tcmalloc 占用更少的額外空間。例如,分配 N 個 8 字節(jié)對象可能要使用大約 8N * 1.01

字節(jié)的空間。即,多用百分之一的空間。Ptmalloc2 使用最少 8 字節(jié)描述一個 chunk。

· 更快。小對象幾乎無鎖, 》32KB 的對象從 CentralCache 中分配使用自旋鎖。 并且》32KB 對象都是頁面對齊分配,多線程的時候應盡量避免頻繁分配,否則也會造成自旋鎖的競爭和頁面對齊造成的浪費。

2.6 思維導圖

3. 分析工具

從 CPU 的性能指標出發(fā)。當你要查看某個性能指標時,要清楚知道哪些工具可以做到。

4. 思路

性能優(yōu)化并不是沒有副作用的,通常情況下 Linux 系統(tǒng)是不需要特意調整某些指標。往往性能優(yōu)化會帶來整體系統(tǒng)的復雜度的上升,降低了可移植性,也可能在調整某個指標的時候導致其他指標異常。

并不是所有的性能問題都需要去優(yōu)化,需要對瓶頸點進行優(yōu)化。比如當前系統(tǒng)有瓶頸,用戶 CPU 使用率升高了 10%,而系統(tǒng)系統(tǒng) CPU 使用率卻升高了 50%,這個時候就應該首先優(yōu)化系統(tǒng) CPU 使用率。

4.1 應用程序優(yōu)化

從應用程序的角度來說,降低 CPU 使用率最好的方法是,排除所有不必要的工作,只保留最核心的邏輯。比如減少循環(huán)層次、減少遞歸、減少動態(tài)內存分配等等。

常見的幾種應用程序的性能優(yōu)化方法:

· 編譯器優(yōu)化:很多編譯器都會提供優(yōu)化選項,適當開啟它們,在編譯階段你就可以獲得編譯器的幫助,來提升性能。目前設備采用的優(yōu)化選項為 Os,相當于 O2.5

· 算法優(yōu)化:使用異步處理,可以避免程序因為等待某個資源而一直阻塞,從而提升程序的并發(fā)處理能力。

· 多線程代替多進程:線程的上下文切換并不切換進程地址空間,因此可以降低上下文切換的成本。目前設備采用的是多線程模式。

· 使用 buffer:經常訪問的數(shù)據(jù),可以放在內存中緩存起來,這樣在下次用時可以直接從內存中獲取,加快程序的處理速度。

· 小內存使用:小內存的申請,在保證棧空間不溢出的情況下,盡量采用棧上申請,少使用動態(tài)內存申請,提高程序運行效率。

4.2 系統(tǒng)優(yōu)化

從系統(tǒng)的角度來說,優(yōu)化 CPU 的運行,一方面要充分利用 CPU 緩存的本地性,加速緩存訪問;另一方面,就是要控制進程的 CPU 使用情況,減少進程間的相互影響。

常見的方法:

· CPU 綁定:把進程綁定到一個或者多個 CPU 上,可以提高 CPU 緩存的命中率,減少跨 CPU 調度帶來的上下文切換問題。

· 優(yōu)先級調整:使用 nice 調整進程的優(yōu)先級,正值調低優(yōu)先級,負值調高優(yōu)先級。

· 中斷負載均衡:無論是軟中斷還是硬中斷,它們的中斷處理程序都可能消耗大量的 CPU。

配置 smp_affinity,就可以把中斷處理過程自動負載均衡到其他 CPU 上

· 替換 ptmalloc:當前使用的 gblic 庫,其動態(tài)內存管理采用就是 ptmalloc。當前應用程序大量使用小尺寸動態(tài)內存,可以采用 tcmalloc,在小內存上更快,幾乎無鎖。

用就是 ptmalloc。當前應用程序大量使用小尺寸動態(tài)內存,可以采用 tcmalloc,在小內存上更快,幾乎無鎖。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10863

    瀏覽量

    211784
  • Linux
    +關注

    關注

    87

    文章

    11304

    瀏覽量

    209524
  • 內存
    +關注

    關注

    8

    文章

    3025

    瀏覽量

    74056
收藏 人收藏

    評論

    相關推薦

    RAID 5 性能優(yōu)化技巧

    RAID 5是一種廣泛使用的磁盤陣列配置,它通過在多個硬盤之間分散數(shù)據(jù)和奇偶校驗信息來提供數(shù)據(jù)冗余和性能提升。然而,RAID 5的性能受到多種因素的影響,包括硬件選擇、配置、操作系統(tǒng)優(yōu)化等。 1.
    的頭像 發(fā)表于 12-27 17:05 ?149次閱讀

    SiFive 推出高性能 Risc-V CPU 開發(fā)板 HiFive Premier P550

    “ ?HiFive Premier P550:世界上性能最高的 RISC-V CPU 開發(fā)板,以 Mini-DTX 外形提供高性能 Linux 開發(fā)平臺,支持下一波 RISC-V 開發(fā)
    的頭像 發(fā)表于 12-16 11:16 ?212次閱讀
    SiFive 推出高<b class='flag-5'>性能</b> Risc-V <b class='flag-5'>CPU</b> 開發(fā)板 HiFive Premier P550

    如何優(yōu)化DCS系統(tǒng)的性能

    優(yōu)化DCS(分布式控制系統(tǒng))系統(tǒng)的性能是確保工業(yè)自動化過程高效、穩(wěn)定運行的關鍵。以下是一些具體的優(yōu)化措施: 一、硬件優(yōu)化 設備選擇與升級 :檢查并確保DCS系統(tǒng)的硬件設備符合規(guī)格要求,
    的頭像 發(fā)表于 11-13 09:19 ?469次閱讀

    如何優(yōu)化SOC芯片性能

    優(yōu)化SOC(System on Chip,系統(tǒng)級芯片)芯片性能是一個復雜而多維的任務,涉及多個方面的優(yōu)化策略。以下是一些關鍵的優(yōu)化措施: 一、架構設計
    的頭像 發(fā)表于 10-31 15:50 ?475次閱讀

    如何優(yōu)化FPGA設計的性能

    優(yōu)化FPGA(現(xiàn)場可編程門陣列)設計的性能是一個復雜而多維的任務,涉及多個方面和步驟。以下是一些關鍵的優(yōu)化策略: 一、明確性能指標 確定需求 :首先,需要明確FPGA設計的
    的頭像 發(fā)表于 10-25 09:23 ?338次閱讀

    linux常用性能優(yōu)化方法

    占用一個本地端口號(與 TCP 協(xié)議端口號不一樣),相當于一個進程,便于與其它進程進行交互。而Linux內核的TCP/IP 協(xié)議實現(xiàn)模塊對本地端口號的范圍進行了限制。當端口號用盡,就會出現(xiàn)這種錯誤了。
    的頭像 發(fā)表于 10-23 13:51 ?150次閱讀

    MySQL性能優(yōu)化淺析及線上案例

    作者:京東健康 孟飛 1、 數(shù)據(jù)庫性能優(yōu)化的意義 業(yè)務發(fā)展初期,數(shù)據(jù)庫中量一般都不高,也不太容易出一些性能問題或者出的問題也不大,但是當數(shù)據(jù)庫的量級達到一定規(guī)模之后,如果缺失有效的預警、監(jiān)控、處理等
    的頭像 發(fā)表于 10-22 15:17 ?693次閱讀
    MySQL<b class='flag-5'>性能</b><b class='flag-5'>優(yōu)化</b>淺析及線上案例

    如何優(yōu)化Linux服務器的性能

    優(yōu)化Linux服務器的性能是一個綜合性的任務,涉及硬件、軟件、配置、監(jiān)控等多個方面。以下是一個詳細的指南,旨在幫助系統(tǒng)管理員和運維人員提升Linux服務器的
    的頭像 發(fā)表于 09-29 16:50 ?312次閱讀

    晶體管對CPU性能的影響

    晶體管作為CPU(中央處理器)的基本構成單元,對CPU性能有著至關重要的影響。
    的頭像 發(fā)表于 09-13 17:22 ?744次閱讀

    CPU單核性能與多核性能的區(qū)別

    CPU的單核性能與多核性能在多個方面存在顯著的差異,這些差異主要體現(xiàn)在處理能力、應用場景、性能瓶頸以及技術發(fā)展等方面。以下是對兩者區(qū)別的詳細探討。
    的頭像 發(fā)表于 09-02 14:42 ?6682次閱讀

    Linux服務器性能查看方法

    Linux服務器性能查看是系統(tǒng)管理員和開發(fā)人員在日常工作中經常需要進行的任務,以確保系統(tǒng)穩(wěn)定運行并優(yōu)化資源使用。以下將詳細介紹多種Linux服務器
    的頭像 發(fā)表于 09-02 11:15 ?1069次閱讀

    Linux服務器CPU飆升的原因

    首先在Linux系統(tǒng)中檢查CPU使用率。可以通過在命令行中輸入top或htop命令來查看當前系統(tǒng)中各個進程的CPU使用率。如果CPU使用率大于80%,則可以考慮進行排查。
    發(fā)表于 02-28 11:00 ?1929次閱讀
    <b class='flag-5'>Linux</b>服務器<b class='flag-5'>CPU</b>飆升的原因

    Linux下常見的十幾款CPU監(jiān)控工具

    今天浩道跟大家分享運維工作中,Linux下常見的十幾款CPU監(jiān)控工具,你可能只會用到其中某些,但是個人覺得作為一個資深運維,你要知道有這些工具可以監(jiān)控CPU
    的頭像 發(fā)表于 01-22 09:19 ?2474次閱讀
    <b class='flag-5'>Linux</b>下常見的十幾款<b class='flag-5'>CPU</b>監(jiān)控工具

    如何使用TCM提高CPU性能

    和 CM7_1)。2。啟用 iCache 時使用 ITCM 會帶來任何 CPU 性能優(yōu)勢嗎?3.如何以最佳方式設計時鐘頻率以優(yōu)化 CPU 性能
    發(fā)表于 01-18 07:01

    如何在Linux系統(tǒng)中檢查CPU使用率

    首先在Linux系統(tǒng)中檢查CPU使用率。可以通過在命令行中輸入top或htop命令來查看當前系統(tǒng)中各個進程的CPU使用率。如果CPU使用率大于80%,則可以考慮進行排查。
    發(fā)表于 01-06 10:42 ?1326次閱讀
    如何在<b class='flag-5'>Linux</b>系統(tǒng)中檢查<b class='flag-5'>CPU</b>使用率
    主站蜘蛛池模板: 又长又大又粗又硬3p免费视| 窝窝午夜看片| 欧美aaaav免费大片| 67xxxxxx日本| 四虎电影院| 福利色播| 网站四虎1515hhcom| 亚洲国产午夜精品理论片的软件| 九九精品在线| aaa视频| 欧美成人性色| 天天操天天干天天| 免费视频黄| 美日毛片| 国产资源网| 一级特黄色毛片免费看| 国产三级网| 亚洲五月六月丁香激情| 四虎影院2022| 亚洲爱v| 免费在线不卡视频| 久久99免费| 1024手机看片国产旧版你懂的| 亚洲欧美日韩色图| www.最色| 亚洲欧洲一区二区三区在线| 日本三级三级三级免费看| 天天看天天摸色天天综合网| 男同小黄文| 国产在线高清精品二区色五郎| 高清影院在线欧美人色| 天天噜天天射| 五月婷婷综合网| 综合色婷婷| 超色视频| 日本在线一区| 国产一级毛片外aaaa| 国产精品欧美激情在线播放| 欧美一卡二三卡四卡不卡| 免费一级在线| 四虎现在的网址入口|