導讀:嵌入式Linux在應用中每每但願系統能在儘可能短的時間內啓動,以提升用戶體驗。並且在有的應用場合,對啓動時間具備嚴格的時間要求,尤爲在工業或者醫療器械應用領域。此時如何加快Linux的啓動,將成爲一個挑戰,對於大多數應用開發人員而言,因爲Linux系統的複雜性,對於如何提升啓動速度,每每無從下手。那麼閱讀完本文,將得到清晰完整的解決思路。linux
1.下降啓動時間的通常思路
git
在準備下降系統的啓動時間時,思路上應創建如下的切入點:github
最快的代碼是未執行的代碼。緩存
引導操做本質上的很大一部分工做其實是將代碼和數據從存儲設備加載到RAM。如所需加載內容越少則意味着加載操做越快。 安全
若是根文件系統越大,則安裝時間可能會越長。微信
所以,即便未執行的代碼也會延長啓動時間。架構
另外在硬件方案設計時儘可能選擇讀寫速度快的存儲介質。例如,從SD卡啓動實際上比從NAND FLASH啓動快。函數
2.啓動時間測量方法工具
要下降系統的啓動時間,則首先須要選擇一個可靠的啓動時間的測量方法:性能
在Linux代碼中加入對某一個GPIO腳的邏輯電平控制,利用示波器測量GPIO狀態。後面將介紹如何在代碼中加入對GPIO的控制。
監控串口控制檯報文以測量時間,可使用grabserial。
參見https://elinux.org/Grabserial
3. 工具鏈優化
3.1 從工具鏈入手
選擇使用合適的工具鏈,應是第一個入手點,由於全部的運行加載固件都是由工具鏈編譯而成。若是還沒有進行其餘優化,則更改工具鏈的好處將更加明顯,而且更容易度量。
您能夠在工具鏈中進行如下更改,這可能會影響啓動時間,性能和大小:
編譯器版本:gcc和binutils的版本,最新版本每每能夠具備更好的優化功能。
C庫:glibc,uClibc,musl。使用uClibc和musl庫編譯的根文件系統更小
指令集變量:ARM或Thumb2,是否支持硬浮點。
可能會影響代碼性能和代碼大小(Thumb2編碼與ARM相同的指令,但以更緊湊的方式,至少會顯着減少大小)。
C庫在建立工具鏈時進行了硬編碼,可供選擇的C庫:
glibc:最標準且功能最全。http://www.gnu.org/software/libc/
uClibc:更小且可配置。已經存在約20年了。http://uclibc-ng.org/
musl:uClibc替代品,雖比較新但很成熟。http://www.musl-libc.org/
能夠對glibc/uclibc-ng /musl進行對比測試:
1.靜態編譯hello.c程序並比較大小
使用gcc 6.3, armel, musl 1.1.16: 7300 字節
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 67204 字節
使用gcc 6.2, armel, glibc: 492792 字節
2. 靜態編譯BusyBox 1.26.2並比較大小
使用gcc 6.3, armel, musl 1.1.16: 183348 字節
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 210620 字節
使用gcc 6.2, armel, glibc: 755088 字節
3.2 指令集選擇
編譯rootfs進行測試對比:
用gcc 7.4編譯,生成ARM代碼:
根文件系統總大小:3.79 MB
用gcc 7.4編譯,生成Thumb2代碼:
根文件系統總大小:3.10 MB(-18%)
性能方面:Thumb2的性能明顯改善(大約少於5%,可是從一次運行到另外一次運行,測量的執行時間略有變化)。
4. 應用軟件優化
4.1 測量strace
strace容許跟蹤應用程序及其子級進行的全部系統調用。對於開發很是有用:
瞭解如何在用戶空間上花費時間
例如,輕鬆查找打開嘗試(open()),文件訪問(read() /write() )和內存分配(mmap2() )。無需訪問源代碼便可完成!
尋找耗時最長的開銷應用
查找在應用程序和腳本中完成的沒必要要的工做。例如:屢次打開同一文件,或嘗試打開不存在的文件。
侷限性:您沒法跟蹤init進程!
關於strace 參見
http://sourceforge.net/projects/strace/:
在全部GNU / Linux系統上可用,能夠由您的交叉編譯工具鏈生成器構建。
更簡單的辦法:直接拷貝一個現成的靜態二進制文件。 參見
https://github.com/bootlin/static-binaries/tree/master/strace
能夠查看進程的操做狀況:
1. 訪問文件,分配內存...
2. 一般足以發現簡單的錯誤。
用法:
1.strace <命令>(開始一個新進程)
2.strace -p <pid>(跟蹤現有進程)strace -c <command>(統計進程的系統開銷時間)
如查看cat操做:
又如統計進程的調用時間:
4.2 Linux上的性能監測工具oprofile
Oprofile是linux上的性能監測工具:
具備兩種工做方式:legacy模式和perf_events模式
legacy模式:
1.精度低,請使用內核驅動程序進行配置
2.使用CONFIG_OPROFILE進行編譯配置
3.用戶空間工具:opcontrol和oprofiled
perf_events模式:
1.使用硬件性能計數器
2.使用CONFIG_PERF_EVENTS和CONFIG_HW_PERF_EVENTS編譯配置
3.用戶空間工具:operf
其使用方法:
legacy 模式:
opcontrol --vmlinux=/path/to/vmlinux # optional step
opcontrol --start
/my/command
opcontrol --stop
perf_events 模式
operf --vmlinux=/path/to/vmlinux /my/command
利用opreport獲取結果
例如:
4.3 perf工具
Perf 是內置於Linux 內核源碼樹中的性能剖析(profiling)工具。它基於事件採樣原理,以性能事件爲基礎,支持針對處理器相關性能指標與操做系統相關性能指標的性能剖析。可用於性能瓶頸的查找與熱點代碼的定位。linux2.6及後續版本都自帶該工具,幾乎可以處理全部與性能相關的事件
使用硬件性能計數器
使用CONFIG_PERF_EVENTS和CONFIG_HW_PERF_EVENTS進行配置
用戶空間工具:性能。它是內核源代碼的一部分,所以始終與您的內核同步。
用法:perf record /my/command
經過如下方式得到結果:perf report
例如:
4.4 鏈接器優化
啓動時使用的應用程序組代碼:
查找啓動期間調用的功能,例如使用
-finstrument-functions gcc選項。
建立一個自定義的連接描述文件,以按調用順序從新排列這些函數。能夠經過將每一個函數放在各自的部分中來實現:
-ffunction-sections gcc選項。
特別對於具備較大MTD讀取塊的閃存存儲特別有用。由於讀取整個讀取塊後,極有可能讀取沒必要要的數據。
詳細信息:http://blogs.linux.ie/caolan/2007/04/24/controlling-symbol-ordering/
經過以下方法,能夠找到有望被優化的地方:
1.啓動一次應用程序並測量其啓動時間。
2.再次啓動應用程序並測量其啓動時間。因爲它的代碼應仍在Linux文件緩存中,故其代碼加載時間將爲零。
從而知道第一次加載應用程序代碼(及其庫)所花費的時間。連接器優化節省的時間應少於此上限。
而後據此能夠決定是否有必要這樣對該應用進行連接優化。因爲連接優化必須修改應用程序的編譯方式,所以此類優化的成本很高。
4.4.1 Prelink 預連接工具
Prelink是Red Hat 開發者 Jakub Jelinek 所設計的工具,正如其名字所示,Prelink利用事先連接代替運行時連接的方法來加速共享庫的加載,它不只能夠加快起動速度,還能夠減小部份內存開銷,是各類Linux架構上用於減小程序加載時間、縮短系統啓動時間和加快應用程序啓動的很受歡迎的一個工具。
預連接減小了啓動可執行文件所需的時間
在Android上普遍使用
必須配置爲知道哪些庫須要進行預連接,並將爲每一個可用符號分配一個固定的地址,從而消除了在啓動可執行文件時從新定位符號的須要。
請注意安全性,由於可執行代碼始終加載在同一地址。
代碼以及文檔參見
http://people.redhat.com/jakub/prelink/
支持ARM,但自2013年以來未發佈。Buildroot也不支持。可是,x86比較容易實現。
後續會發布:
優化嵌入式Linux的啓動時間之init腳本啓動優化
優化嵌入式Linux的啓動時間之文件系統優化
優化嵌入式Linux的啓動時間以內核優化
優化嵌入式Linux的啓動時間之bootloader優化
優化嵌入式Linux的啓動時間之硬件初始化優化
敬請關注!
本文分享自微信公衆號 - 嵌入式客棧(embInn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。