ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Vivado多线程提速指南:综合、布局布线、仿真配置与实测

Vivado多线程提速指南:综合、布局布线、仿真配置与实测 我记得第一次看到Vivado在任务管理器里的CPU曲线差点以为程序卡死了。16核的机器综合阶段CPU占用率只有百分之十几进度条却要跑四五十分钟。后来才知道Vivado有多线程能力但默认参数、工程设置、甚至操作系统的CPU调度都会让它老老实实地“单核加班”。这两三年用Xilinx Vivado 2021.2和2022.1做Zynq和Kintex项目我把综合、布局布线、仿真三个阶段的多线程配置都试了一圈这里把具体设置方法、背后的取舍和实测数据整理成文。内容不复杂适合被大型综合、布线和回归仿真耗时的FPGA工程师尤其是综合一次超过二十分钟的工程按这篇文章操作等待时间通常能压到原来的三分之一左右。1. 为什么同一个Vivado别人能跑到8核你只能跑1核1.1 综合阶段的任务划分天然适合多线程但默认值不一定高Vivado综合synth_design的核心工作是RTL展开、布尔化简、工艺映射和逻辑优化。这些步骤里“展开”和“映射”会对成千上万的节点做类似的计算属于天然的粗粒度并行而像时序约束驱动的全局优化则需要把前一步的结果汇总起来再处理属于串行段。Vivado的做法是建立一个线程池把可并行的子任务丢给多个线程执行。问题在于线程池的实际线程数取决于三个地方一是工程设置里Synthesis的Processors选项二是运行时有没有用-threads参数覆盖三是全局参数general.maxThreads的钳制。三者取最小生效值。我见过不少项目工程综合设置的Processors还是默认的1或2而机器明明是8核以上。官方为了让Vivado在普通笔记本和服务器上都能稳定运行默认值往往比较保守。另外很多工程师直接在GUI里点Run Synthesis根本不会注意这次综合用了几个线程。结果就是一台16线程的机器实际只有一个线程在干活等待时间自然特别长。1.2 布局布线的并行全局布局可以并行详细布局和布线却受数据依赖制约place_design的过程先做全局布局把逻辑单元以面积和拥塞为约束摊开这一步很适合多线程之后的详细布局需要逐步调整单个单元位置很多调整决策依赖前一步结果并行度就下降了。route_design更是这样布线器要在全局资源图上给每条线网找路径不同线网之间争抢通道并行线程必须频繁协调。所以布局布线阶段开多线程有效但提升幅度远没有综合阶段那么直观。把4线程提到8线程综合可能还有接近10%的收益布线可能只有1%到3%甚至因为调度开销出现负优化。1.3 仿真阶段编译能并行运行几乎只能靠任务级并行很多人在仿真上碰壁是因为没搞清楚xsim的并行边界。xelab负责把RTL编译并elaborate成可执行仿真快照这个过程可以用-mt参数并行收益很明显但xsim真正执行事件循环的时候当前版本并没有设计成把一个testbench拆到多核上加速或者说收益非常有限。正确的做法是把可并行的部分放在编译和elaboration阶段把回归测试按不同seed拆成多个独立仿真进程同时喂给机器上多个核。这样整体吞吐量才能真正翻倍。2. 动手前先把全局线程参数、CPU亲和性和内存准备好2.1 先改一个全局参数general.maxThreads在Vivado的Tcl Console里执行set_param general.maxThreads 8这个参数控制Vivado内部线程池的上限综合、布局布线、实现和写比特流等步骤都会受它影响。验证是否生效直接执行get_param general.maxThreads如果返回8说明设置成功。需要注意这句话只在当前会话有效建议写进一个tcl脚本或者在Project Settings里把它加为启动钩子否则每次重新开Vivado都要再执行一次。我习惯在工程根目录放一个setup.tcl第一行就是这个然后在Vivado里source一下。2.2 GUI设置Project Settings里那个Processors下拉框不想敲命令的话可以打开Project Settings → Synthesis → Options找到Processors有的版本显示为Number of processors从默认值改成8Implementation设置里同理。这里改的实际上是综合运行和实现运行的属性会在launch_runs时生效。要注意Project Settings里的Processors与全局maxThreads并不是叠加关系。实测下来是取两者的较小值。如果全局maxThreads被限制为4GUI里设8也不会超过4。所以两个地方最好都统一改成目标值避免自己以为设了8实际生效只有4。2.3 用taskset或affinity把Vivado绑到物理核心上Windows下可以通过启动脚本指定CPU亲和性把Vivado只放在物理核心上。一个简单bat脚本是start Vivado /affinity 0x0F C:\Xilinx\Vivado\2021.2\bin\vivado.bat0x0F表示只允许0到3号逻辑CPU适合2核4线程的机器如果是4核8线程的机器可以用0xFF。这样做不是必须但在与其他编译任务共存的电脑上限制亲和性能避免Vivado跑到超线程虚拟核减少缓存争抢。Linux下更推荐直接在终端运行taskset -c 0-7 vivado -mode tcl或者用numactl控制内存分配节点numactl --physcpubind0-7 --localalloc vivado -mode tcl2.4 内存和硬盘也要提前垫底多线程会放大内存消耗。开8线程综合一个几十万门的设计峰值内存比单线程可能多出1.5到2GB如果机器本身只有16GB内存再同时跑几个仿真进程很容易触发swap。一旦swap多线程带来的收益会被磁盘读写完全吞掉。另外Vivado在综合和实现期间会产生大量中间文件放在机械硬盘和放在NVMe SSD上的速度差距有时比线程数还大。所以提速前先把工作目录放到SSD并在任务管理器确认内存不会吃满。这是一个很反常识但成本最低的优化。3. 综合阶段的多线程实操GUI、Tcl和非工程模式三种路径3.1 工程模式下最省事的方式在Project Settings里把Synthesis的Processors改到8后重新运行综合。之前已经综合过一次的话需要右键synth_1 → Reset Runs再Launch Runs否则Vivado觉得没有变化会直接跳过。我习惯用reset_run synth_1清理状态避免被缓存误导。如果想在Tcl脚本里动态指定可以这样写set_property STEPS.SYNTH_DESIGN.ARGS.PROCESSORS 8 [get_runs synth_1] launch_runs synth_1 -jobs 8注意后面-jobs 8是把多个run并行调度比如多个OOC IP核的run可以同时跑前面才是设置单个综合任务内部的线程数。两者不冲突搭配起来提升最大。不同Vivado版本里这条set_property的完整属性名可能有细微差异执行时如果提示找不到属性先用list_property [get_runs synth_1]看一下当前版本支持的写法。3.2 非工程模式直接给synth_design加-threads如果用的是Tcl脚本流程不是GUI工程模式那么上面的工程属性设置就不适用了。直接在综合命令里加-threads参数read_vhdl /path/to/top.vhd read_verilog /path/to/rtl.v read_xdc /path/to/top.xdc synth_design -top top -part xc7z020clg400-1 -threads 8这个参数在synth_design -help里看得到取值范围一般是1到8。它的作用是覆盖线程池参数让当前综合任务指定使用8个线程。用了它之后即使工程里没有设置Processors也能生效。我建议所有非工程脚本都统一在synth_design命令里显式写-threads脚本可读性好别人接手时一眼能看到用了几个线程。3.3 别忘了IP核的OOC综合一个完整工程里往往有多个IP核DDR控制器、FIFO、FFT、DDS等等。工程默认会把每个IP设置成OOC综合也就是单独综合成网表再与顶层设计合并。这意味着每个IP的综合是独立任务天然可以并行。默认情况下Vivado是按顺序跑这些OOC综合的白白浪费了多核资源。通过launch_runs synth_1 -jobs 8Vivado会同时启动最多8个OOC综合run充分利用机器性能。这一步往往比单纯改Processors带来的体感提升还要明显因为大型IP的单独综合经常要占十几分钟。3.4 综合多线程会不会影响结果会但正式流程不要慌多线程优化顺序不同于单线程可能导致综合网表在具体单元摆放和优化深度上有细微差别进而让布局布线后的时序余量有少量波动。一般不会让一个本来应该收敛的设计变得不收敛。我的经验是同一个工程用4线程和8线程各综合一次worse negative slack最大可能差0.2ns左右。追求可复现的团队最好固定线程数并且把seed固定下来这样每次发布流程生成的结果才一致。4. 布局布线阶段的多线程参数不是越满越好4.1 place_design和route_design单独指定线程工程模式下Implementation Settings里的Processors同样可以改到8。如果你不用工程模式而是在Tcl脚本里显式跑place和route则直接在命令后面加上-threads参数place_design -directive Quick -threads 8 route_design -directive Quick -threads 8与综合相比布局布线的多线程上限也是8但实际使用8线程的收益并不稳定。我测试过一个大工程place从4线程换到8线程只快了3分钟route甚至慢了几十秒。这可能和布线器内部对资源图的加锁机制有关。如果说综合阶段多线程是让更多人同时抄写不同章节布局布线阶段则是让更多人抢用同一支笔增加到一定程度人越多反而越挤。4.2 策略选择和线程数的搭配Vivado实现策略中有Quick、RuntimeOptimized、Performance_Explore、Congestion_SpreadLogic_high等。想要快很多人第一反应是选Quick但Quick带来的面积和时序牺牲经常让后期返工。更稳妥的做法是保留默认策略先把线程数开到4或6用report_timing_summary看WNS变化。只有在差距可接受的情况下再尝试把directive换成RuntimeOptimized而不是一上来就选Quick。线程数和策略共同影响运行时间二者要分开控制否则出了问题很难定位是哪个参数导致时序恶化。4.3 多次运行的确定性seed和线程数要固定布局布线是多阶段迭代算法本身存在随机性多线程又放大了这种随机性。同一份网表同一份约束同一线程数不同seed跑出来的布局可能不同。我们组里的做法是在实现策略中把seed固定成一个版本号同时固定线程数需要复现结果时用同一套配置重新跑。不要中途一会儿4线程一会儿8线程对比时序那样对比出来的差值是线程和随机性混在一起没有参考意义。4.4 布局布线的内存消耗比综合更夸张place_design和route_design阶段需要加载布局数据库、路由资源库和时序分析引擎内存占用普遍比综合高一个量级。在开多线程前先确认剩余内存足够。如果内存不够8线程反而会比4线程更慢因为操作系统会频繁使用虚拟内存。我做Kintex-7大工程时曾经因为8线程把16GB机器拖到几乎无响应最后换到4线程时间只多了6%机器却稳定得多。5. 仿真提速xelab的-mt和回归测试的任务级并行5.1 xelab编译与elaboration阶段用-mtVivado的xsim流程分为xvlog编译、xelab分析和elaboration、xsim运行三步。前两步吃的都是CPU并且适合并行。xelab命令支持-mt参数例如xvlog -i ../rtl -i ../tb ../tb/tb_top.sv xelab -mt 8 work.tb_top -s sim_snapshot -debug typical xsim sim_snapshot -runall-mt 8告诉xelab最多用8个线程去做源文件解析和设计层级展开。对于包含UVM、AXI总线模型或大量验证IP的工程这一步加速非常明显。我实测过一套带AXI VIP的testbenchxelab从6分多钟压缩到2分钟以内这个收益比综合阶段还要稳定。5.2 仿真运行阶段用seed并行替代单线程等待xsim的事件驱动内核本质上按事件队列动作多线程版本目前没有公开的线程开关。想要利用多核最直接的手段是让不同seed的回归测试并行跑。例如UVM环境常用UVM_TESTNAME和UVM_SEED可以写shell脚本同时启动8个xsimfor seed in 1 2 3 4 5 6 7 8; do xsim sim_snapshot \ -testplusarg UVM_SEED$seed \ -testplusarg UVM_TESTNAMEmy_test \ -runall sim_$seed.log 21 done wait这样每个xsim进程占一个核8个seed并行跑总回归耗时基本等于最慢那一个seed的时间比串行跑8个快得多。这是当前最能体现“多核提速仿真”的做法。5.3 千万别忽略波形落盘对速度的影响仿真提速有一个经常被忽略的隐藏瓶颈波形文件。xsim默认会在测试结束后写fsdb或vcd波形写一个几十GB的波形文件会占用大量磁盘IO直接影响仿真速度。多核并行跑多个回归时波形同时写入同一块机械硬盘会互相抢带宽。我的办法是回归模式不导波形只在出问题时用-testplusarg控制某个seed追加波形并且把波形文件放在独立SSD分区。另外可以用Vivado的增量编译选项减少重复仿真开销把testbench拆成固定不变的部分和被测设计部分只有DUT改动时才重新elaborate。5.4 第三方仿真器的多线程不少团队用Questa/ModelSim做仿真它们在编译阶段也提供类似的多线程参数比如vopt -threads 8运行阶段的并行同样有限。如果你在使用这些工具可以先敲help vopt查一下是否有-threads或-mt选项。不同的仿真器和版本支持不一样不要在网络上看到一个参数就往命令里塞建议在项目环境里小规模验证后再推广。仿真提速的原则跟综合差不多能并行的地方编译、elaboration、多个用例就用满不能并行的地方事件循环、波形序列化想办法绕开而不是硬开线程参数。6. 一组实测数据和一个反直觉的结论6.1 同一台机器上综合/布局布线/仿真的多线程加速对比我用AMD Ryzen 9 5950X16核32线程 128GB内存 NVMe SSDVivado 2021.2跑了一个Artix-7 xc7a75t的以太网交换设计资源占用大约四成结果如下。阶段1线程4线程8线程综合synth_design12分31秒4分52秒4分21秒布局place_design18分20秒9分44秒8分10秒布线route_design35分12秒21分08秒19分55秒xelab编译elaboration6分24秒1分58秒1分44秒从数据看综合阶段从1到4线程是接近2.6倍的提升从4到8线程只有约10%的边际收益布局布线从4到8差不多只有15%左右的提升。所以盲目把线程数拉满并不是最优解。6.2 小工程和大工程对线程数的反应完全不同同一个Vivado版本我一个约几千LUT的小规模逻辑工程综合从1线程到8线程几乎没有变化甚至8线程比4线程更慢。原因是任务粒度太小线程创建、同步和合并的开销反而占总时间比例变大。这种工程建议保持默认设置把精力放在理解代码而不是调参数上。大工程几十万门以上才对线程数敏感但也没有线性加速。6.3 多线程后的CPU降频问题8线程跑综合时CPU长时间高负载会触碰功耗墙频率可能从4.6GHz掉到3.7GHz左右实际加速效果被抵消。这时单纯加线程并不解决问题。建议在BIOS里开启更宽松的功耗限制或者选择更高单核性能的CPU而不是堆核心数。笔记本上尤其明显i7-12700H开8线程综合温度冲到95度以后频率骤降整体时间未必比4线程快。6.4 验证多线程到底有没有生效设置完不要只看Tcl返回参数要在跑任务时实际观察。Linux下用top -H -p 能看到Vivado的线程数量Windows下打开任务管理器性能页在综合阶段观察CPU逻辑核心曲线是否大部分被拉高。如果8线程设置后CPU占用率依然只有单核水平优先检查是不是在远程桌面会话里跑或者被CPU亲和性限制了其次检查版本Vivado 2017.3之前的版本对多线程支持很弱有条件尽量升级到较新版本。6.5 除了多线程还有哪些同级别的加速手段多线程不是唯一的花钱买时间方案。把综合策略从RuntimeOptimized改成默认通常能减少不少运行时间在分区约束中限制错误局部重跑也能节省大规模改动后的时间使用增量布局布线write_checkpoint incremental对临近收敛的工程作用明显在第二次布局时只调整变化部分。多线程和这些方法并不冲突组合起来才是完整的提速方案。最后说一点我自己的体会。刚接触Vivado时我也迷信“核越多越好”把所有能开的线程和jobs全拉满结果换来的是内存警报、CPU降频和更不稳定的时序。后来才学会按阶段分开控制综合开到6到8布局布线4到6OOC和回归仿真按进程数并行波形按需记录。这个组合拍下来整体等待时间大概是从前的三分之一机器也不会被拖死。如果你的工程也卡在综合和布线的长时间等待里建议先照文章里的命令跑一次之后每次换工程都记录一份“线程数、内存峰值、阶段耗时”的表格慢慢就能找到最适合自己机器的配置。多线程是工具不是信仰用在对的地方才有意义。
返回列表