一、前言
前面講了關(guān)于 內(nèi)存 方面的優(yōu)化,那么接下來的文章我們主要聚焦于 性能 的優(yōu)化,那么主要體現(xiàn)在優(yōu)化程序 速度 上。程序的 速度 很大程度上會影響用戶體驗或者程序的實際效用,所以優(yōu)化 性能速度 也是程序員需要關(guān)注的一個方面,從本文起接下來的幾篇文章將講述如何對 程序性能 進行優(yōu)化。
二、優(yōu)化思想
在講解優(yōu)化之前,我們先看一下 優(yōu)化的思想,它可以保證我們在學習或者優(yōu)化的過程中保持對問題的關(guān)注,讓我們知道是在學習什么跟如何優(yōu)化。
2.1 性能分析瓶頸分類
說到優(yōu)化,一個程序運行慢可能是有多種原因構(gòu)成的,那么前輩們就將這多種原因歸結(jié)為以下 3類:
- 程序的運算量很大,導致 CPU 過于繁忙。稱為 CPU 瓶頸。
- 程序需要做大量的 I/O,讀寫文件、內(nèi)存操作等等,CPU 更多的是處于等待。稱為 I/O 瓶頸。
- 程序之間相互等待,結(jié)果 CPU 利用率很低,但運行速度依然很慢,事務(wù)間的共享與死鎖制約了程序的性能
2.2 優(yōu)化基本原則
- 等效原則:優(yōu)化前后程序?qū)崿F(xiàn)的功能一致。
- 有效原則:優(yōu)化后要比優(yōu)化前運行速度快或占用存儲空間小,或二者兼有。
- 經(jīng)濟原則:優(yōu)化程序要付出較小的代價,取得較好的結(jié)果。
另外一般有 5 個基本綱領(lǐng)為我們提供優(yōu)化思路:
- Do it faster: 程序除了 實現(xiàn)功能 之外,還需要 提高其運行速度。
- Do it in parallel:能夠 并行執(zhí)行程序 的話,我們就可以 充分利用CPU資源,從而加速程序運行速度。
- Do it later:對于時間緊迫的功能,有些不必要的功能,可以考慮延后執(zhí)行,使程序的任務(wù)減輕,從 而騰出資源,來做重要的事。
- Don't do it at all:設(shè)計程序時,不要加入多余無用的代碼 來實現(xiàn) *模塊化或者提高可讀性。
- Do it before:程序有可能并不需要一直工作,我們可以把一些工作在 系統(tǒng)空閑 時完成,這樣可以減輕繁忙時程序的負擔。
2.3 優(yōu)化思路
在程序優(yōu)化上,往往 20%的代碼 占用了 80%的運行時間,所以我們需要找出這 20% 的代碼。所以 如何找出需要優(yōu)化的代碼 是一個我們需要關(guān)注的問題,而這個問題我們可以有一些工具來解決,在下面的章節(jié)會提到。
第一步:找出 性能瓶頸的代碼,在筆者看來,分析程序問題,找出性能瓶頸是重中之重。
第二步:進行 代碼優(yōu)化
2.4 優(yōu)化經(jīng)驗總結(jié):
下面是書中提到的一些 優(yōu)化經(jīng)驗,在了解這些經(jīng)驗之前,我們需要了解幾個概念:
- 提高程序的效率:程序的 時間效率是指運行速度
- 空間效率:是指程序 占用內(nèi)存或者外存的狀況
- 全局效率 是指站在 整個系統(tǒng)的角度上考慮的效率
- 局部效率 是指站在 模塊或函數(shù)角度上考慮 的效率
書中經(jīng)驗總結(jié)如下:
- 不要一味地追求程序的效率,應(yīng)當在滿足 正確性、可靠性、健壯性、可讀性 等質(zhì)量因素的前提下,設(shè)法提高程序的效率。
- 以提高程序的 全局效率為主,提高 局部效率為輔。
- 在優(yōu)化程序的效率時,應(yīng)當先找出限制效率的 瓶頸,不要在無關(guān)緊要之處優(yōu)化。
- 先優(yōu)化 數(shù)據(jù)結(jié)構(gòu)和算法,再優(yōu)化 執(zhí)行代碼。
- 有時候 時間效率 和 空間效率 可能對立,此時應(yīng)當分析那個更重要,作出適當?shù)恼壑浴?strong>例如多花費一些內(nèi)存來提高性能。
- 不要追求 緊湊的代碼,因為 緊湊的代碼 并不能產(chǎn)生 高效的機器碼。
- 當心那些視覺上不易分辨的操作符發(fā)生 書寫錯誤。 比如會把 == 誤寫成 =,像 ||、&&、<=、>= 這些符號也很容易發(fā)生 丟1失誤。然而 編譯器卻不一定能自動指出這類錯誤。
- 變量(指針、數(shù)組) 被創(chuàng)建之后 應(yīng)當及時把它們初始化,以 防止把未被初始化的變量當成右值使用。
- 當心變量的 初值、缺省值錯誤,或者精度不夠。
- 當心 數(shù)據(jù)類型轉(zhuǎn)換發(fā)生錯誤。盡量使用 顯式 的數(shù)據(jù)類型轉(zhuǎn)換,避免讓 編譯器輕悄悄地進行隱式的數(shù)據(jù)類型轉(zhuǎn)換。
- 當心變量發(fā)生 上溢或下溢,數(shù)組的 下標越界。
- 當心忘記編寫 錯誤處理程序,且要注意防止 錯誤處理程序本身有誤。
- 當心 文件 I/O 有錯誤。
- 避免 編寫技巧性很高代碼。
- 不要設(shè)計 面面俱到、非常靈活的數(shù)據(jù)結(jié)構(gòu)。
- 如果原有的代碼質(zhì)量比較好,盡量復用它。但是 不要修補很差勁的代碼, 應(yīng)當重新編寫。
- 盡量使用 標準庫函數(shù),不要 發(fā)明已經(jīng)存在的庫函數(shù)。
- 盡量不要 使用與具體硬件或軟件環(huán)境關(guān)系密切的變量。
- 把編譯器的選擇項設(shè)置為 嚴格狀態(tài)。
- 如果可能的話,使用 PC-Lint、LogiScope 等工具進行代碼審查。
2.5 優(yōu)化的層次
在我們了解到了 程序瓶頸 之后,接下來我們就要考慮對代碼進行優(yōu)化:
程序的優(yōu)化,主要包括四個層次:
- 算法和數(shù)據(jù)結(jié)構(gòu)的優(yōu)化
- 編譯器優(yōu)化
- 代碼優(yōu)化
- 硬加速
優(yōu)化新手容易犯的錯誤就是:找到 程序熱點 時,過于興奮,急匆匆的就開始 局部代碼 的優(yōu)化。但我們需要在 更大的范圍內(nèi)分析,是什么導致這個 程序瓶頸 的存在,有時可能根本就不需要改動你的程序。
三、性能評估
一般情況下,我們可以把 性能優(yōu)化 分為 2 個部分
- 性能評估:一般而言,程序都有 二八法則。20%的代碼影響80%的速度。我們需要找出這20% 的代碼進行優(yōu)化,對其進行 瓶頸分析,找出影響速度的原因。
- 性能優(yōu)化:找出原因和需要優(yōu)化的代碼后,利用 編譯、硬件 及 算法和數(shù)據(jù)結(jié)構(gòu) 等對其進行優(yōu)化。
3.1 系統(tǒng)及進程性能評估
據(jù)上面所講,性能評測 是至關(guān)重要的一個環(huán)節(jié),如果不知道哪里出了問題,那么優(yōu)化就無從下手。程序性能的問題是有很多原因的,我們先看看一般的問題分析:
- /proc目錄下系統(tǒng)相關(guān)的文件
- /proc目錄下進程相關(guān)的文件
3.1.1 proc系統(tǒng)相關(guān)
系統(tǒng)相關(guān)屬性 我們可以通過下面 2 個文件來了解。
3.1.1.1. /proc/stat
我們使用 cat /proc/stat 來獲取 系統(tǒng)相關(guān) 的信息,這樣可以知道我們 系統(tǒng)效率 的具體細節(jié)

下面 按行 說明各行數(shù)據(jù)的意義:
-
cpuN:其數(shù)值分別代表著 CPU 在 不同狀態(tài) 下所用的時間,其單位為 jiffies(0.01s)。
- user:從 系統(tǒng)啟動 開始累計到 當前時刻,用戶態(tài)的 CPU時間,不包含 nice值為負 的進程。 在圖中的值為 19。
- nice:從 系統(tǒng)啟動 開始累計到 當前時刻,nice值為負 的進程所占用的 CPU時間。 在圖中的值為 0。
- system:從 系統(tǒng)啟動開始累計到 當前時刻,內(nèi)核 所占用的 CPU時間。 在圖中的值為 166。
- idle:從 系統(tǒng)啟動 開始累計到 當前時刻,除 硬盤IO等待時間 的以外其它等待時間。 在圖中的值為 218632。
- iowait:從 系統(tǒng)啟動 開始累計到 當前時刻,硬盤IO 等待時間。 在圖中的值為 73。
- irq:從 系統(tǒng)啟動 開始累計到 當前時刻,硬中斷時間。在圖中的值為 0。
- softirq:從 系統(tǒng)啟動 開始累計到 當前時刻,軟中斷時間。在圖中的值為 0。
- stealstolen:在 虛擬化環(huán)境中 運行時在 其他操作系統(tǒng) 上花費的時間
- guest:Linux內(nèi)核 控制下為 虛擬操作系統(tǒng) 運行 虛擬CPU 所花費的時間
- intr:從 系統(tǒng)啟動 開始累計到 當前時刻,發(fā)生的 所有中斷的次數(shù)。每個數(shù) 對應(yīng)一個特定的 中斷。
- ctxt:從 系統(tǒng)啟動 開始累計到 當前時刻,CPU 發(fā)生的 上下文交換 的次數(shù)。
- btime:從 系統(tǒng)啟動 開始累計到 當前時刻 的 時間,單位為秒。
- processes:從 系統(tǒng)啟動 開始累計到 當前時刻 ,系統(tǒng)所創(chuàng)建的 任務(wù)數(shù)目。
- procs_running:當前 運行隊列 的任務(wù)數(shù)目。
- procs_blocked:當前 被阻塞 的任務(wù)數(shù)目。
3.1.1.2. CPU利用率
CPU利用率是指CPU工作時間占總時間的比重, 簡單地理解為 單位時間內(nèi) CPU處于忙狀態(tài)的時間占比。
摘抄附錄《CPU利用率與Load Average的區(qū)別?》中的說法:
CPU利用率 可以看出在某一個時間段內(nèi)CPU被占用的情況,如果CPU被占用時間很高,那么就需要考慮CPU是否已經(jīng)處于超負荷運作,長期超負荷運作對于機器本身來說是一種損害,因此必須將CPU的利用率控制在一定的比例下,以保證機器的正常運作。
有一種情況需要注意的是:使用 自旋鎖 等 忙等處理的鎖會導致 CPU利用率的上升,此時 CPU利用率 并不能很好的反映 CPU的使用情況。
- CPU時間 = user + system + nice + idle + iowait + irq + softirq
- CPU利用率 = 1 - (idle) / CPU時間。用于測量當前系統(tǒng)的 CPU負載情況。
- CPU用戶態(tài)利用率 = (user+nice) / CPU時間。用于測量 用戶程序 對 CPU的占用率。
- CPU內(nèi)核態(tài)利用率 = (system) / CPU時間。如果程序有大量的 系統(tǒng)調(diào)用,導致 Linux內(nèi)核 占用了大量的 CPU,可以使用該數(shù)值來測量。
- IO利用率 = iowait / CPU時間,測量 FLASH、內(nèi)存 等存儲介質(zhì)的 交互和等待時間。
3.1.1.3. /proc/loadavg

loadavg 主要檢查當前系統(tǒng)的 負載情況:下面 按從左到右 逐個說明:
- 1分鐘 的平均負載
- 5分鐘 的平均負載
- 15分鐘 的平均負載
- 在采樣時刻,運行隊列的任務(wù)的數(shù)目,與 /proc/stat 的 procs_running 表示相同意思
- 在采樣時刻,系統(tǒng)中 活躍的任務(wù)個數(shù)(不包括運行已經(jīng)結(jié)束的任務(wù))
- 最大的 pid值,包括 輕量級進程(即線程)。
更多關(guān)于 CPU負載 的講述可以參考 3.2.1.2小節(jié)。
3.1.2 proc進程相關(guān)
3.1.2.1 proc進程相關(guān)屬性
要查看 進程狀態(tài) ,先需要進入 進程 在 proc目錄 下的文件夾,然后使用 cat stat 查看其狀態(tài),
如圖:

下面按順序逐個介紹各個數(shù)據(jù)的意義:
- pid:進程號(包括線程) ,在圖中值為 89。
- comm:應(yīng)用程序 的名字,在圖中值為 sshd。
-
task_state:任務(wù)的狀態(tài),,在圖中值為 S。其各個狀態(tài)如下:
- R:runnign,即 運行態(tài)
- S:sleeping(TASK_INTERRUPTIBLE),即 睡眠態(tài)(可被打斷)
- D:deep sleep(TASK_UNINTERRUPTIBLE),即 睡眠態(tài)(不可被打斷)
- T:stopped,即 停止態(tài)
- t:tracing stop,即 暫停態(tài)(可被繼續(xù))
- Z:zombie,即僵尸態(tài)
- X:dead,即死亡態(tài)
- ppid:父進程ID,在圖中值為 1。
- pgid:線程組號,在圖中值為 89。
- sid:該任務(wù)所在的 會話組ID,在圖中值為 89。
- tty_nr:該任務(wù)的 tty終端設(shè)備號,在圖中值為 0。
- tpgid:終端的 進程組號,即當前運行在該任務(wù)所在終端的前臺任務(wù) (包括shell及應(yīng)用程序) 的 PID,在圖中值為 -1。
- task_flags:進程標志位,查看該任務(wù)的特性,在圖中值為 4194624。
- min_flt:該任務(wù)不需要從硬盤拷數(shù)據(jù)而發(fā)生的 次缺頁次數(shù),在圖中值為 107。
- cmin_flt:該任務(wù)的累計所有的 waited-for進程 曾經(jīng)發(fā)生的 次缺頁次數(shù),在圖中值為 364。
- maj_flt:該任務(wù)需要從硬盤拷數(shù)據(jù)而發(fā)生的 主缺頁次數(shù) ,在圖中值為 0。
- cmaj_flt:該任務(wù)累計的所有的 waited-for進程 曾經(jīng)發(fā)生的 主缺頁次數(shù),在圖中值為 0。
- utime:該任務(wù)在 用戶態(tài) 運行的時間(單位為jiffies),在圖中值為 0。
- stime:該任務(wù)在 核心態(tài) 運行的時間(單位為jiffies),在圖中值為 0。
- cutime:該任務(wù)累計所有的 waited-for進程 曾經(jīng)在 用戶態(tài) 運行的時間(單位為jiffies),在圖中值為 12。
- cstime:該任務(wù)累計所有的 waited-for進程 曾經(jīng)在 核心態(tài) 運行時間(單位為jiffies),在圖中值為 7。
- priority:任務(wù)的 動態(tài)優(yōu)先級,在圖中值為 20。
- nice:任務(wù)的 靜態(tài)優(yōu)先級,在圖中值為 0。
- num_threads:該任務(wù)所在的 線程組里的 線程個數(shù),在圖中值為 1。
- it_real_value:由于 計時間隔 導致的下一個 SIGALRM 發(fā)送進程的時延(單位為jiffies), 在圖中值為 0。
- start_time:在系統(tǒng)啟動后,到與該任務(wù)啟動時的間隔(單位為jiffies), 在圖中值為 247。
- vsize:該任務(wù)的 虛擬地址空間大小,在圖中值為 4268032。
- rss:該任務(wù)當前 駐留物理地址空間的大小,這些頁可能用于 代碼、數(shù)據(jù)和棧 。在圖中值為 416。
- rlim:該任務(wù)能駐留物理地址空間的 最大值 (單位為byte),在圖中值為 4294967295。
- start_code:該任務(wù)在虛擬地址空間的 代碼段 的起始地址,在圖中值為 4648960。
- end_code:該任務(wù)在虛擬地址空間的 代碼段的結(jié)束地址,在圖中值為 5267368。
- start_stack:該任務(wù)在虛擬地址空間的 棧的結(jié)束地址,在圖中值為 3198615200。
- kstkesp:sp指針(堆棧指針) 的當前值, 與在進程的內(nèi)核堆棧頁得到的一致,在圖中值為 0。
- kstkeip:ip指針(指令指針)的當前值,指向?qū)⒁獔?zhí)行的 指令指針,在圖中值為 0。
- pendingsig:待處理信號 的位圖,記錄發(fā)送給進程的普通信號,在圖中值為 0。
- blocksig:阻塞信號 的位圖 ,在圖中值為 0。
- sigignore:忽略信號 的位圖,在圖中值為 4096。
- sigcatch:被俘獲信號 的位圖 ,在圖中值為 81925。
- wchan:如果該進程是 睡眠狀態(tài),該值給出 調(diào)度的調(diào)用點 ,在圖中值為 1。
- nswap:被 swapped 的頁數(shù) (當前沒用) ,在圖中值為 0。
- cnswap:所有子進程被 swapped 的頁數(shù)的 和 (當前沒用),在圖中值為 0。
- exit_signal:該進程結(jié)束時,向父進程所發(fā)送的信號,在圖中值為 17。
- processor:運行的 CPU編號 ,在圖中值為 0。
- rt_priority:實時進程 的 相對優(yōu)先級別,在圖中值為 0。
-
task_policy:進程的調(diào)度策略,其各個值如下,在圖中值為 0:
- 0:非實時進程
- 1:FIFO實時進程
- 2:RR實時進程
- delayacct_blkio_ticks:累計的 塊I/O延遲,以 clock tick 為單位。在圖中值為 0:
- guest_time:為虛擬操作系統(tǒng)運行虛擬CPU所花費的時間,以 clock tick 為單位。在圖中值為 0。
- cguest_time:進程的 子進程 用于用戶操作系統(tǒng)的時間,以 clock tick 為單位。在圖中值為0。
- start_data:進程的 數(shù)據(jù)段 和 BSS段 的 起始地址。在圖中值為 5335032。
- end_data:進程的 數(shù)據(jù)段 和 BSS段 的 結(jié)束地址。在圖中值為 5342208。
- start_brk:進程的 堆 的 起始地址。在圖中值為 5365760。
- arg_start:進程存放 命令行參數(shù) 的 起始地址。在圖中值為 3198615427。
- arg_end:進程存放 命令行參數(shù) 的 結(jié)束地址。在圖中值為 3198615442。
- env_start:進程存放 環(huán)境變量 的 起始地址。在圖中值為 3198615442。
- env_end:進程存放 環(huán)境變量 的 結(jié)束地址。在圖中值為 3198615533。
- exit_code:進程的 退出碼。在圖中值為 0。
3.1.2.2 使用proc進程相關(guān)屬性計算CPU占有率
先看看下面的公式:
- 進程CPU占用率 = 進程占用CPU時間 / 系統(tǒng)總的時間。
- 進程占用 CPU 時間:可以從 進程的stat文件 獲得,包括 utime、stime、cutime、cstime。
- 系統(tǒng)總的時間:可以通過 /proc/stat 或者 gettime函數(shù) 獲得。
想要計算 CPU占有率 還對 進程的運行采樣,一般需要 2個采樣點:
-
采樣點1:
- 系統(tǒng)時間記為 sys1
- 進程時間分別記為:utime1、stime1、cutime1、cstime1
-
采樣點2:
- 系統(tǒng)時間記為 sys2
- 進程時間分別記為:utime2、stime2、cutime2、cstime2
經(jīng)過計算和采樣后可以按照下面的公式來計算:
- 進程CPU占用率 = ((utime2+stime2-cutime2-cstime2)-(utime1+stime1-cutime1-cstime1)) / (sys2-sys1)
- 進程用戶態(tài)占用率 = ((utime2-cutime2)-(utime1-cutime1)) / (sys2-sys1)
- 進程內(nèi)核態(tài)占用率 = ((stime2-cstime2)-(stime1-cstime1)) / (sys2-sys1)
3.2 系統(tǒng)性能評估工具
3.2.1 top
top 是一個常用的 性能分析 軟件,運行結(jié)果如下圖所示:

下面將 top 分 2 點來講述:
- 內(nèi)存分析
- CPU及負載分析
3.2.1.1 內(nèi)存分析
運行結(jié)果如下圖所示:

可以看到它統(tǒng)計的內(nèi)存有:used、free、shrd、buff、cached。
各個內(nèi)存的含義在前面的 內(nèi)存分析 文章中已經(jīng)說過,這里不再贅述
3.2.1.2 CPU及負載分析
1. CPU負載
Load Average 即 CPU負載 ,該數(shù)據(jù)是 每隔5秒鐘 檢查一次活躍的進程數(shù),然后按特定算法計算出的數(shù)值。
Load Average 可以理解為 CPU 的帶載情況,即有多少進程需要 CPU 來處理。它并不是描述 CPU的使用情況,其本質(zhì)應(yīng)該是 在單位時間內(nèi),CPU正在處理的進程數(shù)以及等待CPU處理的進程數(shù)之間的和,也就是CPU進程隊列的統(tǒng)計信息。
Load Average 越高說明越多的進程在搶占CPU,因而會導致 CPU資源的競爭越來越激烈,對于CPU資源的申請和維護的成本也會加大
理想情況下是一個CPU帶一個進程,這樣就不會發(fā)生CPU資源搶占。所以在一般情況下,如果這個數(shù)除以邏輯CPU的數(shù)量,結(jié)果高于5的時候就表明系統(tǒng)在超負荷運轉(zhuǎn)了。
CPU利用率和CPU負載的區(qū)別:
- CPU利用率指的是 程序在運行期間實時占用的CPU百分比
- CPU負載指的是 一段時間內(nèi)正在使用和等待使用CPU的平均任務(wù)數(shù)。
兩者之間并沒有太大的關(guān)聯(lián)。比如一個進程一直在使用CPU進行運算,那么此時CPU利用率會達到100%,但平均負載則趨近于 1。反過來說,當CPU的工作負載越大,代表CPU必須要在不同的工作之間進行頻繁的工作切換。
按照筆者的理解:
- CPU密集型進程容易讓CPU利用率升高
- I/O 密集型進程容易導致平均負載升高
- 頻繁調(diào)度進程容易讓平均負載和CPU利用率升高
2. CPU利用率及負載

- usr:用戶空間 占用CPU的百分比。
- sy:內(nèi)核空間 占用CPU的百分比。
- nic:改變過優(yōu)先級的進程占用CPU的百分比
- id:空閑 CPU百分比
- io: IO等待 占用CPU的百分比
- irq:硬中斷 占用CPU的百分比
- sirq:軟中斷 占用CPU的百分比
- Load average:指 CPU的 負載均衡,后面的三個數(shù)分別是 1分鐘、5分鐘、15分鐘的負載情況。
2.2.1.3 進程分析

- PID:進程ID
- PPID:父進程ID
- USER:進程所有者
- STAT:當前進程的狀態(tài),其值可以參考 進程stat 的 task_state
- VSZ:進程的 虛擬大小
- %CPU:上次更新到現(xiàn)在的CPU時間占用百分比
- COMMAND:運行的 命令行
3.2.2 vmstat
在嵌入式設(shè)備上,busybox 是不帶有該工具,而該工具的源碼也不是獨立的,而是在 procps 這個中聚集中。關(guān)于 procps 的交叉編譯請參考附錄中的:
- json-c 交叉編譯(undefined reference to rpl_malloc )
- 交叉編譯Procps-ng-3.3.11
編譯完成后將相應(yīng)的文件拷貝到設(shè)備端上就可以使用 vmstat 工具了,運行結(jié)果如下:

該命令的意思是:每隔1秒運行1次vmstat,一共運行5次。
數(shù)據(jù)含義如下:
-
procs:系統(tǒng)中的進程狀態(tài)
- r(running):運行隊列中的進程數(shù)量。
- b(block): 在阻塞等待IO的進程數(shù)量。
-
memory:系統(tǒng)的內(nèi)存使用情況
- swpd:使用的虛擬內(nèi)存 大小。如果 swpd 的值不為0且 SI,SO的值長期為0,這種情況不會影響系統(tǒng)性能。
- free:空閑物理內(nèi)存 大小。
- buff:用作 文件緩沖 的內(nèi)存大小。
- cache:用作 緩存 的內(nèi)存大小,如果cache值大,說明緩存的文件數(shù)多,如果頻繁訪問到的文件都能被cache中,那么磁盤的 讀IO(bi) 會非常小。
-
swap:內(nèi)存交換情況
- si:每秒從交換區(qū)寫到內(nèi)存的大小,由磁盤調(diào)入內(nèi)存。
- so:每秒寫入交換區(qū)的內(nèi)存大小,由內(nèi)存調(diào)入磁盤。
注意: 內(nèi)存夠用的時候,這2個值都是 0。如果這2個值長期大于0時,系統(tǒng)性能會受到影響,磁盤IO 和 CPU資源 都會被消耗。不能因為觀察到 空閑內(nèi)存(free) 很少或接近于0時,就認為內(nèi)存不夠用了。還需要結(jié)合 si 和 so。如果 閑內(nèi)存(free)很少,同時si 和 so 也很少(大多時候是0),那么此時說明內(nèi)存剛好夠用,系統(tǒng)性能暫時不會受到影響的。
-
IO:系統(tǒng)IO的使用情況,如果值越大
- bi:每秒讀取 的塊數(shù)
- bo:每秒寫入 的塊數(shù)
注意:隨機磁盤讀寫的時候,bi** 和 bo 值越大,能看到 CPU 的 IO等待(wa) 也會越大。**
-
system:系統(tǒng)情況
- in:每秒中斷數(shù),包括時鐘中斷。
- cs:每秒上下文切換數(shù)。
注意: 隨機磁盤讀寫的時候,in 和 cs 值越大,能看到 CPU 的 內(nèi)核消耗的CPU時間(sy) 也會越大。
CPU:CPU 的使用情況,以 百分比表示
- us:用戶進程執(zhí)行時間百分比(us) 的值比較高時,說明 用戶進程消耗的CPU時間多。如果該值長期超 50%,那么我們就該考慮對程序進行優(yōu)化。
- sy: 內(nèi)核系統(tǒng)進程執(zhí)行時間百分比(sy) 的值高時,說明 系統(tǒng)內(nèi)核消耗的CPU資源多。此時系統(tǒng)的情況比較糟糕,我們需要排查原因并優(yōu)化
- wa:IO等待時間百分比(wa) 的值高時,說明 IO等待 比較嚴重。這可能由于 磁盤大量作隨機訪問造成,也有可能 磁盤出現(xiàn)瓶頸(塊操作)。
- id:空閑時間百分比
四、查找性能瓶頸
在分析程序的時候,往往需要找個程序的 性能瓶頸。從而對 性能瓶頸 進行優(yōu)化,這樣可以取得比較大的收益。我們一般都使用功能來查找 性能瓶頸,一般有 gprof、OProfile 或者 perf 等。本文著重說明一下 perf 的使用方法,及如何將 perf 獲取到的數(shù)據(jù)轉(zhuǎn)換為 火焰圖 來分析程序性能。
4.1 perf
4.1.1 perf編譯
perf 依賴于幾種庫,分別如下:
- zlib
- elfutils
-
binutils
其中 binutils 就是我們常用的 readelf、ar 等編譯器工具,一般情況下我們的 交叉編譯鏈 都有自帶,所以我們需要自行編譯 zlib 和 elfutils
1. zlib交叉編譯
- 點擊 zlib下載地址 下載 zlib 源碼。
- 解壓并進入 zlib的目錄
- 使用命令導出 交叉編譯工具,命令舉例如下:
export CC=arm-linux-gnueabihf-gcc
- 使用命令進行配置,該命令會直接將編譯出來的庫自動加入到我們的 庫路徑,我們就不再需要去指定 庫路徑 了。如下:
./configure --host=arm-linux-gnueabihf --prefix=/your_compiler_path/arm-linux-gnueabihf/libc/usr
附錄
- 編譯安裝
make -j12 && make install
2. elfutils交叉編譯
我們編譯 elfutils 是需要其里面的庫 libelf。編譯過程依賴 2 個工具 m4 和 bison。在編譯前請檢查編譯機是否有安裝該工具。編譯步驟如下:
- 點擊 elfutils下載地址 下載 elfutils 源碼。
- 解壓并進入目錄
- 使用命令進行配置:
./configure --host=arm-linux-gnueabihf --prefix=/your_compiler_path/arm-linux-gnueabihf/libc/usr/ --disable-debuginfod
- 編譯安裝
make -j12 && make install
3. perf交叉編譯
perf源碼 在我們開發(fā)板上 linux 的源碼中,其路徑一般是 /your_linux_path/tool/perf。
編譯步驟如下:
- 進入 perf 源碼目錄
- 使用命令進行編譯
make LDFLAGS=-static ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- DEBUG=1 HAVE_CPLUS_DEMANGLE=1
- 編譯完成后在 perf目錄下 有個叫 perf 的執(zhí)行文件。將 perf、libz 和 libelf 拷貝到開發(fā)板上對應(yīng)的位置,就是 庫路徑和執(zhí)行文件路徑
4.1.2 perf概念
perf 的原理是通過對 系統(tǒng)事件 進行 統(tǒng)計采樣 得到 統(tǒng)計數(shù)據(jù),再通過分析 統(tǒng)計數(shù)據(jù) 得出性能瓶頸的結(jié)果。
perf 中能采樣 系統(tǒng)事件 分為以下 3 類:
- Hardware Event:由 PMU部件或芯片硬件如cache等 產(chǎn)生,在特定的條件下探測 硬件系統(tǒng)事件是否發(fā)生以及發(fā)生的次數(shù)。
- Software Event:是內(nèi)核產(chǎn)生的事件,分布在各個功能模塊中,統(tǒng)計和操作系統(tǒng)相關(guān)性能事件。比如進程切換,clock_tick數(shù)等。
- Tracepoint Event:tracepoints 是散落在內(nèi)核源碼中的一些 hook函數(shù),它們可以在特定的代碼被執(zhí)行到時觸發(fā),比如 slab分配器的分配次數(shù)。根據(jù)一特性,perf 將 tracepoints 產(chǎn)生的時間記錄下來,生成報告,通過分析這些報告對性能做出準確的判斷。
4.1.2 perf使用方法
perf 是一個工具集,一共包含 20多種 工具,下面看看常用的 5種工具。
1. perf list
perf 的運行原理就是對 系統(tǒng)事件 進行采樣,從而得到相關(guān)數(shù)據(jù)來分析。我們可以使用perf list 來查看編譯出來的 perf 支持哪些 系統(tǒng)事件。每個 linux版本 的 perf 可能有所不同。筆者的運行結(jié)果如下:

可以看到一共有 10種軟件事件 和 3種硬件事件。筆者編譯出來的 peff 比較簡陋,所以本文主要講述 軟件事件 相關(guān)的分析。
2. perf stat
perf stat 可以統(tǒng)計 程序 的 整體情況,它能夠顯示出 程序 的 系統(tǒng)事件 統(tǒng)計數(shù)據(jù)。一般用于 分析程序的整體性能
常用選項如下 :
- -a(--all-cpus):顯示 所有CPU上的統(tǒng)計信息。
- -C(--cpu <cpu>):顯示 指定CPU的統(tǒng)計信息。
- -D(--delay <n>):指定 命令的延遲統(tǒng)計時間,單位為 毫秒。
- -d(--detailed):顯示更多細節(jié)信息。
- -e(--event <event>):統(tǒng)計 指定事件 的數(shù)據(jù)。
- -o(--output <file>):輸出統(tǒng)計信息到文件。
- -p(--pid <pid>):對指定 pid的進程 進行統(tǒng)計。
- -t(--tid <tid>):對指定 tid的線程 進行統(tǒng)計。
- -r(--repeat <n>):重復命令 n次 并顯示 平均結(jié)果
- -S(--sync):在開始執(zhí)行前使用 sync函數(shù)。
運行結(jié)果如下:

perf stat 顯示的默認 統(tǒng)計信息如下:
- task-clock-msecs:指 CPU利用率。該值越高,說明程序花費越多的時間在 CPU計算 上而不 文件IO。
- context-switches:指 進程切換次數(shù),記錄了程序運行過程中發(fā)生 進程切換 的次數(shù)。應(yīng)當盡量避免頻繁的進程切換。
- cache-misses:指 **程序運行過程中的 cache非命中次數(shù)。如果該值越高,說明程序的 cache命中率越低。
- cache-references:指 **程序運行過程中的 cache命中次數(shù)。如果該值越高,說明程序的 cache命中率越高。
- CPU-migrations:表示 進程 在運行過程中發(fā)生的 CPU遷移次數(shù)。
- cycles:處理器時鐘周期,一條機器指令可能需要多個 cycles。
- instructions:指 程序的機器指令數(shù)目。
- IPC:指 instructions/cycles 。該值越大,說明 程序越充分利用了處理器
3. perf top
perf top 與 top 不同的是。top 常用于分析系統(tǒng)的整體性能。而 perf top 可以精確到系統(tǒng)或程序中 函數(shù)級的運行情況
常用選項如下 :
- -e <event>:指明要分析的性能事件。
- -p <pid>:僅分析 pid目標進程及其創(chuàng)建的線程。
- -k <path>:帶符號表的內(nèi)核映像所在的路徑,用于注釋函數(shù)。
- -K:不顯示屬于內(nèi)核或模塊的符號。
- -U:不顯示屬于用戶態(tài)程序的符號。
- -d <n>:界面的 刷新周期,默認為 2s。因為 perf top 默認 每2s 從 mmap 的內(nèi)存區(qū)域讀取一次性能數(shù)據(jù)。
- --call-graph fractal:路徑上的調(diào)用率為 相對值,加起來為100%。調(diào)用順序為 從下往上。
- perf top --call-graph graph:路徑調(diào)用率為 絕對值,加起來為該函數(shù)的 熱度。
運行結(jié)果如下:

- 第一列:符號引發(fā)的 性能事件的比例,默認指 占用的cpu周期比例。
- 第二列:符號所在的 DSO(Dynamic Shared Object),可以是 應(yīng)用程序、內(nèi)核、動態(tài)鏈接庫、模塊。
-
第三列:DSO的類型。
[.]:表示此符號屬于 用戶態(tài)的ELF文件,包括 8可執(zhí)行文件與動態(tài)鏈接庫*。
[k]:表述此符號屬于內(nèi)核或模塊。 - 第四列:符號名。如果有些符號 不能解析為函數(shù)名,只能用 地址 表示。
4. perf record
perf record 可以 用于記錄perf統(tǒng)計的數(shù)據(jù) 并輸出到 文件perf.data,并使用相關(guān)工具生成 可視化 圖像來分析程序。配合 perf report 可以精確的分析程序
常用選項:
- -e:指定記錄的 系統(tǒng)事件
- -a:指定記錄 所有CPU的事件
- -p:記錄指定 pid進程的事件
- -o:指定 保存數(shù)據(jù)的文件名
- -g:指定 生成函數(shù)調(diào)用圖
- -C:記錄 指定CPU的事件
- -F:設(shè)置統(tǒng)計頻率
這里不展開說 perf report,我們使用另一個強有力的工具 火焰圖FlameGraph,可以在 github 上找到火焰圖的項目,點擊下載火焰圖生成軟件
下面我們通過一個例程來說明:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
void* func_test1(void* arg)
{
int j = 0;
for(int i = 0; i < 90000000; i++)
j=i;
return NULL;
}
void* func_test2(void* arg)
{
int j = 0;
for(int i = 0; i < 120000000; i++)
j=i;
return NULL;
}
int main()
{
pthread_t test1 = 0;
pthread_t test2 = 0;
pthread_create(&test1, NULL, func_test1, NULL);
pthread_create(&test2, NULL, func_test2, NULL);
pthread_join(test1,NULL);
pthread_join(test2,NULL);
return 0;
}
注意,在使用時需要注意要加參數(shù) -g。
步驟如下:
- 在設(shè)備上運行 perf record -a -g your_program
- 使用命令 perf script -i perf.data > perf.unfold 將生成的 perf.data 轉(zhuǎn)換為 perf.unfold
- 將生成的 perf.unfold 拷貝到宿主機上
- 使用 FlameGraph 中的工具執(zhí)行命令 ./stackcollapse-perf.pl perf.unfold > perf.fold
- 使用命令 ./flamegraph.pl perf.fold > perf.svg 生成 svg文件
- 使用 瀏覽器 打開 svg文件 (筆者使用的是chrom)
結(jié)果如下:

可以看到 func_test1 和 func_test2 占據(jù)了 執(zhí)行時間 的大頭,在旁邊還有 2個 函數(shù)在執(zhí)行。
點擊 左側(cè)紅框 查看如下:

從結(jié)果中可以看到是 perf 自身的調(diào)用情況。
再點擊 右側(cè)紅框 查看如下:

可以看到是一個名為 swapper 的函數(shù)在執(zhí)行,而這個函數(shù)是干什么用的呢?
其實在 CPU 執(zhí)行程序時,空閑的時候就會調(diào)用 swapper 函數(shù),此時 CPU 處于 idle狀態(tài)。
五、程序優(yōu)化
前面我們講了 程序優(yōu)化 的幾個層次,分別是:
- 算法和數(shù)據(jù)結(jié)構(gòu)的優(yōu)化
- 編譯器優(yōu)化
- 代碼優(yōu)化
- 硬加速
其中 算法和數(shù)據(jù)結(jié)構(gòu)的優(yōu)化 不在本文內(nèi)容計劃之內(nèi)。使用 SIMD指令硬加速 已經(jīng)在筆者的其他博客 neon指令 系列一將說到。 下面主要簡單地講述一下 編譯器優(yōu)化 和 代碼優(yōu)化。
5.1 編譯器優(yōu)化
編譯器按照 arm-linux-gcc 系列來說明。下面將按書中所寫,列舉出 gcc 的相關(guān)編譯優(yōu)化選項。如果你想 關(guān)掉 某一個優(yōu)化選項, 你可以在 -f 和 優(yōu)化選項 之間增加 no。
在編譯時,我們一般回加入 -O1、-O2和-O3 等選項,其實它們的作用就是讓編譯器進行不同程度的優(yōu)化,那么每種優(yōu)化打開的編譯選項都不同,下面看看每種優(yōu)化都打開了哪些選項。
5.1.1 -O1優(yōu)化
-
-fcprop-registers:
即 復寫傳播,一般情況下該選項會與 常量折疊 一起出現(xiàn)。因為在函數(shù)中把寄存器分配給變量,所以編譯器執(zhí)行二次檢查以便 減少調(diào)度依賴性 并且 刪除不必要的寄存器復制操作。以下面的代碼作說明。
const int i = 2*2;
編譯器確實將 2*2 算成 4 了,以后碰到 i 就用 4 替換,這個計算 2*2 的過程據(jù)說叫 常量折疊(const folding),而用 4 替換 i 的過程叫做 復寫傳播(copy propagation)。
-fdefer-pop:
該優(yōu)化選項與 函數(shù)返回 有關(guān)。 一般情況下,函數(shù)返回,輸入?yún)?shù)被立即彈出堆棧后。但該優(yōu)化選項會 推遲彈出函數(shù)調(diào)用的輸入?yún)?shù),等必要時與幾個函數(shù)調(diào)用參數(shù)一起彈出。這樣可以 節(jié)省處理時間,但也 會使堆棧中的內(nèi)容有些雜亂。-fdelayed-branch:
該選項會讓編譯器 試圖根據(jù)指令周期時間重新安排指令, 把盡可能多的指令 移動到條件分支前,以便充分的利用處理器的 緩存。-fguess-branch-probability:
該選項直譯為 猜測分支可能性,該選項試圖讓編譯器 確定條件分支可能的結(jié)果,并且移動相應(yīng)的指令。這有可能導致不同的編譯器會編譯出迥然不同的目標代碼。-fif-conversion:
if-then 語句應(yīng)該是程序中僅次于循環(huán)的最消耗時間的語句。簡單的if-then語句可能在最終的 匯編代碼 中產(chǎn)生 較多條件分支。 通過 減少或者刪除條件分支 ,以及使用 條件傳送、設(shè)置標志 和 運算技巧 來替換 if-then語句。由此編譯器可以減少 if-then語句 花費的時間量。-fif-conversion2:
相比于 -fif-conversion , -fif-conversion2 加入更高級的 數(shù)學特性, 減少實現(xiàn) if-then語句 所需的 條件分支 。-floop-optimize:
優(yōu)化循環(huán) 通??梢院艽蟪潭鹊?提高程序性能。一般情況下,程序會存在 大型且復雜的循環(huán)。通過刪除在循環(huán)內(nèi)沒有改變值的變量賦值操作,可以 減少循環(huán)內(nèi)執(zhí)行指令的數(shù)量,在很大程度上提高性能。 同時也優(yōu)化那些確定何時離開循環(huán)的條件分支, 以便減少分支的影響。-fmerge-constants:
嘗試(string constants and floating point constants)
該選項會讓編譯器試圖 橫跨編譯單元合并同樣的常量。這一特性有時候會導致 很長的編譯時間。
5.1.2 -O2優(yōu)化
-falign-functions:
這個選項用于使 函數(shù)對準內(nèi)存中特定邊界的開始位置。大多數(shù)處理器按照頁面讀取內(nèi)存,并且確保全部函數(shù)代碼位于單一內(nèi)存頁面內(nèi)。這樣 同一函數(shù)就不需要讀取到多個內(nèi)存頁中。-fcaller-saves:
該選項可以讓編譯器對 函數(shù)調(diào)用 只進行一次 寄存器的保存和恢復操作,而不是在每個函數(shù)調(diào)用中都進行。 如果調(diào)用多個函數(shù), 這樣能夠節(jié)省時間。-fcrossjumping:
該選項讓編譯器 跨越跳轉(zhuǎn)的轉(zhuǎn)換代碼進行處理, 以便組合分散在程序各處的相同代碼。 這樣可以 減少代碼的長度, 但是有可能不會對程序性能產(chǎn)生直接影響。-fcse-follow-jumps:
CES即通用子表達式消除技術(shù)(common subexpression elimination)。在程序中,有時候會有一些 無法到達的代碼,該選項讓編譯器查找程序中的此類代碼,然后跳過該代碼的 跳轉(zhuǎn)指令。最常見的就是 if-else 的 else部分-fdelete-null-pointer-checks:
該選項讓編譯器掃描 匯編語言代碼,檢查可能存在 空指針的代碼。 編譯器假設(shè)間接引用空指針將 停止程序。-fexpensive-optimizations:
該選項讓編譯器執(zhí)行 代價高昂的各種優(yōu)化技術(shù)(編譯時的角度)。但是不一定保證運行時性能能提升,有可能對運行時的性能產(chǎn)生負面影響。-fforce-mem:
該選項讓編譯器在做算術(shù)操作前,強制將內(nèi)存數(shù)據(jù)copy到寄存器 中以后再執(zhí)行。對于只涉及 單一指令的變量來說,這樣也許不會有很大的優(yōu)化效果。但是對于 很多指令中都涉及到的變量(比如數(shù)學操作) 來說,這時有顯著的優(yōu)化。因為和訪問內(nèi)存中的值相比,處理器訪問寄存器中的值要快的多。
該選項有可能導致 內(nèi)存與寄存器之間的數(shù)據(jù)不一致。對于某些依賴 內(nèi)存操作順序而進行的邏輯,需要做 嚴格的處理 后才能進行優(yōu)化。例如采用 volatile關(guān)鍵字限制變量的操作方式或者 利用barrier迫使cpu嚴格按照指令序執(zhí)行。-fgcse:
該選項讓編譯器 所有匯編代碼執(zhí)行全局通用表達式消除。該操作 試圖分析匯編代碼并且結(jié)合通用片段,消除冗余的代碼段。如果代碼使用 計算性的goto,推薦 使用-fno-gcse選項關(guān)閉該優(yōu)化選項。-foptimize-sibling-calls:
該選項可以優(yōu)化 尾遞歸的調(diào)用。一般情況下 遞歸的函數(shù) 可以被 展開為一系列一般的指令, 而不是使用分支。 這樣處理器的指令緩存能夠加載展開的指令并且處理他們。和 需要分支操作的函數(shù)相比這樣更快。-fregmove:
該選項讓編譯器試圖 重新分配 mov 指令中使用的寄存器,并且將其作為 其他指令的操作數(shù),以便 最大化捆綁的寄存器的數(shù)量。說實在的,筆者目前也不清楚書中所講關(guān)于該選項的內(nèi)容,有知道的讀者還請不吝賜教-freorder-functions:
該選項讓編譯器重新安排指令塊以便改進 分支操作 和 代碼局部性。-frerun-cse-after-loop:
該選項讓編譯器在對 任何循環(huán) 已經(jīng)進行過優(yōu)化之后執(zhí)行 運行通用子表達式消除。這樣確保在展開循環(huán)代碼之后更進一步地優(yōu)化代碼-fsched-interblock:
該選項讓編譯器能夠 跨越指令塊調(diào)度指令。 這可以非常靈活地 移動指令以便等待期間完成的工作最大化。-fschedule-insns:
該選項讓編譯器將 重新安排指令,以讓等待數(shù)據(jù)的處理器可以執(zhí)行其他操作。 比如對于在進行浮點運算時有延遲的處理器來說, 這使處理器在等待浮點結(jié)果時可以加載其他指令-fstrength-reduce:
該選項讓編譯器對循環(huán)執(zhí)行優(yōu)化并且 刪除迭代變量。迭代變量 是 捆綁到循環(huán)計數(shù)器的變量,類似于for循環(huán)中常用的 i,j。-fstrict-aliasing:
該選項讓編譯器強制實行高級語言的嚴格變量規(guī)則,確保不在數(shù)據(jù)類型之間共享變量。比如 int 和 float 不使用相同的內(nèi)存區(qū)域。-fthread-jumps:
在某些情況下, 一條跳轉(zhuǎn)指令可能轉(zhuǎn)移到另一條分支語句。 通過一連串跳轉(zhuǎn),編譯器確定多個跳轉(zhuǎn)之間的終目 標并且把第一個跳轉(zhuǎn)重新定向到終目標。 也就是直接優(yōu)化從第一個跳轉(zhuǎn)到最后一個目標代碼-funit-at-a-time:
該選項讓編譯器在優(yōu)化程序之前讀取 整個匯編代碼。 這使編譯器可以 重新安排不消耗大量時間的代碼以便優(yōu)化指令緩存。 缺點是編譯時 花費相當多的內(nèi)存,對于 小型計算機可能是一個問題
5.1.3 -O3優(yōu)化
-fgcse-after-reload:
完全重新加載生成的且優(yōu)化后的匯編語言代碼之后執(zhí)行第二次gcse優(yōu)化,幫助消除不同優(yōu)化代碼方式創(chuàng)建的任何冗余段.-finline-functions:
該選項讓編譯器 不為函數(shù)創(chuàng)建單獨的匯編語言代碼, 而是把函數(shù)代碼包含在調(diào)度程序的代碼中。按照筆者理解將多個函數(shù)集成到一個函數(shù)中。該優(yōu)化選項可用充分的利用指令緩存,而不是在每次函數(shù)調(diào)用時進行分支操作,由此提高性能。
5.2 代碼優(yōu)化
按照筆者理解,代碼優(yōu)化 更加考驗一個人的經(jīng)驗積累。本節(jié)不會詳細介紹書中每種 代碼優(yōu)化技巧 的原理,主要是總結(jié) 代碼優(yōu)化技巧 的 結(jié)論??梢钥焖賾?yīng)用于 開發(fā) 中。
數(shù)據(jù)類型:針對 8位和16位,ARM 是在將數(shù)據(jù)加載到寄存器中,完成 符號位擴展。數(shù)據(jù)加載指令 ldr、ldrsb、ldrb、 lsdh、lsdsh、ldr等,它們的 指令周期是一樣的。所以 char、short、int 其效率是相同的。
if與switch:如果 case值 變化不大(太大的話,會導致跳轉(zhuǎn)表過大,造成內(nèi)存的浪費),有足夠的分支(大 于 4 個分支),switch 會帶來性能極大的提升。
-
循環(huán):
- 展開循環(huán)分支,降低循環(huán)的次數(shù),減少 分支語句 對循環(huán)的影響。
- 合并循環(huán),既可以 提高程序性能并減少代碼尺寸,同時不影響功能。
- 流水線級數(shù)越高,對分支操作越加敏感。在程序正常運行期間處理當前代碼時,預(yù)取模塊 會 讀取并解碼 下一部分指令而 不使存儲總線閑置下來。如果遇到 分支語句,則會 清除流水線而立刻使預(yù)先進行的讀取和解碼工作無效。流水線 級數(shù)越多 ,系統(tǒng)就花費越多的時間 來填充流水線。在這期間 CPU會閑置下來。因此,分支語句越少,性能越高。
數(shù)組:盡量使用數(shù)組的大小是 4或8 的倍數(shù),用此倍數(shù)展開循環(huán)體 一維數(shù)組和多維數(shù)組 。
-
函數(shù):
- 函數(shù)的參數(shù)最好 不多于 4 個。
- 盡量限制函數(shù)內(nèi)部循環(huán)所用局部變量的數(shù)目,最好 不超過12個,以便編譯器能把 變量分配到寄存器。
- 如果不需要 返回值,則盡量定義為 void,這樣可以 節(jié)省 一個 寄存器R0。 如果需要返回值,則最好 限定在4個字節(jié),使用一個 寄存器R0 即可。
六、參考鏈接
/proc/stat 詳解
Linux top命令詳解
Linux CPU性能優(yōu)化方法
json-c 交叉編譯(undefined reference to rpl_malloc )
交叉編譯Procps-ng-3.3.11【轉(zhuǎn)】
CPU 利用率背后的真相,你知道嗎?
CPU利用率與Load Average的區(qū)別?
死鎖一定會造成cpu使用率飆升嗎?
深入理解perf報告中的swapper進程
系統(tǒng)級性能分析工具perf的介紹與使用
perf工具+ 火焰圖分析性能
perf 工具原理與使用
GNU下優(yōu)化代碼
gcc -o 優(yōu)化選項