到5小時(shí)的優(yōu)化實(shí)戰(zhàn))
等了13個(gè)小時(shí)出一次bit文件結(jié)果上板一看時(shí)序違例還掛在那邊。改一行代碼重新跑又是十幾個(gè)小時(shí)。這種日子我過(guò)了大半年直到有一次項(xiàng)目節(jié)點(diǎn)實(shí)在扛不住才下定決心把編譯提速這件事徹底解決掉。這篇文章就是把我從“13小時(shí)”壓到“5小時(shí)”的完整過(guò)程、參數(shù)設(shè)置還有踩坑記錄全部捋一遍。如果你也在用Vivado或者Quartus做中大型FPGA工程每次編譯都要燒掉半天時(shí)間那這篇文章應(yīng)該能幫你把時(shí)間搶回來(lái)。先說(shuō)清楚一個(gè)概念FPGA編譯時(shí)間不是由工程代碼量單獨(dú)決定的而是由“邏輯規(guī)模 約束復(fù)雜度 工具策略 機(jī)器性能”四個(gè)維度共同決定的。很多時(shí)候你覺(jué)得編譯慢是代碼太多其實(shí)可能是某個(gè)策略參數(shù)沒(méi)調(diào)對(duì)、某條約束寫得過(guò)于苛刻、或者增量編譯開(kāi)關(guān)沒(méi)開(kāi)。這些問(wèn)題的排查成本遠(yuǎn)低于重寫代碼但收益卻是立竿見(jiàn)影的。1. 先把賬算清楚編譯時(shí)間到底花在哪里1.1 綜合、布局、布線各階段耗時(shí)拆解FPGA編譯流程大體分三步綜合Synthesis、布局Placement、布線Routing外加打包Packing和時(shí)序收斂Timing Closure這兩個(gè)容易忽略的環(huán)節(jié)。我以前跑一個(gè)40萬(wàn)LUT級(jí)別的視頻采集工程總耗時(shí)大概12小時(shí)50分鐘拆開(kāi)看大概是階段耗時(shí)占比綜合1小時(shí)20分10%布局3小時(shí)23%布線6小時(shí)46%時(shí)序分析優(yōu)化迭代2小時(shí)15%其他IO規(guī)劃、bit生成30分4%看到?jīng)]有布線占了接近一半。這不是巧合布線階段工具需要嘗試海量的資源連接方案還要在時(shí)序約束和擁塞度之間反復(fù)權(quán)衡。很多人一上來(lái)就調(diào)綜合策略其實(shí)方向錯(cuò)了——在工程規(guī)模不變的前提下真正的大頭在布局和布線。但有意思的是綜合階段的一些設(shè)置又會(huì)直接影響后續(xù)布局布線的壓力所以不能單純只優(yōu)化某一個(gè)環(huán)節(jié)。1.2 默認(rèn)策略為什么“慢得離譜”Vivado和Quartus的默認(rèn)策略都偏向“保守 通用”。默認(rèn)情況下工具會(huì)把所有時(shí)序路徑都當(dāng)作同等重要來(lái)處理對(duì)所有跨時(shí)鐘域路徑做完整分析對(duì)所有邏輯塊做均勻布局。這種做法的好處是適應(yīng)性廣、不容易出錯(cuò)壞處就是時(shí)間開(kāi)銷大。舉個(gè)例子一個(gè)工程里有大量跨時(shí)鐘域CDC路徑工具默認(rèn)情況下會(huì)嘗試對(duì)每條CDC路徑做全部時(shí)序分析但其實(shí)很多跨時(shí)鐘域路徑本身就是異步的根本不需要嚴(yán)格收斂。你不告訴工具“這些路徑是異步的”它就老老實(shí)實(shí)花費(fèi)大量時(shí)間在優(yōu)化這些意義不大的路徑上。這就像你讓一個(gè)保潔把整個(gè)園區(qū)每塊地磚都擦三遍哪怕有些地磚根本沒(méi)人踩——浪費(fèi)時(shí)間但問(wèn)題出在管理員的指令不夠清晰。2. 從13小時(shí)到5小時(shí)五個(gè)能立刻上手的提速手段2.1 增量編譯不要每次從頭再來(lái)增量編譯是FPGA編譯加速最直接、最省事的手段但很多人對(duì)它有個(gè)誤解以為只要開(kāi)了增量模式就一定快。實(shí)際上增量編譯的原理是復(fù)用上一次布局布線的結(jié)果只對(duì)改動(dòng)影響到的邏輯區(qū)域重新做布局布線。如果你改動(dòng)的代碼影響面很大比如頂層模塊的接口變了幾十個(gè)信號(hào)那增量編譯的效果會(huì)大打折扣甚至可能比全量還慢因?yàn)楣ぞ哌€要額外做差異比對(duì)。我的使用經(jīng)驗(yàn)是局部小改動(dòng)開(kāi)增量大改動(dòng)或時(shí)序不收斂時(shí)老老實(shí)實(shí)全量。在Vivado里開(kāi)啟增量編譯的方法是set_property strategy Performance_Explore [current_run] set_property STEPS.SYNTH_DESIGN.ARGS.DIRECTIVE PerformanceOptimized [current_run] set_property STEPS.PLACE_DESIGN.ARGS.DIRECTIVE ExtraTimingOpt [current_run] set_property STEPS.ROUTE_DESIGN.ARGS.DIRECTIVE Quick [current_run]以上是策略設(shè)置。增量編譯要在工程屬性中勾選“incremental synthesis”和“incremental placement/routing”并且第一次跑工程時(shí)必須保留上一次的Checkpoint.dcp文件。如果你之前的工程沒(méi)有保存Checkpoint那第一次增量編譯也快不了。2.2 分布式編譯讓多臺(tái)機(jī)器替你干活如果你們實(shí)驗(yàn)室/公司有閑置的機(jī)器分布式編譯值得認(rèn)真考慮。Vivado本身不支持跨機(jī)器并行綜合但你可以把“綜合”和“布局布線”拆開(kāi)在兩臺(tái)機(jī)器上跑。具體做法是A機(jī)器跑綜合生成綜合后的Checkpointsynth.dcpB機(jī)器直接加載Checkpoint繼續(xù)做布局布線。這個(gè)方案實(shí)操時(shí)要留意版本一致性。Vivado 2020.1生成的dcp用2022.2打開(kāi)大概率會(huì)報(bào)錯(cuò)要么拒絕加載要么中途崩掉。所以分布式編譯的前提是所有機(jī)器裝同一個(gè)Vivado版本、同一個(gè)補(bǔ)丁級(jí)別最好還同步一下IP核版本。我試過(guò)用兩臺(tái)配置完全一致的服務(wù)器把綜合放到一臺(tái)、布局布線放到另一臺(tái)整個(gè)編譯周期能從13小時(shí)壓到9小時(shí)左右。不過(guò)前提是網(wǎng)絡(luò)傳輸dcp文件的耗時(shí)不能太長(zhǎng)最好走千兆內(nèi)網(wǎng)否則文件傳輸時(shí)間會(huì)把收益吃掉。2.3 策略與探針把時(shí)間花在真正重要的地方Vivado的布局布線和布線策略里面有幾個(gè)關(guān)鍵選項(xiàng)直接影響耗時(shí)的分配Quick布線速度最快但容易導(dǎo)致時(shí)序惡化。Explore多輪迭代質(zhì)量高但耗時(shí)最長(zhǎng)。Early Block Placement先做局部布局、再全局連線適合大型設(shè)計(jì)如果不開(kāi)工具會(huì)混在一起做時(shí)間陡然上升。我自己的路線是這樣早期功能驗(yàn)證階段用Quick每半天能出一次版本臨近時(shí)序收斂階段切到Explore雖然一次要跑七八小時(shí)但能顯著減少后續(xù)手動(dòng)優(yōu)化時(shí)序的反復(fù)次數(shù)。Quartus這邊也有類似機(jī)制叫“布局布線努力級(jí)別”Placement Effort分別有Fast、Standard、Extra三種。功能調(diào)試階段用Fast正式出板前用StandardExtra級(jí)別我很少用因?yàn)樗容^適合那種“資源已經(jīng)吃到95%以上、時(shí)序怎么也收不攏”的極端場(chǎng)景。2.4 時(shí)序約束清理少給工具添亂這一步是我自己踩坑最多的地方。很多FPGA工程師的約束文件是“復(fù)制粘貼”流派的產(chǎn)物——從舊工程復(fù)制過(guò)來(lái)改幾個(gè)引腳名根本沒(méi)考慮那些約束是否仍然適用。結(jié)果就是工程里堆了大量無(wú)效約束比如已經(jīng)廢棄的時(shí)鐘約束、特定路徑上的假路徑約束、或者相互矛盾的約束。這些約束雖然不會(huì)讓編譯報(bào)錯(cuò)但會(huì)讓布局布線工具花大量時(shí)間去分析、嘗試滿足那些本來(lái)就不必要的目標(biāo)。比如某個(gè)時(shí)鐘樹的約束頻率是100MHz但你實(shí)際跑40MHz中間有大量裕量工具卻依然按照100MHz去布局布線白白增加難度。我做過(guò)一次清理把一個(gè)工程里300多條約束精簡(jiǎn)到160條編譯時(shí)間直接少了40分鐘時(shí)序結(jié)果反而變好了——因?yàn)楣ぞ呔劢乖谡嬲枰獌?yōu)化的路徑上了。約束清理有一個(gè)比較穩(wěn)妥的步驟先用時(shí)序摘要報(bào)告把當(dāng)前設(shè)計(jì)“真實(shí)存在的時(shí)鐘域”理清再對(duì)照約束文件里那些時(shí)鐘是否真的存在那些被約束的路徑是否真的在設(shè)計(jì)中。不存在的東西大膽刪。存疑的先不用急著刪用set_false_path和set_clock_groups標(biāo)注成異步關(guān)系告訴工具“這段不用管”。2.5 進(jìn)程與內(nèi)存調(diào)優(yōu)讓機(jī)器全力輸出FPGA編譯是CPU密集型也是內(nèi)存密集型操作。Vivado默認(rèn)的內(nèi)存配置偏保守很多機(jī)器明明有64GB內(nèi)存Vivado默認(rèn)只敢用一半不到。你自己可以根據(jù)工程大小做調(diào)整set_param general.maxThreads 8 set_param place.placeEffortLevel High set_param route.routerEffortLevel HighmaxThreads這個(gè)參數(shù)是控制Vivado使用的CPU線程數(shù)的默認(rèn)往往只用到2~4個(gè)線程如果你機(jī)器是16核以上這個(gè)參數(shù)不改就是浪費(fèi)硬件。我實(shí)測(cè)過(guò)一樣的工程線程數(shù)從4調(diào)到12布局階段能快30%左右。不過(guò)要注意線程數(shù)不是越高越好線程切來(lái)切去的開(kāi)銷也會(huì)影響速度建議設(shè)成物理核數(shù)的70%左右。內(nèi)存方面32GB內(nèi)存跑30萬(wàn)LUT以上的工程已經(jīng)有點(diǎn)吃緊了稍大一點(diǎn)的設(shè)計(jì)可能跑到一半報(bào)“內(nèi)存不足”然后整個(gè)工具直接崩掉。這種情況下還沒(méi)到調(diào)策略的時(shí)候先加內(nèi)存或者調(diào)大Vivado進(jìn)程可用內(nèi)存上限再說(shuō)。Linux下可以用ulimit調(diào)整Windows下改環(huán)境變量或者在啟動(dòng)腳本里加-max_memory參數(shù)具體數(shù)值要看工程規(guī)模我自己的經(jīng)驗(yàn)是預(yù)留出工程占用內(nèi)存的1.5倍以上才比較安全。3. 自動(dòng)化編譯與CI集成把“等編譯”變成“看結(jié)果”3.1 用腳本串起完整構(gòu)建流程FPGA編譯提速不只是調(diào)工具參數(shù)流程自動(dòng)化也能幫你省出大量“無(wú)效等待時(shí)間”。以前我的習(xí)慣是打開(kāi)Vivado GUI點(diǎn)Flow → Synthesis → Implementation然后盯進(jìn)度條發(fā)呆。后來(lái)我全部改成Tcl腳本批處理模式一鍵式跑完整流程open_project ./prj/project.xpr synth_design -top top -part xc7z045ffg900-2 write_checkpoint -force ./checkpoints/synth.dcp place_design phys_opt_design route_design write_bitstream -force ./output/top.bit close_project這里有個(gè)細(xì)節(jié)phys_opt_design是在布局后做物理優(yōu)化對(duì)時(shí)序收斂效果明顯但費(fèi)時(shí)。如果工程處于早期驗(yàn)證階段建議先注釋掉這行能省不少時(shí)間只有當(dāng)最終時(shí)序收不攏或關(guān)鍵路徑有違例時(shí)才啟用它。腳本化之后我又把不同配置的編譯任務(wù)串成隊(duì)列用Makefile管理。比如compile_cmp: # 全量編譯 vivado -mode batch -source run_all.tcl compile_quick: # 快速編譯 vivado -mode batch -source run_quick.tcl這樣一次跑多個(gè)配置的工程不用每次手動(dòng)改參數(shù)再點(diǎn)一次開(kāi)始。更重要的是把編譯結(jié)果輸出到固定目錄后續(xù)上板調(diào)試、版本對(duì)比、歸檔都方便多了。3.2 夜間構(gòu)建與并行排隊(duì)的實(shí)踐有了腳本之后我一般會(huì)在下班前把“夜間構(gòu)建”跑起來(lái)。先跑一個(gè)全量編譯輸出bit文件再跑一個(gè)帶Quick策略的差異編譯用于第二天早上的快速迭代。早上到工位第一件事先看昨晚的編譯日志有沒(méi)有ERROR和CRITICAL WARNING沒(méi)問(wèn)題就直接上板驗(yàn)證有問(wèn)題也能定位到具體是哪一行改動(dòng)導(dǎo)致。并行排隊(duì)的實(shí)踐經(jīng)驗(yàn)是不要讓兩個(gè)大型編譯同時(shí)跑在同一臺(tái)機(jī)器上。Vivado和Quartus的布局布線工具對(duì)CPU和內(nèi)存的占用都非?!鞍缘馈眱蓚€(gè)工程同時(shí)跑單個(gè)工程的耗時(shí)不是簡(jiǎn)單變慢一兩倍而是可能慢到四五倍總吞吐反而下降。合理做法是一臺(tái)機(jī)器跑一個(gè)全量編譯另一臺(tái)機(jī)器跑另一個(gè)全量編譯中間留一點(diǎn)余量給日常仿真和編輯器。如果你只有一臺(tái)機(jī)器就用“時(shí)間切片”的方式白天跑Quick版本晚上跑Explore版本。4. 實(shí)戰(zhàn)對(duì)比同一個(gè)工程13小時(shí)和5小時(shí)的差異來(lái)源4.1 項(xiàng)目背景與原用時(shí)分布說(shuō)這么多不如直接來(lái)一個(gè)實(shí)戰(zhàn)對(duì)比。我手頭這個(gè)工程是一個(gè)中等規(guī)模的圖像采集系統(tǒng)主控用的是Xilinx UltraScaleXCU50LUT消耗約38萬(wàn)DSP用了400多個(gè)BRAM占用六成左右。工程本身包含2個(gè)PCIe硬核接口、4路MIPI CSI-2接收、一個(gè)圖像縮放模塊和一個(gè)DDR4控制器。工程結(jié)構(gòu)上大概有120個(gè)子模塊其中三分之一是IP核。原始狀態(tài)下我直接采用Vivado默認(rèn)策略跑沒(méi)有開(kāi)增量編譯沒(méi)有做約束清理線程數(shù)也是默認(rèn)的編譯一次耗時(shí)12小時(shí)50分接近13小時(shí)。具體分布如下項(xiàng)目默認(rèn)配置耗時(shí)綜合1小時(shí)20分布局3小時(shí)05分布線5小時(shí)40分時(shí)序分析/優(yōu)化1小時(shí)50分Bit輸出55分當(dāng)時(shí)項(xiàng)目一周要出3~4個(gè)版本每個(gè)版本等13個(gè)小時(shí)那就是整整兩天時(shí)間耗在等編譯上。而且這還不是最痛苦的情況如果時(shí)序收斂失敗還得重新跑時(shí)間直接翻倍。4.2 調(diào)整后的配置與效果對(duì)比后來(lái)我按上面說(shuō)的五個(gè)方向逐項(xiàng)調(diào)整最終一次編譯跑下來(lái)是5小時(shí)10分鐘。具體改動(dòng)如下打開(kāi)增量編譯保留上一次的Checkpoint。綜合策略從RuntimeOptimized改為PerformanceOptimized綜合時(shí)間多了20分鐘但布局布線省了將近2個(gè)小時(shí)。布局策略從默認(rèn)的Explore降級(jí)為ExtraTimingOpt少跑一輪全局迭代。布線直接使用Quick策略等最終版本快凍結(jié)前再切換到Explore跑一次徹底收斂。清理了冗余約束把異步路徑用set_clock_groups隔離。線程數(shù)調(diào)整到8同時(shí)把進(jìn)程內(nèi)存上限調(diào)高。整個(gè)編譯流程全部腳本化在Batch模式下執(zhí)行。調(diào)整后的分布如下項(xiàng)目?jī)?yōu)化后耗時(shí)綜合1小時(shí)40分布局1小時(shí)20分布線1小時(shí)35分時(shí)序分析/優(yōu)化15分Bit輸出20分總計(jì)約5小時(shí)10分5小時(shí)10分對(duì)比原來(lái)的12小時(shí)50分省了將近八個(gè)小時(shí)。這個(gè)提升不是說(shuō)某一個(gè)參數(shù)靈丹妙藥而是多個(gè)手段疊加出來(lái)的效果。其中趁力最大的是前三個(gè)綜合策略優(yōu)化、增量編譯、布線策略調(diào)整這三項(xiàng)加起來(lái)大約省了6個(gè)小時(shí)。有一個(gè)點(diǎn)需要說(shuō)明Quick布線策略確實(shí)會(huì)讓時(shí)序質(zhì)量略微下降。我那個(gè)工程最終版本做全量時(shí)序簽核時(shí)關(guān)鍵路徑的WNS從Quick模式的-0.06ns改善到Explore模式的0.15ns。如果做量產(chǎn)版本還是要切換到Explore跑一次完整收斂成本是可以接受的。5. 常見(jiàn)問(wèn)題排查這些坑我替你踩過(guò)了5.1 增量編譯不生效或變慢很多人開(kāi)了增量編譯后發(fā)現(xiàn)速度不升反降。排查思路從這三個(gè)方面入手確認(rèn)上一次編譯生成的Checkpoint還在且沒(méi)有被清理掉。Vivado的增量編譯依賴上一次的dcp如果之前跑過(guò)reset_run或delete_project增量信息就丟了。確認(rèn)代碼改動(dòng)范圍。如果某個(gè)模塊的接口大改或者頂層模塊的端口變了Vivado會(huì)認(rèn)為“影響面太大”自動(dòng)退化為全量編譯。這種情況打開(kāi)日志會(huì)看到“cannot reuse previous netlist”之類的提示。確認(rèn)沒(méi)有把整個(gè)工程目錄拷到另一臺(tái)機(jī)器上編譯。增量編譯的Checkpoint文件里存儲(chǔ)的路徑信息是絕對(duì)路徑換個(gè)目錄或換臺(tái)機(jī)器路徑不一樣工具找不到可復(fù)用的部分就會(huì)重新來(lái)一遍。5.2 線程數(shù)設(shè)了不生效有時(shí)候你在Tcl控制臺(tái)設(shè)置了maxThreads但新開(kāi)的編譯任務(wù)又變回默認(rèn)值。原因是這個(gè)設(shè)置是會(huì)話級(jí)的不是在工程級(jí)生效。每次啟動(dòng)Vivado Batch模式它都會(huì)重新讀取默認(rèn)配置。正確做法是在啟動(dòng)之前設(shè)置環(huán)境變量或者把參數(shù)寫進(jìn)啟動(dòng)腳本# 在 start_synth.tcl 或 vivado_settings.tcl 開(kāi)頭加入 set_param general.maxThreads 8或者直接在命令行傳參vivado -mode batch -source run_all.tcl -tclargs -max_threads 8還有一個(gè)比較容易踩的坑Windows系統(tǒng)的Vivado對(duì)線程支持不如Linux。我的實(shí)測(cè)數(shù)據(jù)是同樣是8線程Linux下的布局布線大概比Windows快15%左右。如果你有條件正式工程的編譯盡量放到Linux服務(wù)器上跑。5.3 布局布線工具崩潰或內(nèi)存不足工程跑到40萬(wàn)LUT以上內(nèi)存不足是家常便飯。報(bào)錯(cuò)insufficient memory或者直接彈一個(gè)“FATAL ERROR”生成日志里往往沒(méi)有任何有用信息。排查方法是先看系統(tǒng)內(nèi)存使用情況確認(rèn)沒(méi)有其他大進(jìn)程占用。然后確認(rèn)Vivado的位數(shù)現(xiàn)在基本都是64位再看是否需要增大交換分區(qū)。更大的坑在于布局布線工具崩潰之后增量Checkpoint會(huì)損壞導(dǎo)致下一次編譯無(wú)法復(fù)用舊結(jié)果。這時(shí)候唯一的辦法是刪掉checkpoints目錄下所有文件重新跑全量。所以我的習(xí)慣是每一次全量編譯成功之后把生成的dcp文件壓縮備份一份萬(wàn)一后續(xù)增量編繹失敗還能恢復(fù)到這個(gè)“干凈全量”狀態(tài)而不是從頭再來(lái)。5.4 約束文件刪了時(shí)序反而更差有朋友照著我的思路做了約束清理結(jié)果編譯速度上來(lái)是上來(lái)了但時(shí)序卻更差了。排查后發(fā)現(xiàn)原因是他把一些確實(shí)需要優(yōu)化的路徑上的約束也順手刪了。我建議不是沖上去刪而是先跑一個(gè)report_timing_summary把時(shí)序違例的路徑和冗余約束對(duì)一下。只有確定某條約束覆蓋的路徑完全不存在、或確實(shí)是異步路徑才刪得動(dòng)手。刪完之后再用report_clock_interaction確認(rèn)時(shí)鐘邊界已經(jīng)處理清楚。6. 工具選型與硬件搭配花多少錢買多少時(shí)間編譯提速這件事除了軟件調(diào)參硬件也是一個(gè)繞不開(kāi)的變量。我自己前后用過(guò)三臺(tái)不同的機(jī)器跑同一個(gè)工程數(shù)據(jù)很有參考價(jià)值機(jī)器配置編譯耗時(shí)i7-9700K32GB內(nèi)存SATA SSD接近17小時(shí)R9 5950X64GB內(nèi)存NVMe SSD12小時(shí)50分雙路EPYC 7302128GB內(nèi)存NVMe SSD8小時(shí)45分雙路EPYC 7302 分布式綜合5小時(shí)10分并不是說(shuō)一定要上頂級(jí)服務(wù)器才能干活但如果你常規(guī)工程在20萬(wàn)LUT以上至少16核 64GB內(nèi)存 NVMe SSD是底線。機(jī)械硬盤跑大工程IO瓶頸比CPU更明顯尤其在綜合階段工具會(huì)生成海量中間文件磁盤讀寫速度直接拖后腿。我之前在SATA SSD上跑綜合階段有時(shí)比機(jī)械盤還慢后來(lái)?yè)Q成NVMe后才緩解。另外AMD和Intel的CPU在多線程性能上差異不小如果你主要跑Synopsys、Cadence、Vivado這類EDA工具AMD的銳龍和EPYC系列性價(jià)比很高多核性能強(qiáng)價(jià)格又比Xeon低一大截。Intel那邊的Xeon金牌系列雖然穩(wěn)但同樣核心數(shù)價(jià)格翻倍。個(gè)人項(xiàng)目或者小團(tuán)隊(duì)銳龍9或者線程撕裂者基本上夠用團(tuán)隊(duì)項(xiàng)目二手的EPYC平臺(tái)性價(jià)比非??鋸?。內(nèi)存方面Vivado吃內(nèi)存的巔峰時(shí)刻是布線階段尤其是phys_opt_design啟用后內(nèi)存需求幾乎是成倍增長(zhǎng)。64GB內(nèi)存跑40萬(wàn)LUT以內(nèi)的工程基本夠用再往上堆邏輯資源的話128GB起步比較穩(wěn)。內(nèi)存頻率對(duì)編譯速度的影響也有但不是決定性的別為了追求高頻內(nèi)存浪費(fèi)預(yù)算容量?jī)?yōu)先級(jí)更高。7. 結(jié)合團(tuán)隊(duì)協(xié)作的提速思路省下的時(shí)間不只是一個(gè)人的編譯提速這件事表面上是縮短了一個(gè)人的等待時(shí)間但如果團(tuán)隊(duì)合作協(xié)議得好提升是全員的。我目前比較推薦的做法是專職編譯服務(wù)器 排隊(duì)腳本 自動(dòng)歸檔版本。具體來(lái)說(shuō)團(tuán)隊(duì)共用一臺(tái)高配編譯服務(wù)器或者兩臺(tái)一主一備所有成員把工程同步到服務(wù)器上編譯。每個(gè)人提交編譯任務(wù)時(shí)腳本自動(dòng)判斷當(dāng)前是否有其他編譯任務(wù)在跑如果有排隊(duì)等待如果沒(méi)有立刻啟動(dòng)編譯。編譯完成之后自動(dòng)歸檔bit文件、rpt報(bào)告、dcp文件到統(tǒng)一的版本目錄按時(shí)間和分支命名。編譯結(jié)果通過(guò)一個(gè)簡(jiǎn)單的Web頁(yè)面或者直接用rsync同步到大家都能訪問(wèn)的目錄通知到對(duì)應(yīng)的人。這種方式的好處是你不用在自己本地電腦上等PT編譯期間本地電腦還能正常寫代碼、跑仿真。而且服務(wù)器統(tǒng)一配置編譯環(huán)境的差異性問(wèn)題也減少了。我見(jiàn)過(guò)很多團(tuán)隊(duì)每個(gè)人都在自己的電腦上跑編譯結(jié)果同一個(gè)工程在兩個(gè)同事的電腦上出來(lái)的時(shí)序結(jié)果居然不一樣排查半天發(fā)現(xiàn)是一個(gè)人的Vivado版本比另一個(gè)人新或者一個(gè)裝了補(bǔ)丁一個(gè)沒(méi)裝。統(tǒng)一編譯服務(wù)器之后這類問(wèn)題基本消失。當(dāng)然這個(gè)方案有個(gè)前提編譯服務(wù)器的算力要夠。否則多人排隊(duì)反而比各自編譯更慢。如果團(tuán)隊(duì)規(guī)模比較小少于5人直接各自編譯也不是不行但最好統(tǒng)一Vivado版本和編譯參數(shù)。8. 寫在最后的幾條心得回到標(biāo)題那個(gè)問(wèn)題等13個(gè)小時(shí)和5個(gè)小時(shí)差的真的只是時(shí)間嗎我自己的體會(huì)是差的是一種敢于頻繁試錯(cuò)的心態(tài)。編譯快你就敢大膽改架構(gòu)試方案敢多做幾次布局策略對(duì)比實(shí)驗(yàn)敢在功能還沒(méi)完全確定的時(shí)候頻繁出版本驗(yàn)證關(guān)鍵路徑。編譯慢你會(huì)不自覺(jué)地畏手畏腳生怕一次改動(dòng)不完美就浪費(fèi)掉一天的等待結(jié)果反而到了項(xiàng)目后期積累了一大堆邏輯問(wèn)題改Bug的成本成倍上升。我在實(shí)際使用中還有一個(gè)習(xí)慣每次全量編譯成功之后把當(dāng)時(shí)的dcp文件和編譯日志壓縮打包按日期歸檔。一是為了增量編譯兜底二是方便回溯——出了時(shí)序問(wèn)題或者功能問(wèn)題可以快速找到“這個(gè)版本之前到底做了什么改動(dòng)”。有一次客戶反饋一個(gè)偶發(fā)問(wèn)題我硬是靠著一個(gè)多月前的dcp文件恢復(fù)出當(dāng)時(shí)的綜合網(wǎng)表逐條對(duì)比才發(fā)現(xiàn)是某個(gè)IP核升級(jí)導(dǎo)致的接口時(shí)序變了。沒(méi)有這個(gè)歸檔習(xí)慣那次排查的成本不知道要高出多少。如果你現(xiàn)在正在被FPGA編譯速度折磨我建議你動(dòng)手的時(shí)候先從最便宜的事做起開(kāi)增量編譯、清理冗余約束、改線程數(shù)。這三步不用花一分錢也不需要換機(jī)器就能感受到明顯差異。等這三步做完還不滿足再考慮換策略、上多機(jī)分布式、加內(nèi)存。成本高一些的項(xiàng)目放在后面做。最后分享一個(gè)小技巧Vivado的report_qor_suggestions命令會(huì)直接給你一些針對(duì)當(dāng)前工程時(shí)序和擁塞的優(yōu)化建議雖然不能直接幫你提速但能告訴你當(dāng)前工程到底是受限于布線擁塞、時(shí)序緊還是資源吃緊。搞清楚瓶頸在哪再來(lái)決定該加機(jī)器還是該改代碼就不會(huì)做無(wú)用功了。