自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

抖音 Swift 編譯優(yōu)化 - 基于自定義 Toolchain 編譯提速 60%

移動開發(fā)
本文重點探討全部模塊化后帶來的依賴解析瓶頸,主要包括對頭文件增量編譯分析等內(nèi)容。

優(yōu)化方案基于 Swift Toolchain 源碼,本文不再探討 Toolchain 相關(guān)基本概念及配置流程等,僅聚焦方案本身。?

背景

隨著混編落地的業(yè)務(wù)場景越來越多,越來越大,開發(fā)中出現(xiàn)的性能痛點開始顯現(xiàn),問題很明顯集中在被 Swift 環(huán)境所依賴的 OC 倉的頭文件改動上。因此基建架構(gòu)把重點放在接口層依賴的性能分析上,力求解決性能瓶頸。

抖音基礎(chǔ)技術(shù)團隊借助自定義 Toolchain 能力,通過自定義編譯參數(shù),裁剪 Clang Header 指定內(nèi)容,最終實現(xiàn)編譯提速 60% 。

本方案已于 2022 年 11 月底上線,在抖音穩(wěn)定運行近 5 個月。下面就讓我們一起回顧下整個方案從提出到落地的全過程。

初步分析

在混編場景下,若要確保 OC 與 Swift 間盡可能充分地互操作,則模塊化的啟用無法僅用在 Swift 編譯上下文中——Swift編譯導(dǎo)出的 Clang Header,在工程中以??$(project_name)-Swift.h??形式出現(xiàn),將其需要被 re-export 引用的 OC 依賴項,以模塊的形式導(dǎo)出,這就意味著若 OC 編譯不啟用模塊化,則無法正確使用 Swift 提供的頭文件。

圖片

如圖,二者不可兼得,Objc Pod D 為了能夠解析語句??@import A;??而引入??A.modulemap??,則其與 A 的互操作不可能再基于文本導(dǎo)入的邏輯,而全面轉(zhuǎn)向模塊化。

對于抖音而言,巨型 OC 項目的大量頭文件傳遞依賴的歷史包袱,使得在 OC 編譯中引入模塊化是一場災(zāi)難。模塊化環(huán)境下,緩存系統(tǒng)決議是否要命中 .o 緩存的耗時,比文本環(huán)境下重新編譯耗時還要長;增量編譯時,也會導(dǎo)致廣泛的模塊重編,改動一個頭文件,就要等待數(shù)分鐘。

傳遞依賴治理是一項長期工程,但編譯優(yōu)化等不了那么久,我們需要一個可以快速解決的方案。

優(yōu)化效果

在介紹方案之前,先上結(jié)論。

在抖音工程中選取代碼量最大的 OC&Swift 混編倉庫進(jìn)行測試:

  • OC 增量編譯:選取被 Swift 依賴的 OC 接口層頭文件進(jìn)行改動,編譯耗時降低 60%
  • Swift 增量編譯:選取被 OC 依賴的 Swift public class 進(jìn)行改動,編譯耗時相近,無變化
  • 全量編譯:清除本地編譯緩存進(jìn)行 clean build,編譯耗時降低 17%

可見該方案對編譯速度的巨大提升。接下來就讓我們回顧一下整個方案從預(yù)研到上線的過程。

方案原理

解決問題的關(guān)鍵在于降低將 OC 頭文件預(yù)編譯耗時,這里有兩個思路:

  • 長期:模塊解析的耗時根源在于傳遞依賴,模塊的特性導(dǎo)致不同模塊內(nèi)包含的頭文件的傳遞依賴會將模塊增量重編的影響范圍擴展到很大。業(yè)務(wù)庫在現(xiàn)有工程架構(gòu)體系下已經(jīng)嚴(yán)格控制了接口層傳遞依賴,因此長期方案會逐步推動治理基礎(chǔ)庫的傳遞依賴問題。
  • 短期:將 OC 頭文件預(yù)編譯轉(zhuǎn)回文本導(dǎo)入,即裁剪-fmodule-map-files注入,但依然保留對 OC 調(diào)用 Swift 代碼的支持

圖片

Swift會將自身接口層(即 public/open )聲明使用到的 C/OC 模塊,在??xxx-Swift.h??中以??@import aaa??形式給出,這就要求 OC 側(cè)使用該頭文件時也需要將這些模塊對 OC 側(cè)可見,我們想要達(dá)成目的,就需要對這些聲明進(jìn)行裁剪。這需要自定義工具鏈的支持。

本次優(yōu)化方案效果測試針對的是短期方案。

通過修改編譯器,對 Swift 編譯生成的 Clang Header Interface 進(jìn)行裁剪,刪除掉系統(tǒng)庫以外的 @import,而 OC 側(cè)引用該頭文件的地方手動補全依賴。即以暫時犧牲接口self-contained為代價,使OC側(cè)不必再關(guān)心模塊相關(guān)的因素。為支持更細(xì)粒度的控制,通過向編譯器注入編譯參數(shù),以針對不同組件控制此功能的啟用,以及實現(xiàn)更具體的裁剪內(nèi)容。

而對于??-fmodule-map-files??的裁剪相對容易,只需修改??OTHER_CFLAGS??即可關(guān)閉??-fmodule-map-files??的注入。

預(yù)研

方案拆解

我們先來對整個方案做一個任務(wù)拆解,可以分析出各部分的依賴關(guān)系,節(jié)省預(yù)研階段的耗時。

一個工具鏈相關(guān)的落地方案,必須保證其穩(wěn)定性,因此一定是可以通過一種簡單的方式進(jìn)行外部控制開關(guān)的。

從發(fā)版角度講,工具鏈發(fā)版并不像業(yè)務(wù)代碼,和存放在開發(fā)倉庫的配置一樣可以靈活發(fā)版,因此應(yīng)盡可能保證工具鏈代碼的穩(wěn)定,非必要不修改。

基于這兩個原則,我們可以拆解為:

1.分析 ??swiftc?? 的參數(shù)解析機制,在編譯時的參數(shù)列表中拼接新的自定義參數(shù)以控制裁剪能力。??swiftc?? 是實際的前端 ??swift-frontend?? 的一個入口,下面會詳細(xì)提到,向 swiftc 注入的參數(shù)列表,在各 ??swift-frontend?? 子任務(wù)中并不總是以相同的全集出現(xiàn),作用機制需要進(jìn)一步分析。

2.基于細(xì)粒度控制的考量,參數(shù)選擇傳入一個配置文件,包含一個白名單,來確定哪些??@import Module??是可以留下的。我們也有考慮過黑名單,但實際工程的依賴情況是復(fù)雜的,不論是 Cocoapods 還是 seer ,都僅能描述工程層面的依賴情況,而不能保證實際編譯時的依賴情況,難以構(gòu)建一個全面的業(yè)務(wù)黑名單。而系統(tǒng)庫白名單是相對固定的,并不需要經(jīng)常維護(hù)。

3.尋找生成 -Swift.h 的具體函數(shù),以及寫入??@import Module;??的邏輯以進(jìn)行裁剪。

4.在寫入邏輯處加載白名單文件并進(jìn)行過濾。

5.通過本地驗證,完成無感知下發(fā) Toolchain 的驗證,打出測試 Toolchain 。

6.灰度驗證。

7.合碼發(fā)版上線。

快速驗證

想要驗證方向是否正確,同時給予飽受編譯耗時困擾的業(yè)務(wù)同學(xué)以信心,需要先找到最關(guān)鍵的點快速驗證。

因此我們決定先直接整體關(guān)掉所有 -Swift.h 的??@import Module;??生成邏輯。此時我們對整體 Swift 源碼的認(rèn)知還較為模糊,但我們只需要去尋找類似??<< "@import"??或其他寫文件的邏輯再去篩選即可,所幸這一過程沒有花費太久。

圖片

我們很快找到了這塊邏輯,并直接將??out << "@import " << Name.str() << ";\n";??注釋掉,打包驗證成功,出具了本文開頭的數(shù)據(jù)報告,給業(yè)務(wù)同學(xué)吃下一顆定心丸。

接下來,我們就可以穩(wěn)健地按部就班地去執(zhí)行其他任務(wù)了。

開發(fā)、調(diào)試

swift-frontend 參數(shù)解析流程

于是我們將目光轉(zhuǎn)向了其他在前端層級應(yīng)用的原生參數(shù),并參考它們的寫法。很快我們將目光鎖定在??module-cache-path??,這是一個 Swift 前端編譯必需的參數(shù),指定模塊緩存位置,且后面?zhèn)魅胍粋€路徑,完全符合我們的要求。

根據(jù)對該參數(shù)的分析,可得 -frontend 階段的參數(shù)解析流程,具體調(diào)研過程不再展開,直接簡單過下流程。

圖片

簡單流程如上圖,下面具體過下修改參數(shù)解析流程的代碼位置。

定義

圖片

此處使用了一種十分類似 python 的,LLVM 推出的 TableGen (https://llvm.org/docs/TableGen/)語言,后面這些 flag ,我們需要的是

  • FrontendOption 前端參數(shù),擁有這個flag才會進(jìn)入前端參數(shù)解析流程,而 Clang Header 生成的過程就發(fā)生在前端流程中
  • ArgumentIsPath 參數(shù)為路徑,告知編譯器該參數(shù)后攜帶路徑字符串作為參數(shù)

仿照這種形式的自定義參數(shù):

圖片

第二個 EQ 定義其實是一種 Alias,定義了可以使用" flag=arg "這種形式來進(jìn)行傳參,沒有其他額外作用。

通過??tablegen??工具,把 Options.td 的內(nèi)容生成為 Options.inc ,如下圖

圖片

結(jié)合 Swift 源碼中 Options.h 的 OPTION 定義,引入并提供給 cpp 代碼使用

圖片

解析

解析過程發(fā)生在 CompilerInvOCation 的參數(shù)解析流程中

圖片

在 ArgsToFrontendOptionsConverter 方法中,從參數(shù)列表讀取需要的信息,賦值到 Opts 當(dāng)中

圖片

Opts 是一個 FrontOptions 類型的實例,我們需要在這里定義一個字符串以存儲我們需要的參數(shù)

圖片

Opts 會在整個前端流程中流轉(zhuǎn),為各環(huán)節(jié)提供必要參數(shù)。

Clang Header 生成流程

調(diào)用過程的流程圖如下,PrintAsClang 是一個相對獨立的模塊,我們改動只需要關(guān)注這兩個標(biāo)紅環(huán)節(jié)即可。

圖片

增加入?yún)⒍x

在原方法定義上加入兩個傳參,分別是我們傳入的白名單文件路徑,以及診斷信息,診斷信息后面會提到,用于提示一些自定義錯誤。

圖片

這里也是相同,增加兩個參數(shù)定義。

圖片

白名單解析

printAsClangHeader 這里是我們的主要修改之一,在這個 function_ref 當(dāng)中,我們對 allow list path 指向的文件進(jìn)行了內(nèi)容解析,得到白名單指定的模塊名稱,以參數(shù)形式傳遞給下一個環(huán)節(jié)。

圖片

writeImports 方法在原有基礎(chǔ)上增加一個 function_ref,可以理解為 ??lambda?? 表達(dá)式,就是我們剛剛做的白名單解析的過程。

圖片

在具體寫入??@import Module;??處進(jìn)行白名單篩選,在白名單內(nèi)部的允許寫入,否則跳過。

圖片

自定義診斷信息

DiagnosticsClangImporter.def 中加入兩個自定義條目,error 用于提示解析錯誤,note 僅提示白名單為空,為空是允許的操作,此時退化為默認(rèn)邏輯。

圖片

前面我們在方法定義中傳入了 Diags 實例,想要提示信息,只需簡單調(diào)用即可,note 只會輸出到日志,error 則會打斷編譯流程。

圖片

驗證、上線

可使用云構(gòu)建機器打出測試 Toolchain,下載至本地,集成到 Xcode 中在抖音驗證即可。

將自定義參數(shù)加入到指定混編組件的編譯參數(shù)當(dāng)中,即可成功構(gòu)建。

后記

Swift 工具鏈定制是一個擁有無限可能的方向,包括編譯優(yōu)化這類效率提升的工作等等,都可以在底層進(jìn)行傳統(tǒng)意義上的架構(gòu)層所難以進(jìn)行的深度優(yōu)化,后續(xù)針對這塊可做的事還有很多,相信有更多的經(jīng)驗可以分享給到大家。

責(zé)任編輯:龐桂玉 來源: 字節(jié)跳動技術(shù)團隊
相關(guān)推薦

2022-06-06 12:19:08

抖音功耗優(yōu)化Android 應(yīng)用

2022-06-01 09:18:37

抖音ReDex算法優(yōu)化

2024-06-13 17:10:16

2022-03-29 13:27:22

Android優(yōu)化APP

2022-07-19 16:47:53

Android抖音

2021-07-01 11:07:49

Swift 自定義操作符

2022-07-06 13:02:00

高延時電商直播主播互動

2011-09-09 14:39:43

S60 Webkit

2023-11-03 17:02:18

抖音直播畫質(zhì)優(yōu)化

2015-02-12 15:33:43

微信SDK

2023-07-31 07:33:04

Rust編譯器內(nèi)存

2022-04-28 15:07:41

抖音內(nèi)存泄漏Android

2021-06-08 09:00:42

Swift 協(xié)議LLDB 命令

2015-02-12 15:38:26

微信SDK

2022-11-01 11:15:56

接口策略模式

2009-07-06 13:49:29

2011-09-09 15:08:17

S60 WebKit

2023-11-15 17:58:58

C++代碼

2023-03-03 15:43:23

抖音世界杯畫質(zhì)優(yōu)化

2016-12-26 15:25:59

Android自定義View
點贊
收藏

51CTO技術(shù)棧公眾號