01
工具鏈/應(yīng)用程序優(yōu)化
導(dǎo)讀:嵌入式Linux在應(yīng)用中往往希望系統(tǒng)能在盡量短的時間內(nèi)啟動,以提高用戶體驗(yàn)。而且在有的應(yīng)用場合,對啟動時間具有嚴(yán)格的時間要求,尤其在工業(yè)或者醫(yī)療器械應(yīng)用領(lǐng)域。此時如何加快Linux的啟動,將成為一個挑戰(zhàn),對于大多數(shù)應(yīng)用開發(fā)人員而言,由于Linux系統(tǒng)的復(fù)雜性,對于如何提高啟動速度,往往無從下手。那么閱讀完本文,將獲得清晰完整的解決思路。
1.降低啟動時間的一般思路
在準(zhǔn)備降低系統(tǒng)的啟動時間時,思路上應(yīng)建立以下的切入點(diǎn):
最快的代碼是未執(zhí)行的代碼。
引導(dǎo)操作本質(zhì)上的很大一部分工作實(shí)際上是將代碼和數(shù)據(jù)從存儲設(shè)備加載到RAM。如所需加載內(nèi)容越少則意味著加載操作越快。
如果根文件系統(tǒng)越大,則安裝時間可能會越長。
因此,即使未執(zhí)行的代碼也會延長啟動時間。
另外在硬件方案設(shè)計時盡量選擇讀寫速度快的存儲介質(zhì)。例如,從SD卡啟動實(shí)際上比從NAND FLASH啟動快。
2.啟動時間測量方法
要降低系統(tǒng)的啟動時間,則首先需要選擇一個可靠的啟動時間的測量方法:
在Linux代碼中加入對某一個GPIO腳的邏輯電平控制,利用示波器測量GPIO狀態(tài)。后面將介紹如何在代碼中加入對GPIO的控制。
監(jiān)控串口控制臺報文以測量時間,可以使用grabserial。
參見https://elinux.org/Grabserial
3. 工具鏈優(yōu)化
3.1 從工具鏈入手
選擇使用合適的工具鏈,應(yīng)是第一個入手點(diǎn),因?yàn)樗械倪\(yùn)行加載固件都是由工具鏈編譯而成。如果尚未進(jìn)行其他優(yōu)化,則更改工具鏈的好處將更加明顯,并且更容易度量。
您可以在工具鏈中進(jìn)行以下更改,這可能會影響啟動時間,性能和大?。?/p>
編譯器版本:gcc和binutils的版本,最新版本往往可以具有更好的優(yōu)化功能。
C庫:glibc,uClibc,musl。使用uClibc和musl庫編譯的根文件系統(tǒng)更小
指令集變量:ARM或Thumb2,是否支持硬浮點(diǎn)。
可能會影響代碼性能和代碼大?。═humb2編碼與ARM相同的指令,但以更緊湊的方式,至少會顯著減小大?。?/p>
C庫在創(chuàng)建工具鏈時進(jìn)行了硬編碼,可供選擇的C庫:
glibc:最標(biāo)準(zhǔn)且功能最全。http://www.gnu.org/software/libc/
uClibc:更小且可配置。已經(jīng)存在約20年了。http://uclibc-ng.org/
musl:uClibc替代品,雖比較新但很成熟。http://www.musl-libc.org/
可以對glibc/uclibc-ng /musl進(jìn)行對比測試:
1.靜態(tài)編譯hello.c程序并比較大小
使用gcc 6.3, armel, musl 1.1.16: 7300 字節(jié)
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 67204 字節(jié)
使用gcc 6.2, armel, glibc: 492792 字節(jié)
2. 靜態(tài)編譯BusyBox 1.26.2并比較大小
使用gcc 6.3, armel, musl 1.1.16: 183348 字節(jié)
使用gcc 6.3, armel, uclibc-ng 1.0.22 : 210620 字節(jié)
使用gcc 6.2, armel, glibc: 755088 字節(jié)
3.2 指令集選擇
編譯rootfs進(jìn)行測試對比:
用gcc 7.4編譯,生成ARM代碼:
根文件系統(tǒng)總大?。?.79 MB
用gcc 7.4編譯,生成Thumb2代碼:
根文件系統(tǒng)總大小:3.10 MB(-18%)
性能方面:Thumb2的性能明顯改善(大約少于5%,但是從一次運(yùn)行到另一次運(yùn)行,測量的執(zhí)行時間略有變化)。
4. 應(yīng)用軟件優(yōu)化
4.1 測量strace
strace允許跟蹤應(yīng)用程序及其子級進(jìn)行的所有系統(tǒng)調(diào)用。對于開發(fā)非常有用:
了解如何在用戶空間上花費(fèi)時間
例如,輕松查找打開嘗試(open()),文件訪問(read() /write() )和內(nèi)存分配(mmap2() )。無需訪問源代碼即可完成!
尋找耗時最長的開銷應(yīng)用
查找在應(yīng)用程序和腳本中完成的不必要的工作。例如:多次打開同一文件,或嘗試打開不存在的文件。
局限性:您無法跟蹤init進(jìn)程!
關(guān)于strace 參見
http://sourceforge.net/projects/strace/:
在所有GNU / Linux系統(tǒng)上可用,可以由您的交叉編譯工具鏈生成器構(gòu)建。
更簡單的辦法:直接拷貝一個現(xiàn)成的靜態(tài)二進(jìn)制文件。 參見
https://github.com/bootlin/static-binaries/tree/master/strace
可以查看進(jìn)程的操作情況:
1. 訪問文件,分配內(nèi)存。。.
2. 通常足以發(fā)現(xiàn)簡單的錯誤。
用法:
1.strace 《命令》(開始一個新進(jìn)程)
2.strace -p 《pid》(跟蹤現(xiàn)有進(jìn)程)strace -c 《command》(統(tǒng)計進(jìn)程的系統(tǒng)開銷時間)
如查看cat操作:
?
4.2 Linux上的性能監(jiān)測工具oprofile
Oprofile是linux上的性能監(jiān)測工具:
具有兩種工作方式:legacy模式和perf_events模式
legacy模式:
1.精度低,請使用內(nèi)核驅(qū)動程序進(jìn)行配置
2.使用CONFIG_OPROFILE進(jìn)行編譯配置
3.用戶空間工具:opcontrol和oprofiled
perf_events模式:
1.使用硬件性能計數(shù)器
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獲取結(jié)果
?
4.3 perf工具
Perf 是內(nèi)置于Linux 內(nèi)核源碼樹中的性能剖析(profiling)工具。它基于事件采樣原理,以性能事件為基礎(chǔ),支持針對處理器相關(guān)性能指標(biāo)與操作系統(tǒng)相關(guān)性能指標(biāo)的性能剖析??捎糜谛阅芷款i的查找與熱點(diǎn)代碼的定位。linux2.6及后續(xù)版本都自帶該工具,幾乎能夠處理所有與性能相關(guān)的事件
使用硬件性能計數(shù)器
使用CONFIG_PERF_EVENTS和CONFIG_HW_PERF_EVENTS進(jìn)行配置
用戶空間工具:性能。它是內(nèi)核源代碼的一部分,因此始終與您的內(nèi)核同步。
用法:perf record /my/command
通過以下方式獲得結(jié)果:perf report
?
4.4 連接器優(yōu)化
啟動時使用的應(yīng)用程序組代碼:
查找啟動期間調(diào)用的功能,例如使用
-finstrument-functions gcc選項(xiàng)。
創(chuàng)建一個自定義的鏈接描述文件,以按調(diào)用順序重新排列這些函數(shù)。可以通過將每個函數(shù)放在各自的部分中來實(shí)現(xiàn):
-ffunction-sections gcc選項(xiàng)。
特別對于具有較大MTD讀取塊的閃存存儲特別有用。因?yàn)樽x取整個讀取塊后,極有可能讀取不必要的數(shù)據(jù)。
詳細(xì)信息:http://blogs.linux.ie/caolan/2007/04/24/controlling-symbol-ordering/
通過如下方法,可以找到有望被優(yōu)化的地方:
1.啟動一次應(yīng)用程序并測量其啟動時間。
2.再次啟動應(yīng)用程序并測量其啟動時間。由于它的代碼應(yīng)仍在Linux文件緩存中,故其代碼加載時間將為零。
從而知道第一次加載應(yīng)用程序代碼(及其庫)所花費(fèi)的時間。鏈接器優(yōu)化節(jié)省的時間應(yīng)少于此上限。
然后據(jù)此可以決定是否有必要這樣對該應(yīng)用進(jìn)行鏈接優(yōu)化。由于鏈接優(yōu)化必須修改應(yīng)用程序的編譯方式,因此此類優(yōu)化的成本很高。
4.4.1 Prelink 預(yù)鏈接工具
Prelink是Red Hat 開發(fā)者 Jakub Jelinek 所設(shè)計的工具,正如其名字所示,Prelink利用事先鏈接代替運(yùn)行時鏈接的方法來加速共享庫的加載,它不僅可以加快起動速度,還可以減少部分內(nèi)存開銷,是各種Linux架構(gòu)上用于減少程序加載時間、縮短系統(tǒng)啟動時間和加快應(yīng)用程序啟動的很受歡迎的一個工具。
預(yù)鏈接減少了啟動可執(zhí)行文件所需的時間
在Android上廣泛使用
必須配置為知道哪些庫需要進(jìn)行預(yù)鏈接,并將為每個可用符號分配一個固定的地址,從而消除了在啟動可執(zhí)行文件時重新定位符號的需要。
請注意安全性,因?yàn)榭蓤?zhí)行代碼始終加載在同一地址。
代碼以及文檔參見
http://people.redhat.com/jakub/prelink/
支持ARM,但自2013年以來未發(fā)布。Buildroot也不支持。但是,x86比較容易實(shí)現(xiàn)。
工具鏈/應(yīng)用程序優(yōu)化的部分就在此結(jié)束了,下篇我們將繼續(xù)講嵌入式Linux啟動時間優(yōu)化的方法之文件系統(tǒng),請大家繼續(xù)關(guān)注我們電子發(fā)燒友網(wǎng)和嵌入式客棧。
編輯連載推薦:嵌入式Linux啟動時間優(yōu)化的秘密之二文件系統(tǒng)
評論
查看更多