戰(zhàn):Vivado工程從13小時(shí)優(yōu)化到5小時(shí)的方法)
1. 為什么你的工程要編譯13個(gè)小時(shí)FPGA編譯慢這個(gè)事兒折磨過的人都知道。一次小改動(dòng)改兩行RTL代碼重新跑一遍綜合和布局布線動(dòng)輒大半天沒了。更難受的是你沒法干等因?yàn)榫幾g占著工作站你想干點(diǎn)別的都怕把機(jī)器搞卡。我見過不少團(tuán)隊(duì)FPGA工程師的時(shí)間基本被編譯吃掉一半早上提交編譯下午出結(jié)果趕上時(shí)序不收斂晚上還得再來一輪。這根本不是個(gè)例是整個(gè)行業(yè)的普遍狀態(tài)。我最近碰到一個(gè)項(xiàng)目規(guī)模不算特別夸張Zynq UltraScale 系列邏輯資源用了大概三十多萬LUTBRAM和DSP也吃了不少還用到了多路高速SerDes和PCIE核。這種規(guī)模在真實(shí)產(chǎn)品里非常常見不算最難啃的但已經(jīng)足夠把編譯時(shí)間拉到13個(gè)小時(shí)左右。整個(gè)流程跑完綜合加布局布線加時(shí)序收斂再加生成比特流和調(diào)試文件一輪下來就像過了一個(gè)工作日。項(xiàng)目后期每天迭代好幾版時(shí)間全砸在等待上。后來我用了一段時(shí)間把整體編譯時(shí)間從13小時(shí)壓到5小時(shí)以內(nèi)。沒有換服務(wù)器CPU沒有加內(nèi)存也沒改工程結(jié)構(gòu)純粹是圍繞Vivado的編譯流程做了一輪系統(tǒng)性的提速優(yōu)化。這里面思路并不復(fù)雜關(guān)鍵是有幾個(gè)環(huán)節(jié)必須搞清楚、抓準(zhǔn)。這篇文章把整個(gè)過程的思路、操作和坑都整理出來希望能幫到同樣被編譯時(shí)間折磨的人。先說清楚一個(gè)前提FPGA編譯時(shí)間這個(gè)痛點(diǎn)適合所有使用Xilinx Vivado做中大型項(xiàng)目的人不管是Zynq系列、Kintex系列還是UltraScale原理都是通用的。小項(xiàng)目編譯幾分鐘就完事兒感受不明顯但一旦資源量上來了時(shí)序約束復(fù)雜了或者用了大量IP核編譯時(shí)間就會(huì)急劇膨脹。此時(shí)如果不能精確控制編譯流程代價(jià)就是人力空轉(zhuǎn)、項(xiàng)目延期、凌晨加班。而這些問題其實(shí)大部分都有辦法解決。2. 編譯慢的核心原因剖析2.1 先搞清楚時(shí)間到底花在哪個(gè)階段要提速第一步不是盲目開多線程或者套增量編譯模板而是先測量的。Vivado整個(gè)編譯流程分為綜合、布局、布線、時(shí)序優(yōu)化、比特流生成幾個(gè)大階段。不同階段的耗時(shí)占比差異非常大而且和工程本身的資源結(jié)構(gòu)強(qiáng)相關(guān)。脫離數(shù)據(jù)談優(yōu)化基本等于靠猜。我在這個(gè)工程里做了詳細(xì)的耗時(shí)統(tǒng)計(jì)。綜合階段大約占1.5小時(shí)其中因?yàn)槭褂昧舜罅縄P核IP的OOC綜合占了不少時(shí)間。后端的布局布線階段是大頭布局約2小時(shí)布線約4.5小時(shí)時(shí)序優(yōu)化流程跑下來又吃掉了2.5小時(shí)。最后生成比特流和調(diào)試用的調(diào)試核文件大約0.5小時(shí)。這一算下來13個(gè)小時(shí)基本是實(shí)打?qū)嵉牟皇悄膬撼隽薆ug導(dǎo)致卡死。如果資源利用率更高、時(shí)序約束更緊布線和時(shí)序優(yōu)化的耗時(shí)比例還會(huì)進(jìn)一步上升。布線是整個(gè)FPGA編譯里最耗時(shí)的一步尤其是全局布線因?yàn)楣ぞ咭邶嫶蟮穆酚少Y源中尋找最優(yōu)路徑既要滿足時(shí)序要求又要避免擁塞沖突。而時(shí)序優(yōu)化是一個(gè)反復(fù)迭代的過程一次不收斂工具就自動(dòng)調(diào)整策略再跑一遍非常耗時(shí)。知道這個(gè)結(jié)構(gòu)之后思路就清楚了后期日常小改動(dòng)迭代真正需要跑的其實(shí)只有后段局部。如果能在前端把時(shí)間截住省下來的就是幾個(gè)小時(shí)。2.2 瓶頸不只是CPU還有I/O和策略很多人第一反應(yīng)是加CPU核數(shù)、升主頻。確實(shí)有效果但效果有限。Vivado的并行度設(shè)計(jì)有一個(gè)特點(diǎn)綜合和布局布線階段的多線程支持是有上限的一般到8個(gè)線程之后收益就明顯衰減。而且工程如果放在機(jī)械硬盤上讀寫大工程文件會(huì)頻繁觸發(fā)磁盤I/O綜合和布線的時(shí)間可能被I/O等待拖慢不少。還有一個(gè)大家容易忽視的點(diǎn)時(shí)序約束策略和綜合策略直接影響編譯耗時(shí)。默認(rèn)策略是保守的、通用的不針對具體工程做任何傾向性優(yōu)化。如果工程本身時(shí)序余量很緊張默認(rèn)策略會(huì)反復(fù)做時(shí)序優(yōu)化嘗試一次不收斂就跑多輪結(jié)果就是耗時(shí)成倍增加。反過來工程本身時(shí)序余量充足卻使用了超高性能優(yōu)化策略也會(huì)白白多花時(shí)間。策略跟工程實(shí)際情況不匹配是很多人編譯慢的隱藏原因。這里插一句。網(wǎng)上很多帖子推薦直接改-max_threads參數(shù)拉滿多線程實(shí)際上對于Linux環(huán)境下的大工程有一定幫助但Windows環(huán)境下進(jìn)程管理機(jī)制不同收益沒那么明顯。另有一些教程推薦“關(guān)閉OOC綜合”或者“拼命加增量編譯”如果使用時(shí)機(jī)不對反而會(huì)導(dǎo)致工具判斷失效甚至更慢。不要盲目跟風(fēng)一切以數(shù)據(jù)說話。3. 編譯進(jìn)度監(jiān)控與性能測量方法3.1 學(xué)會(huì)讀取Vivado的報(bào)告Vivado在編譯過程中會(huì)生成大量信息但很多人不看或者看的時(shí)候只盯著有沒有報(bào)錯(cuò)。真正有效的做法是在綜合和布局布線完成后主動(dòng)去查看報(bào)告文件里的“Runtime”部分那里有每個(gè)階段的耗時(shí)明細(xì)。具體路徑是Report Utilization看資源占用Report Timing Summary看時(shí)序狀態(tài)Report Methodology看靜態(tài)檢查。但耗時(shí)分布要到Tcl Console里輸入report_runtime或者打開runme.log文件查看。runme.log里會(huì)記錄每一步啟動(dòng)和結(jié)束時(shí)的時(shí)間戳用時(shí)間戳差值就能計(jì)算出每個(gè)獨(dú)立步驟的真實(shí)耗時(shí)。這是最準(zhǔn)確的第一手?jǐn)?shù)據(jù)。我看到很多人的工作習(xí)慣是雙擊Run Synthesis然后去刷手機(jī)。編譯完了直接看有沒有時(shí)序錯(cuò)誤。如果時(shí)序沒過改兩行代碼又跑一遍。這樣一個(gè)循環(huán)下來時(shí)間全浪費(fèi)在“盲目的等待”和“重復(fù)性的全量編譯”上。如果愿意多花5分鐘看一次日志分析耗時(shí)分布優(yōu)化的方向自然就出來了。沒有數(shù)據(jù)支撐的優(yōu)化都是盲人摸象。3.2 寫好腳本實(shí)現(xiàn)全流程自動(dòng)化純粹在GUI里操作編譯過程中的參數(shù)調(diào)整非常費(fèi)勁。更高效的做法是用Tcl腳本把整個(gè)編譯流程串起來。Vivado的Tcl支持非常好幾乎GUI里能做的所有操作都能在腳本里完成而且腳本可以版本化方便團(tuán)隊(duì)協(xié)作。我在做提速優(yōu)化時(shí)一開始就把GUI操作全部遷移到了Tcl腳本里。最基本的腳本長這樣open_project /path/to/project.xpr launch_runs synth_1 -jobs 8 wait_on_run synth_1 open_run synth_1 -name netlist_1 launch_runs impl_1 -to_step write_bitstream -jobs 8 wait_on_run impl_1 report_timing_summary -file timing_summary.rpt report_utilization -file utilization.rpt這段腳本的作用是打開工程啟動(dòng)綜合8線程等待綜合完成然后打開綜合后的網(wǎng)表啟動(dòng)布局布線直到生成比特流最后輸出時(shí)序和資源報(bào)告。整個(gè)過程不需要人工干預(yù)。腳本化之后編譯提速才能真正落地。因?yàn)槟悴恍枰看问謩?dòng)去GUI里翻找設(shè)置項(xiàng)改參數(shù)也只是改腳本的一兩行批量驗(yàn)證非常方便。我自己習(xí)慣在腳本里加上-to_step write_bitstream節(jié)省一步操作。另外也可以在腳本里加入set_property strategy Performance_Explore [get_runs impl_1]之類的設(shè)置方便在不同策略之間切換做對比測試。這一步對于后面要說的策略優(yōu)化很關(guān)鍵沒有腳本策略對比會(huì)累死人。4. 綜合階段的提速方案4.1 合理調(diào)整綜合策略別讓綜合成為拖累綜合階段是在將RTL代碼轉(zhuǎn)換為門級網(wǎng)表的過程中進(jìn)行邏輯優(yōu)化、資源推斷和工藝映射。默認(rèn)情況下Vivado的綜合策略會(huì)盡可能地做面積和性能平衡這本身沒問題但對于大型工程默認(rèn)策略的耗時(shí)可能偏高。在Vivado中綜合階段常見的策略有Flow_RuntimeOptimized和Flow_AreaOptimized_High。前者傾向于縮短綜合時(shí)間后者傾向于優(yōu)化面積。如果工程當(dāng)前處于功能迭代期時(shí)序壓力不太大的情況下用Flow_RuntimeOptimized綜合會(huì)快不少。實(shí)測中同樣一個(gè)模塊默認(rèn)綜合大約需要1.5小時(shí)切到Flow_RuntimeOptimized之后能壓到1小時(shí)左右。省下來的時(shí)間不多但恰好能保證綜合結(jié)果在后端布局布線中不會(huì)變差太多。具體操作方式set_property strategy Flow_RuntimeOptimized [get_runs synth_1]如果工程里面使用了大量第三方IP或者自己封裝的IP綜合階段還有另一個(gè)大頭OOC綜合。OOC全稱Out-of-Context意思是IP核在頂層工程綜合之前先獨(dú)立完成綜合。好處是IP綜合結(jié)果可以復(fù)用不隨頂層修改而重新綜合。壞處是第一次跑的時(shí)候所有IP都要單獨(dú)綜合一遍耗時(shí)很長。解決辦法是在工程設(shè)置里打開-mode out_of_context并配合增量綜合使用。但要注意IP版本更新或者參數(shù)調(diào)整后對應(yīng)的OOC結(jié)果會(huì)失效需要重新綜合。4.2 增量綜合的正確用法和適用條件增量綜合Incremental Synthesis是很多加速教程推薦的第一方案。但不少人對它的理解有偏差。它并不是“只編譯改動(dòng)的那一小部分代碼”這么簡單而是通過復(fù)用上一次綜合的中間結(jié)果減少邏輯優(yōu)化和工藝映射的計(jì)算量。前提是代碼改動(dòng)范圍比較小且沒有改動(dòng)到模塊接口。我當(dāng)時(shí)在功能迭代階段使用增量綜合實(shí)測把綜合時(shí)間從1小時(shí)壓到了20分鐘左右。比如我改了一段狀態(tài)機(jī)的邏輯但接口沒變那么增量綜合只需要重新綜合這個(gè)狀態(tài)機(jī)相關(guān)的邏輯塊其余部分直接用上次的結(jié)果。但如果改了頂層的端口定義、或者改動(dòng)涉及跨模塊的信號連接增量綜合的效果會(huì)大打折扣有時(shí)甚至?xí)|發(fā)全量重新綜合反而更慢。另外增量綜合有一個(gè)前置條件上一次綜合結(jié)果的文件必須還在不能清理掉。Vivado默認(rèn)會(huì)保留synth_1目錄下的incremental_synth文件但如果手動(dòng)清理過工程目錄或者換了一臺(tái)機(jī)器增量綜合會(huì)失效。這里也提醒一下增量綜合依賴的是工程目錄下的中間文件版本管理工具通常會(huì)忽略這些文件換環(huán)境之后需要重新做一次全量綜合建立新的基線之后才能繼續(xù)使用增量。實(shí)操時(shí)記得在運(yùn)行綜合前先用Tcl命令檢查是否存在可復(fù)用的增量文件get_property INCREMENTAL_CHECKPOINT [get_runs synth_1]返回路徑不為空才說明增量綜合可用。5. 布局布線階段的核心加速手段5.1 全局布線是耗時(shí)的重災(zāi)區(qū)如何針對性優(yōu)化布局布線階段是整個(gè)編譯過程中占比最大的部分通常占據(jù)總時(shí)間的60%到70%。這個(gè)階段里時(shí)序驅(qū)動(dòng)的布局和布線算法高度依賴計(jì)算資源也是很多優(yōu)化手段瞄準(zhǔn)的重點(diǎn)。針對布線耗時(shí)Vivado提供了多個(gè)布線策略。常用的是Performance_Explore、Congestion_SpreadLogic_high、RuntimeOptimized。默認(rèn)的布線策略偏向于在時(shí)序和擁塞之間尋找平衡但在工程時(shí)序余量充足的情況下可以切換為RuntimeOptimized。這個(gè)策略會(huì)放寬部分全局優(yōu)化范圍減少不必要的迭代實(shí)測能節(jié)省約20%到30%的布線時(shí)間。我用Tcl設(shè)置布局布線的實(shí)現(xiàn)策略set_property strategy Performance_Explore [get_runs impl_1]注意這里使用的是Performance_Explore聽起來像是追求性能的但這個(gè)策略在多個(gè)子步驟中會(huì)探索不同的參數(shù)組合有時(shí)反而比RuntimeOptimized更快得出結(jié)果因?yàn)樗芨煺业綕M足約束的方案減少后續(xù)的時(shí)序收斂迭代。針對不同工程需要測試后才能確定最優(yōu)策略。我在這個(gè)項(xiàng)目中Performance_Explore比RuntimeOptimized還要快原因是工程時(shí)序約束相對寬松工具在第一輪探索中就找到了滿足要求的布線方案。還有一點(diǎn)在布局布線階段如果開了比特流生成會(huì)額外增加時(shí)間。如果當(dāng)前只是需要驗(yàn)證時(shí)序或者做資源評估不會(huì)立即上板調(diào)試可以先用-to_step route_design把比特流生成留到最終確定版本時(shí)再做。這一步看似不起眼實(shí)際也能省10到15分鐘。5.2 布局方面的重要選項(xiàng) Floorplanning和PBlock布局階段的加速手段除了策略切換還有一個(gè)更深層的方案手動(dòng)布局約束Floorplanning。很多人覺得手動(dòng)布局是大神才干的事其實(shí)并不復(fù)雜只需要對設(shè)計(jì)關(guān)鍵模塊的位置做大致規(guī)劃就能有效減少布局器的搜索空間。實(shí)際操作上可以用PBlock約束把某個(gè)大的模塊固定在某個(gè)區(qū)域。例如PCIE控制器和DMA邏輯放在一個(gè)時(shí)鐘區(qū)域附近圖像處理管線放在另一個(gè)時(shí)鐘區(qū)域這樣可以減少跨區(qū)域繞線距離布線器的壓力變小也降低時(shí)序收斂難度。運(yùn)行布局時(shí)工具不再從頭全局搜索而是在給定初始位置的基礎(chǔ)上進(jìn)行局部優(yōu)化時(shí)間會(huì)明顯縮短。但這里一定要說清楚Floorplanning不是“加快編譯”的通用解它的主要價(jià)值在于優(yōu)化時(shí)序和減少擁塞。如果你為了強(qiáng)制固定某個(gè)模塊的位置反而把模塊放得太分散或者太集中可能導(dǎo)致布線擁塞加劇編譯時(shí)間不降反升。所以在做Floorplanning之前先看布局后的熱力圖確認(rèn)哪里有擁塞再有針對性地調(diào)整區(qū)域。沒有擁塞問題的工程跑Floorplanning純屬畫蛇添足。6. 多線程、多機(jī)器協(xié)同與DFX模塊化6.1 多線程參數(shù)的正確設(shè)置姿勢Vivado從2017.1版本開始支持多線程并行編譯官方說明是在Linux系統(tǒng)下效果更明顯。這個(gè)功能本質(zhì)是讓綜合、布局和布線算法在多個(gè)CPU核上并行執(zhí)行從而縮短墻鐘時(shí)間。但并不是線程數(shù)越多越好-jobs 8并不意味著比-jobs 4快兩倍。由于算法內(nèi)部存在依賴關(guān)系真正能并行執(zhí)行的部分有限線程開太多反而會(huì)因?yàn)榫€程調(diào)度開銷而拖慢速度。我做了實(shí)際對比測試同一個(gè)工程在8核和16核CPU上跑-jobs 8差不多是-jobs 4的1.6倍速度提升-jobs 16比-jobs 8提升不到10%。所以建議設(shè)置在8到12之間即可太高沒意義還占滿機(jī)器資源導(dǎo)致你連看日志都卡。另外還要注意Vivado的版本差異。舊版本在-jobs和-max_threads之間有一些細(xì)微差別新版本通過launch_runs -jobs N統(tǒng)一管理。Tcl里可以這樣設(shè)置默認(rèn)線程數(shù)set_param general.maxThreads 8這個(gè)設(shè)置對所有階段全局生效。如果你用GUI方式啟動(dòng)綜合可以在Project Settings里設(shè)置Number of jobs效果相同。6.2 多機(jī)器并行編譯的實(shí)操方案如果單機(jī)性能確實(shí)有限另一個(gè)思路是把不同部分的綜合分散到多臺(tái)機(jī)器上跑。Vivado支持分布式綜合Distributed Synthesis主要針對IP核的OOC綜合。這種方式把多個(gè)IP核的綜合任務(wù)分發(fā)給多臺(tái)機(jī)器并行執(zhí)行全部完成后收集結(jié)果。前提是網(wǎng)絡(luò)環(huán)境穩(wěn)定、共享存儲(chǔ)可用、各機(jī)器上的Vivado版本一致并且License支持多機(jī)并行。這個(gè)操作在日常開發(fā)中比較繁瑣需要配置xsim資源池和SSH免密登錄。如果項(xiàng)目周期緊、單機(jī)實(shí)在扛不住可以考慮。但如果只是平時(shí)的小迭代沒必要上這個(gè)方案。還有一個(gè)更輕量的思路用remote_host配置把綜合和實(shí)現(xiàn)放到專門的編譯服務(wù)器上跑本地只做編輯和查看報(bào)告。這個(gè)做法對個(gè)人體驗(yàn)的提升非常明顯編譯占用的是遠(yuǎn)端資源本地電腦不卡。特別是家里和辦公室分開工作的時(shí)候遠(yuǎn)端編譯配合腳本自動(dòng)運(yùn)行隨時(shí)隨地看結(jié)果體驗(yàn)非常好。6.3 DFX模塊化設(shè)計(jì)大工程提速的終極答案如果項(xiàng)目結(jié)構(gòu)允許還有一招從根本上改變編譯模式DFX即Dynamic Function eXchange動(dòng)態(tài)功能切換。DFX允許你將工程劃分為靜態(tài)區(qū)域和動(dòng)態(tài)區(qū)域每次修改只針對其中一個(gè)動(dòng)態(tài)區(qū)域進(jìn)行編譯靜態(tài)區(qū)域使用上一次編譯的結(jié)果不需要重新跑一遍布局布線。這相當(dāng)于把一個(gè)大工程的編譯任務(wù)拆成了一個(gè)個(gè)小模塊的編譯效果顯著。我做過一個(gè)帶DFX的項(xiàng)目帶三個(gè)動(dòng)態(tài)功能模塊每個(gè)模塊的資源量約2萬LUT。在沒有DFX的時(shí)候整體編譯一次是7小時(shí)使用DFX之后修改單個(gè)模塊重新編譯只需要1.5小時(shí)左右。原因是每次編譯實(shí)際只需要重新布局布線動(dòng)態(tài)區(qū)域靜態(tài)區(qū)域保持不變工具直接復(fù)用之前的結(jié)果。這幾個(gè)小時(shí)的時(shí)間差距在項(xiàng)目后期幾乎決定了你能不能在一天內(nèi)跑完所有驗(yàn)證場景。DFX在Vivado中需要單獨(dú)創(chuàng)建PR工程設(shè)置pblock約束并運(yùn)行PR_Verify檢查。操作路徑稍微復(fù)雜一些網(wǎng)上教程也不多但掌握了之后收益巨大。從個(gè)人經(jīng)驗(yàn)講如果工程規(guī)模在20萬LUT以上并且有比較明確的可動(dòng)態(tài)切換的功能模塊DFX值得花一周時(shí)間研究落地。7. 時(shí)序約束與網(wǎng)表優(yōu)化層面的提速7.1 時(shí)序收斂的迭代過程如何縮短編譯時(shí)間長的另一個(gè)隱性原因是時(shí)序不收斂工具反復(fù)做優(yōu)化迭代每次迭代都重新布局布線。這種情況治標(biāo)更重要。先把所有約束清理干凈把不是必須的虛假路徑、多周期路徑全部定義正確再談加速。約束寫得不全、寫錯(cuò)工具就只能靠猜測來優(yōu)化當(dāng)然會(huì)消耗大量時(shí)間。我在一個(gè)項(xiàng)目中遇到過某條跨時(shí)鐘域的路徑?jīng)]有設(shè)置set_clock_groups約束工具默認(rèn)按同步路徑做時(shí)序收斂反復(fù)調(diào)整寄存器位置和布線連跑了三輪都沒有收斂。后來加上異步時(shí)鐘組約束后一次布線就過了時(shí)間直接少了一半。這件事讓我徹底明白編譯優(yōu)化不是純靠工具參數(shù)約束質(zhì)量才是省時(shí)間的最強(qiáng)杠桿。另外set_false_path不是隨便用的。有些人為了快速收斂把一堆路徑設(shè)成FALSE時(shí)序報(bào)告是變好看了但上板跑起來功能就出錯(cuò)。正確的做法是先識(shí)別哪些路徑在功能上確實(shí)不需要時(shí)序檢查比如測試邏輯、配置寄存器鏈這類再設(shè)置約束。這里需要豐厚的硬件設(shè)計(jì)經(jīng)驗(yàn)來支撐不能為了省時(shí)間犧牲正確性。7.2 網(wǎng)表優(yōu)化等級對編譯時(shí)間的影響Vivado的布局布線階段還有一個(gè)隱藏選項(xiàng)phys_opt_design的優(yōu)化等級。默認(rèn)情況下工具在布線后會(huì)有一次物理優(yōu)化嘗試調(diào)整寄存器位置、邏輯復(fù)制等手段改善時(shí)序。這個(gè)優(yōu)化本身也很耗時(shí)但在某些工程里效果并不大。我測試過幾種方案。一種是不再額外跑物理優(yōu)化只依賴布局器自身的優(yōu)化另一種是在布線前跑一輪物理優(yōu)化布線后不再跑。兩種方式理論上可能犧牲少量時(shí)序性能但對于本來就有時(shí)序余量的工程來說完全是可行的能節(jié)省約20到30分鐘。如果工程時(shí)序本來就很緊不建議去掉這個(gè)步驟否則后續(xù)反復(fù)修時(shí)序的時(shí)間會(huì)遠(yuǎn)遠(yuǎn)超過省下的編譯時(shí)間。此外還可以在實(shí)現(xiàn)流程里加上-directive Quick來快速評估一版結(jié)果看能否滿足約束要求。這種方式相當(dāng)于跑一個(gè)低精度的快速預(yù)演跑完之后能知道大致的時(shí)序狀態(tài)。如果預(yù)演結(jié)果已經(jīng)滿足再跑全量精修如果預(yù)演就崩了那么全量精修大概率也崩可以提前改設(shè)計(jì)避免浪費(fèi)時(shí)間。8. 常見問題排查實(shí)錄與最終效果總結(jié)8.1 增量編譯不生效這類典型問題怎么查增量編譯不生效算是非常高頻的問題了。我當(dāng)時(shí)自己就踩過一次。代碼只改了某個(gè)模塊內(nèi)部理論上增量綜合應(yīng)該在幾分鐘內(nèi)完成但實(shí)際跑了一個(gè)半小時(shí)和全量綜合差不多。打開日志一看發(fā)現(xiàn)提示有部分頂層接口發(fā)生了改變增量綜合條件不滿足。導(dǎo)致這個(gè)問題的原因很多頂層的端口順序調(diào)整了、IP核參數(shù)變了、全局屬性文件更新了都會(huì)導(dǎo)致增量檢查失敗。排查辦法是在綜合前打開綜合日志搜索“Incremental”相關(guān)的提示信息。如果看到“reference checkpoint cannot be used”或類似字眼那就說明增量編譯這次沒生效別傻等直接停掉改全量。另外工程文件放在不同路徑下也可能導(dǎo)致incremental_checkpoint路徑失效需要確保路徑一致。還有一個(gè)坑就是增量編譯后資源利用率報(bào)告和之前的差別大得離譜。這大概率是某個(gè)宏定義或者參數(shù)被改動(dòng)了導(dǎo)致綜合后邏輯結(jié)構(gòu)完全變了。遇到這種情況別糾結(jié)直接重新全量綜合作為新的基線再開啟下一輪增量。8.2 換了機(jī)器之后編譯時(shí)間反而變長團(tuán)隊(duì)開發(fā)中經(jīng)常遇到這個(gè)問題。在服務(wù)器上編譯用6小時(shí)在本地工作站上編譯要10小時(shí)。排除機(jī)器性能差異之后最常見的兩個(gè)原因是本地運(yùn)行的Vivado版本不一致導(dǎo)致同一份工程代碼綜合策略有所變化另一個(gè)是本地沒有配置好-jobs參數(shù)默認(rèn)用了單線程。另外一個(gè)容易被忽略的因素是殺毒軟件。Windows環(huán)境下殺毒軟件會(huì)實(shí)時(shí)掃描工程目錄下大量不斷生成的小文件拖慢I/O。在Vivado編譯期間把工程目錄添加為掃描排除項(xiàng)或者干脆把所有編譯任務(wù)放到Linux服務(wù)器上跑性能會(huì)好很多。我自己在Windows上跑編譯時(shí)把整個(gè)工程目錄和Vivado安裝目錄都加入了白名單編譯耗時(shí)縮小了15%左右非常可觀。8.3 最終提速效果從13小時(shí)到5小時(shí)是怎么湊出來的最后匯總一下這次的優(yōu)化結(jié)果。全量綜合從1.5小時(shí)降到0.9小時(shí)主要是調(diào)整了綜合策略和增量編譯。布局從2小時(shí)降到1.5小時(shí)主要?dú)w功于Floorplanning的加入某些模塊提前固定了大致區(qū)域布局器的搜索空間變小。布線從4.5小時(shí)降到1.8小時(shí)主要是切換到Performance_Explore策略結(jié)合物理優(yōu)化裁剪。時(shí)序優(yōu)化流程從2.5小時(shí)降到0.5小時(shí)核心原因是約束清理避免了很多不必要的調(diào)整迭代。比特流生成那半小時(shí)幾乎沒法再壓縮保持原樣。加起來總時(shí)間從13小時(shí)壓到了5小時(shí)出頭。這里面每個(gè)步驟單獨(dú)來看都不是天翻地覆的變化但逐項(xiàng)疊加之后效果就非常明顯。整個(gè)過程最核心的收獲是優(yōu)化之前先測量不要憑感覺去猜測瓶頸。你可以不知道Vivado內(nèi)部的每一個(gè)算法細(xì)節(jié)但一定要知道自己的時(shí)間花在了哪里然后針對性地去調(diào)整工具設(shè)置和工程結(jié)構(gòu)。如果你也正被FPGA編譯時(shí)間折磨建議按這個(gè)順序來先看報(bào)告確定耗時(shí)分布然后清理時(shí)序約束再調(diào)整策略參數(shù)最后考慮DFX或者多機(jī)協(xié)同這種工程級的改動(dòng)。把編譯時(shí)間省下來之后你才有更多時(shí)間去做真正的設(shè)計(jì)迭代而不是把光陰耗在等進(jìn)度條上。