摘 ?要: EDKII作為當(dāng)前最流行的UEFI開源實(shí)現(xiàn),其編譯工具性能的提升是非常關(guān)鍵也是值得研究的,同時編譯過程的快慢也是衡量這一框架的重要指標(biāo)。通過使用cProfile對EDKII Build工具編譯時間進(jìn)行分析,在Pre-build階段和Post-build階段進(jìn)行源代碼的修改,實(shí)現(xiàn)了通過比較編譯模塊Autogen相關(guān)文件時間戳是否改變的方式來提升增量編譯的性能和多線程產(chǎn)生平臺固件文件的方式來提升整體編譯的性能,采用這兩方面的改進(jìn),使得Build工具編譯達(dá)到更高的效率。最后在OVMF和KabyLake平臺的編譯過程中對上述兩個優(yōu)化方案進(jìn)行了檢測驗(yàn)證。
關(guān)鍵詞: UEFI;EDKII;Build;性能優(yōu)化
中圖分類號: TP302.7 ? ?文獻(xiàn)標(biāo)識碼: A ? ?DOI:10.3969/j.issn.1003-6970.2020.06.039
本文著錄格式:朱勇洪. 關(guān)于EDKII Build工具的性能優(yōu)化研究[J]. 軟件,2020,41(06):192195
【Abstract】: With the wide use of EDKII framework, the performance of Build tool becomes more and more important. Analyze the Build tools performance by cProfile, then update the code of Pre-build phase and Post-build phase, use the method to skip module Autogen by comparing timestamp and multiple thread to generate the firmware files to enhance the tools performance. In the end this enhancement method has been verified on OVMF and KabyLake platforms build process.
【Key words】: UEFI; EDKII; Build; Performance
0 ?引言
軟件廠商可以根據(jù)UEFI[1]標(biāo)準(zhǔn)開發(fā)屬于自己的UEFI實(shí)現(xiàn),其中最常用的開源實(shí)現(xiàn)便是EDKII[2]。EDKII是遵循UEFI標(biāo)準(zhǔn)和PI[3]標(biāo)準(zhǔn)的跨平臺固件開發(fā)環(huán)境,EDKII Build Tool是其中的平臺編譯工具。該工具目前正在被UEFI社區(qū)、開發(fā)人員、測試人員及UEFI愛好者以日均數(shù)以幾千次甚至上萬次的頻率在使用,對于一些簡單平臺的編譯,該工具能夠很快的完成編譯,而對于一些復(fù)雜的服務(wù)器平臺的編譯,該工具往往需要20分鐘甚至半小時以上的編譯時間,那么這個效率就很難讓使用者滿意了。因而該工具的性能在使用過程中越來越被人們重視起來了。
本文通過cProfile對Build工具編譯耗費(fèi)時間比較長的過程進(jìn)行分析,研究并實(shí)現(xiàn)了該工具在Pre-build階段和Post-build階段的一些優(yōu)化方案,有效的為整個平臺的編譯過程簡省編譯時長,提升工具的整體性能。
1 ?EDKII Build過程簡介
EDKII Build主要是用來處理EDKII meta-data文件(包括build_rule.txt, tools_def.txt, target.txt等),EDKII source和 binary文件,以及一些已經(jīng)存在的可兼容的EDK組件和庫模塊文件,最終產(chǎn)生遵循UEFI和PI規(guī)范的二進(jìn)制文件。
EDKII Build過程可以分為3個主要階段:
Pre-build(AutoGen)階段:主要是來解析meta-data文件,.dsc文件,.inf文件,.fdf文件,.dec文件,Unicode文件和VFR文件等,產(chǎn)生一些標(biāo)準(zhǔn)C的代碼文件(Autogen.c,Autogen.h)和相應(yīng)的Makefile文件[4]。
Build階段:主要是來處理source文件并通過Make(Linux系統(tǒng))或者Nmake(Windows系統(tǒng))來生成符合EFI格式的PE32/PE32+/COFF 文件[4]。
Post-build(ImageGen)階段:主要是來處理binary文件和EFI格式的文件,產(chǎn)生最終的UEFI Flash Images, Capsules,Applications和PCI Option ROMs[4]。
下圖1描述了這3個階段之間的關(guān)系。
在整個EDKII框架的編譯流程中涉及到了以下一些輸入文件:
.inf文件用于描述一個系統(tǒng)模塊(Module),它是UEFI系統(tǒng)的一個特色,其作用相當(dāng)于Visual Studio項(xiàng)目中的.proj文件,用于指導(dǎo)EDKII編譯工具自動編譯模塊,它包含[Defines]、[Sources]、[Packages]、[LibraryClasses]等必須的部分以及 [Depex]、[Protocols]、[Ppis]、[Guids]、[PCD]、[BuildOptions]等可選的部分[5]。
.dsc文件用于描述一個平臺包(Package),它相當(dāng)于Visual Studio項(xiàng)目中的.solution文件,用于指導(dǎo)編譯工具編譯整個平臺包,它包含[Defines]、[LibararyClasses]、 [Components]等幾個必需部分以及 [PCD]、[BuildOptions]等幾個可選部分[6]。其中在[Components]內(nèi)定義的模塊都會被Build 工具編譯并生成對應(yīng)的.efi可執(zhí)行文件。
.dec文件是一個聲明文件,它定義了公開的接口、數(shù)據(jù)及初始值,向其它模塊提供了本文件的資源。它包含了必須的[Defines]以及可選的[Includes]、[LibraryClasses]、[Guids]、[Protocols]、[Ppis]和[PCD]等幾個部分[7]。
.fdf文件是Flash的描述文件,描述了最終固件文件的組成結(jié)構(gòu),用于生成固件Image、Option Rom Image或可啟動的Flash Image等[8]。
Meta-data文件中的build_rule.txt一般不需要用戶更改,編譯工具通過整個文件來定義如何處理不同的文件類型,如何構(gòu)建最終的固件Image文件等規(guī)則;而tools_def.txt則描述了用戶可配置的工具的路徑、參數(shù)等信息,以及一些默認(rèn)的編譯器標(biāo)記;target.txt描述了此次編譯的平臺名字、架構(gòu),以及build_rule.txt和tools_def.txt文件所在的路徑信息,因此該文件是編譯工具啟動后第一個解析的。
2 ?性能優(yōu)化方案研究
整個Build工具的編譯過程復(fù)雜,涉及到的文件和相關(guān)工具的調(diào)用過程多,代碼量非常大,針對該工具性能的提升問題,本文采用Python自帶的性能分析模塊cProfile[9],將其嵌入到Build工具的代碼中執(zhí)行,從而可以對得到的結(jié)果進(jìn)行分析。
例如: python -m cProfile -s time "`dirname $0`/../../Source/Python"/`basename $0`/`basename $0`.py $*
對整個平臺進(jìn)行編譯,可以得到如圖2的實(shí)驗(yàn)結(jié)果:
通過對cProfile得到的結(jié)果進(jìn)行callers分析,發(fā)現(xiàn)整個工具的編譯過程在AutoGen\AutoGen.py、AutoGen\BuildEngine.py和GenFds\FfsInfStatement.py花費(fèi)的時間尤其多,因此可以考慮對其進(jìn)行優(yōu)化,主要是在Pre-build階段和Post-build階段中。
2.1 ?Pre-build階段優(yōu)化
Pre-build階段通過解析不同的meta-data文件來獲取平臺相關(guān)的基本信息之后,就開始解析各個不同的模塊的源文件來產(chǎn)生對應(yīng)的Autogen.c、Autogen.h、Makefile文件和.depex文件等[4]。在一個真實(shí)的平臺描述文件(.dsc)和Flash描述文件(.fdf)中,往往包含幾百個甚至上千個對應(yīng)的.inf文件需要解析,而每個.inf文件又關(guān)聯(lián)著非常多的系統(tǒng)驅(qū)動源文件和工程文件,從而導(dǎo)致整個平臺的編譯工程在Autogen階段需要花費(fèi)相當(dāng)長的時間,這種情況在復(fù)雜的服務(wù)器平臺的編譯過程中尤為常見。
考慮一個很常見的例子,當(dāng)UEFI開發(fā)人員對一個平臺進(jìn)行一次編譯之后,他后續(xù)對該平臺的某個系統(tǒng)驅(qū)動程序進(jìn)行更改,可能只是更改某一個簡單的.c 或者.h文件或者其它配置相關(guān)文件,此后當(dāng)他再次對整個平臺進(jìn)行重新編譯時,這個時候的Autogen過程針對那些沒有被更改過的系統(tǒng)驅(qū)動或者與被改動的驅(qū)動程序之間沒有存在依賴關(guān)系的系統(tǒng)驅(qū)動而言是可以優(yōu)化的。然而,通過對cProfile得到的結(jié)果進(jìn)行分析后,發(fā)現(xiàn)當(dāng)前的Build工具并沒有做這樣的優(yōu)化,而是每次編譯都全部重新進(jìn)行產(chǎn)生。
本文正是采用這個思路,通過判斷來優(yōu)化掉沒有被更改的或者與被更改的驅(qū)動文件不存在依賴關(guān)系的系統(tǒng)驅(qū)動程序的重新編譯中的Autogen過程,以此來簡省平臺在增量編譯過程中整個AutoGen階段的時間,從而達(dá)到平臺增量編譯過程的性能優(yōu)化。本文主要通過對EDKII Build工具Pre-build階段中AutoGen.py源文件進(jìn)行更改,在每一個編譯模塊進(jìn)行Autogen過程之后產(chǎn)生一個全新的文件AutoGenTimeStamp,這個新的文件中記錄了此次該模塊Autogen過程中所涉及到的所有文件,包括對整個平臺編譯都有影響的.dec文件,.dsc文件,.fdf文件,build_rule.txt,tools_def.txt,target.txt以及Build平臺時提供的全局參數(shù)等,也包括只與當(dāng)前模塊編譯相關(guān)的文件,其中包含有模塊本身的源文件和工程文件(如.inf文件,.c文件,.asm匯編文件,.uni字符串資源文件,.vfr窗體資源文件等),模塊依賴的庫模塊文件,編譯自動生成的Autogen.h文件等。因此在用戶對某個或某些系統(tǒng)驅(qū)動程序進(jìn)行更改之后,重新對該平臺進(jìn)行增量編譯時,通過對已經(jīng)存在的AutoGenTimeStamp的分析比較便可以知道當(dāng)前的文件改動對這個驅(qū)動程序的重新編譯是否有影響,如果有影響,則該模塊的Autogen過程重新執(zhí)行一次,否則,可以直接優(yōu)化掉該模塊的Autogen過程,從而可以省略掉沒有被影響的模塊的Autogen過程,以此來減少整個平臺在增量編譯過程中 ? ?的Autogen時間。當(dāng)然,如果用戶此次改動的是 ? ?一個全局的文件類型,如.dec文件,.dsc文件, build_rule.txt等,那么此次新的增量編譯過程中所有的AutoGenTimeStamp都會被更新,在這種情況下,這個優(yōu)化方案對整個平臺的增量編譯性能上是沒有額外提升的。除此之外,也可以考慮通過增加計算hash值的比較方式來進(jìn)行文件是否更改的 ? 判斷。
2.2 ?Post-build階段優(yōu)化
當(dāng)所有的模塊的.efi可執(zhí)行文件生成之后,就進(jìn)入了Post-build的階段。這個階段處理各個模塊的.efi可執(zhí)行文件以及一些Binary文件并通過特定的規(guī)則將其生成相應(yīng)的固件文件(Firmware files)、固件卷(Firmware volume)及最終的Flash image文件。整個流程如下圖3所示。
本文在對cProfile得到的結(jié)果并結(jié)合Build工具源代碼進(jìn)行分析后,發(fā)現(xiàn)目前EDKII Build工具在固件文件生成的時候是單線程執(zhí)行的,因此這個階段最大的性能優(yōu)化便在于如何實(shí)現(xiàn)多線程方式的產(chǎn)生平臺編譯所需的所有固件文件。
本文正是基于整個思路,實(shí)現(xiàn)多線程的方式產(chǎn)生固件文件來達(dá)到優(yōu)化平臺編譯的目的。通過對Pre-build階段、Build階段和Post-build階段的源代碼分析后,發(fā)現(xiàn)Pre-build階段是采用多線程的方式進(jìn)行文件的解析,Build階段也是通過多線程方式調(diào)用對應(yīng)的Makefile來產(chǎn)生此次平臺編譯所需的所有.efi可執(zhí)行文件,僅僅只有Post-build階段是單線程的依據(jù)系統(tǒng)驅(qū)動程序在平臺描述文件(.dsc)和Flash描述文件(.fdf)中的順序進(jìn)行逐一產(chǎn)生對應(yīng)的固件文件。本文采用了一種最簡便,代碼量更改較少的方式來進(jìn)行多線程的產(chǎn)生固件文件,首先通過更改Build階段中Makefile的生成過程,將每個系統(tǒng)驅(qū)動程序的固件文件的生成過程也給寫到該模塊對應(yīng)的Makefile文件中,從而可以簡便地利用現(xiàn)在已有的Build階段中的多線程機(jī)制進(jìn)行多線程的生成一個平臺編譯中所需要的所有固件文件,簡省Post-build階段的編譯時間,最終簡省平臺的整個編譯時間。其中涉及到Autogen過程中對Makefile文件的重新生成,Post-build階段中各個section(包括Apriori section,Compress section,Data section,Depex section,EFI section等)的重新生成過程以及Region的重新組成等復(fù)雜過程。該方法比直接考慮在現(xiàn)有EDKII框架下對Post-build階段代碼進(jìn)行重構(gòu)來實(shí)現(xiàn)多線程的方式更加容易實(shí)現(xiàn)。通過整個優(yōu)化后,發(fā)現(xiàn)編譯OVMF平臺在Post-build階段所花費(fèi)的時間直接從37 s降低到了8 s。
3 ?優(yōu)化方案的測試檢驗(yàn)
該檢驗(yàn)過程主要通過編譯OVMF(Open Virtual Machine Firmware)平臺和KabyLake平臺來查看Build 工具的編譯時間的變化來檢驗(yàn)性能是否有所優(yōu)化。OVMF是用于虛擬機(jī)上的UEFI固件,能夠較好的模擬真實(shí)環(huán)境,又可以做到快速、方便、簡單。而KabyLake平臺是搭載Intel第七代酷睿處理器的真實(shí)平臺。
下表1和表2中的數(shù)據(jù)均是在相同環(huán)境下編譯五次后所得的有效數(shù)據(jù)的平均值,表1表示的是在一次編譯過程之后進(jìn)行系統(tǒng)某些驅(qū)動文件更改后的增量編譯在Autogen階段所需要的時間,表2表示的是一次全新編譯過程總共所需要的時間。從表1 中可以看出,針對Pre-build階段的關(guān)于增量編譯的優(yōu)化方案可以提升27%-47%左右的性能,從表2中可以看出,針對Post-build階段的優(yōu)化方案可以提升15%-25%左右的性能。從而可以說明Pre-build階段和Post-build階段所采用的優(yōu)化方案對編譯工具整體性能的提升是有效的,尤其是對一些編譯時間比較長的服務(wù)器平臺,其性能提升的效果是比較明顯的。
目前這兩個方案的優(yōu)化patch已經(jīng)提交到開源的EDKII項(xiàng)目的github上去了。
4 ?結(jié)束語
本文通過cProfile模塊對Build工具性能進(jìn)行分析后,在Pre-build階段和Post-build階段分別通過比較編譯模塊Autogen相關(guān)文件時間戳是否發(fā)生改變的優(yōu)化和采用多線程方式產(chǎn)生各個驅(qū)動文件的固件文件的優(yōu)化方案來提高整個編譯過程的性能。除此之外,也可以對編譯工具中的函數(shù)在一次編譯過程中的調(diào)用次數(shù)以及所花費(fèi)的時間來進(jìn)行分析,進(jìn)行函數(shù)優(yōu)化來達(dá)到提高性能的目的,例如ValueExpressionEx函數(shù)。
參考文獻(xiàn)
[1] UEFI Forum. UEFI Specification[OL].(2019-03) [2020-02]. http://www.uefi.org/specs/
[2] 戴正華. UEFI原理與編程[M]. 北京:機(jī)械工業(yè)出版社, 2015. 1: 14.
[3] UEFI Forum. UEFI Platform Initialization Specification [OL].(2019-01) [2020-02].http://www.uefi.org/specs/.
[4] Intel Corporation. EDK II Build Specification[OL].(2018-04) [2020-02].https://edk2-docs.gitbooks.io/edk-ii-build-specification/content/v/release/1.28/.
[5] Intel Corporation. EDK II INF Specification[OL].(2018-04) [2020-02].https://edk2-docs.gitbooks.io/edk-ii-inf-specification/content/v/release/1.27/.
[6] Intel Corporation. EDK II DSC Specification[OL].(2018-04) [2020-02]. https://edk2-docs.gitbooks.io/edk-ii-dsc-specification/ content/v/release/1.28/.
[7] Intel Corporation. EDK II DEC Specification[OL].(2018-04) [2020-02].https://edk2-docs.gitbooks.io/edk-ii-dec-specification/content/v/release/1.27/.
[8] Intel Corporation. EDK II FDF Specification[OL].(2017-06) [2020-02].https://edk2-docs.gitbooks.io/edk-ii-fdf-specification/content/v/release/1.28/.
[9] Python Software Foundation. The Python Profilers[OL]. (2019-06) [2020-02]。https://docs.python.org/3/library/profile.html.