尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vivado多核优化实战:从综合到仿真全面提升FPGA编译效率

Vivado多核优化实战:从综合到仿真全面提升FPGA编译效率 如果你的 Vivado 工程一次综合加实现要跑五六个小时改一行代码就得等到第二天才能看到结果那你一定想过同一个问题CPU 明明有十几个核心Vivado 为什么不能全用起来我在做 Xilinx 平台下的 FPGA 开发时也被这个情况折磨过很久尤其是工程到了中后期综合两小时、布局布线三四个小时都是常态整个迭代节奏慢到让人怀疑人生。后来我专门花时间把 Vivado 从综合到仿真整个流程的多核性能优化梳理了一遍踩了不少坑也找到了几条真正有效的路径。这篇就分享一下我的实测经验覆盖综合、实现、仿真三个阶段的具体加速方案以及安装、License、硬件环境层面的避坑建议。适合被大型工程编译时间折磨的 FPGA 工程师也适合刚接触 Vivado 想少走弯路的朋友。如果你现在只是做电赛综合测评级别的小工程这些优化可能用不上但等你做的工程规模上来之后差别会非常明显。1. 先搞清楚Vivado 多核优化到底卡在哪1.1 编译时间都花在哪儿了先说一个重要前提Vivado 的多核优化不是全局统一的不同阶段对多核的利用程度差别非常大。综合Synthesis阶段主要是把 RTL 翻译成工艺网表并进行逻辑优化这个过程中有大量可以拆分的子任务比如各模块的逻辑综合、资源映射、基础优化并行潜力相对较高。布局Place阶段要把网表中的单元映射到 FPGA 内部的实际 LUT、FF、BRAM、DSP 位置算法对全局布局质量要求很高很多迭代不容易简单拆分。布线Route阶段则是在已有布局基础上把可编程互连资源分配好全局资源竞争和时序收敛让这个过程天然偏向串行。拿一个包含 PCIe、DDR4 和若干高速串行接口的中大型 UltraScale 工程举例我常见的时间分配大概是综合 1~2 小时布局 1 小时左右布线 2~3 小时后面还经常跟着时序收敛和物理优化的多轮迭代。综合加实现加起来动辄半天仿真又是另一个时间黑洞。所以“多核优化”这件事并不是改一个参数就能让所有阶段都提速而是要先搞清楚每个阶段的瓶颈在哪里再对症下药。1.2 Vivado 的多线程模型和那几行关键 TclVivado 内部有多线程机制的开关主要通过 Tcl 参数控制。最基础的是general.maxThreads它控制整个工具链的全局最大线程数。默认情况下Vivado 会根据机器逻辑 CPU 数量自动设置但在 Windows 上经常识别不准超线程的存在也会干扰判断所以手动设置是更稳妥的做法。# 查看当前值 get_param general.maxThreads # 设置全局最大线程数为 8 set_param general.maxThreads 8除了全局参数还有几个分阶段的覆盖参数比如synth.maxThreads、place.maxThreads、route.maxThreads。我的经验是全局参数设一个基数再根据具体阶段微调。这里有个容易踩的坑——线程数并不是越大越好。我最初在一台 16 核 32 线程的机器上把general.maxThreads直接拉到 32结果综合时间反而比默认更慢。原因是 Vivado 的很多任务之间有依赖线程太多会导致大量同步等待和内存带宽争抢超线程带来的虚拟核心也不总能提供真实计算力。一般建议先按物理核心数设置比如 8 核 16 线程就设 8然后往上试探拐点。查询物理核心数可以用系统命令# Linux lscpu # Windows PowerShell (Get-CimInstance Win32_Processor).NumberOfCores另外提醒一下Vivado 在 Linux 和 Windows 上的多线程表现是有差异的。Linux 的文件 IO 和进程调度整体更高效大工程放 Linux 服务器上跑通常会比同配置的 Windows 机器快一些尤其是并行任务多的时候。2. 综合阶段加速从单核苦熬到多模块并行2.1 综合的多线程参数与策略取舍综合阶段最直接的加速方式就是打开多线程。除了全局参数Vivado 的综合 run 也有独立的线程数设置。GUI 的操作路径是Flow Navigator 中右键Synthesis选择Process Properties里面有Number of threads选项。用 Tcl 设置更灵活尤其适合脚本化构建# 设置 synth_1 这个 run 的综合线程数为 8 set_property -name {STEPS.SYNTH_DESIGN.ARGS.MAX_THREADS} -value 8 [get_runs synth_1]另一个容易被忽略的点是综合策略。Vivado 内置了多个综合策略比如Vivado Synthesis Defaults、Flow_AreaOptimized_high、Flow_RuntimeOptimized等。时间吃紧时可以选偏 Runtime 的策略它会减少一部分全局优化 pass缩短编译时间。我实测过同一个工程开Flow_RuntimeOptimized后综合时间能缩短 20%~30%但 LUT 和寄存器资源可能增加 5% 左右。项目后期迭代时如果资源余量充足这个取舍完全可以接受资源特别紧张的话就得谨慎使用。2.2 OOC 模式并行综合效果最明显如果说综合阶段有什么技巧能让多核收益最大化那一定是 OOCOut-of-Context模式的并行综合。OOC 的意思是让某个子模块脱离顶层环境独立综合生成单独的网表和 checkpoint。它的好处有两个一是子模块可以单独优化不会在顶层综合时被过度 flatten 或 padding二是可以和其他模块并行综合把一颗 CPU 当成多颗 CPU 用。在 Vivado 工程里把模块设为 OOC 的常见做法是在综合后的网表中右键目标模块选择Set OOC也可以在 Tcl 里对对应模块设置属性。当你把几个大模块都设成 OOC 之后可以创建多个综合 run 并联动启动# 并行启动多个综合 runjobs 参数控制同时运行的任务数 launch_runs -jobs 4 [get_runs synth_1 ooc_mod_a ooc_mod_b ooc_mod_c] # 等待全部完成 wait_on_runs synth_1 ooc_mod_a ooc_mod_b ooc_mod_c我实际项目里把三个吃资源的模块拆成独立 OOC 并行综合整体综合时间从 2 小时 10 分钟缩短到 55 分钟左右效果非常直接。需要注意的是OOC 模块脱离了顶层约束环境时序约束和物理约束必须单独写好否则实现阶段会出现奇怪的时序违例。另外OOC 综合会额外消耗 License 资源和中间文件磁盘空间并行度太高时要注意磁盘占用。如果你更喜欢非工程模式也可以直接并行启动多个vivado批处理进程每个进程单独综合一个模块。比如用 shell 脚本for mod in mod_a mod_b mod_c; do vivado -mode batch -notrace -nojournal \ -source synth_${mod}.tcl log_${mod}.txt 21 done wait这种方式需要注意几个前提每个进程要用独立的输出目录避免 checkpoint 互相覆盖License 必须支持多个 Vivado 实例同时运行内存要足够因为每个综合任务大概会吃 2~4GB 内存并行 8 个任务就是 16~32GB。3. 实现阶段加速布局布线的多线程与多任务并行3.1 Place 阶段多线程参数与实测对比布局阶段在 Vivado 2020.1 之后对多线程的支持有了明显改进。如果你还在用 2017.x 或 2018.x 这类老版本布局多线程的收益比较有限甚至可能出现负优化。版本在 2020.1 以上的话可以放心设置独立的 place 线程数# 单独设置布局线程数 set_param place.maxThreads 8我在一台 8 核 16 线程的机器上做过对比同一份网表place 线程数从默认 4 提高到 8Place Design 阶段时间缩短了约 25%。如果继续调到 16时间反而没有继续下降还有轻微回弹。这说明布局阶段的多线程收益存在明显的边际递减点实际跑之前最好多测一两组参数找到当前设计的拐点。布局指令Directive也值得关注。place_design支持-directive参数包括Default、Explore、ExtraNetDelay_high等。Explore会尝试更多布局方案改善布线可行性但会明显增加运行时间。如果当前目标是缩短迭代周期建议先用默认或 Runtime 倾向的 directive等最终时序收敛时再开 Explore。3.2 Route 阶段多线程受限怎么办布线阶段比较头疼。Vivado 的route_design虽然也有多线程参数内置算法也会利用部分并行能力但布线里的线程间依赖非常重多线程带来的加速通常只有 10%~20%远不如综合阶段明显。如果布线是全流程主要耗时点直接调线程数收益不大我更推荐两种思路。第一种是增量布局布线。如果改动只涉及局部逻辑先跑一次完整实现并保存 checkpoint之后改完代码或约束用增量模式复用上次结果# 将上一次的 route.dcp 指定给 impl run 使用 set_property INCREMENTAL_CHECKPOINT ./impl_1_prev_route.dcp [get_runs impl_1]增量模式能跳过大量布局迭代实测改动不大的情况下整个实现时间能从 4 小时压到 1 小时以内。但要注意增量复用的前提是改动范围确实有限。如果顶层结构大变增量可能到处不匹配退化成全量重跑甚至比全量更慢。第二种是利用多核跑多个实现副本。单个布线任务吃不满多核那就同时跑多个实现任务并行试探不同策略。Vivado 支持创建多个 implementation run然后用launch_runs并行执行# 并行运行两个不同策略的实现 launch_runs impl_1 impl_2 -jobs 2 # 查看完成情况 wait_on_runs impl_1 impl_2这种做法的收益在于多个策略同时跑哪个先收敛、时序更好就选哪个等于用 CPU 资源换等待时间。我在做时序收敛冲刺时经常这么干一次并行跑三四个实现整体效率比串行尝试高很多。前提同样是 License 允许同时内存和磁盘也要顶得住。还有一点物理优化phys_opt_design在布局布线之后往往还要跑多轮如果当前主要瓶颈在这一步也可以配合-directive Explore并行尝试多个优化方向不过收益因设计而异建议先小规模验证再上。4. 仿真加速策略从单进程慢等到多进程并行4.1 仿真工具的多核支持与选择仿真的加速思路和综合不完全一样。Vivado 自带的 XSIM 在编译阶段可以通过xelab的参数开启多线程比如xelab work.tb_top -mt 8其中-mt控制编译和 elaboration 阶段的工作线程。但按我的经验XSIM 的编译并行度还是偏弱工程里挂着大量 IP 仿真模型时编一个仿真环境依然很折磨人。很多团队会把仿真器换成 QuestaSim 或 VCS它们的编译器和 elaboration 在并行方面做得很成熟。如果你还在用 ModelSim/QuestaSim编译阶段可以关注vlog的并行编译参数它支持同时编译多个库和多个文件。仿真运行阶段则更多要靠多进程并发来提速而不是指望单个仿真进程内部多线程大幅加速。Vivado 工程里的自定义 IP 和第三方 IP 很多仿真模型编译也可以分批并行把不同的 IP 仿真库分别生成到不同目录然后开多个终端同时编译最后在仿真脚本里统一-L指定库路径。另外一个容易被忽略的点是仿真模型本身的复杂度。像 PCIe、DDR4、Aurora 8B/10B 这类高速串行接口 IP如果直接拿完整 RTL 模型做系统级仿真速度会慢到让人怀疑人生。通常的做法是在系统级仿真里用行为级模型或总线功能模型替代复杂 IP 的底层收发器逻辑需要专门验证收发器行为时再单独跑精细模型。这个替换带来的提速往往比调编译参数明显得多尤其是做整个 SoC 或子系统级仿真的时候。4.2 回归测试并行化把一颗 CPU 当成一群 CPU 用仿真真正吃 CPU 的场景通常不是单个 testbench 跑多久而是回归测试要跑几百上千个用例。这种情况下最有效的多核加速策略是把一个串行回归队列拆成多个并行的仿真进程。我常用做法非常简单按种子或按测试用例分组每个进程跑一组然后用脚本统一调度。# 示例用 GNU parallel 同时跑 8 个仿真用例 seq 1 8 | parallel -j 8 \ vsim -c work.tb_top ntb_random_seed{} -do run -all; quit如果本地机器够强一个工程可以同时开 8 个甚至 16 个仿真进程。需要注意两个限制一是 License 数量很多仿真工具的 License 对并发实例数有限制二是磁盘 IO每个仿真进程都会产生波形文件和日志如果全部写到机械硬盘CPU 再多也快不起来。我自己的做法是波形文件默认不 dump只在需要调试的用例里打开波形记录这样大多数回归用例跑起来就像单元测试一样轻量。对于使用 UVM 或复杂 SystemVerilog 验证环境的团队还可以把仿真队列分发到多台服务器上用 LSF、SGE 这类任务管理系统或简单的sshnohup脚本实现分布式回归。本质上思路只有一个不要指望单个仿真任务吃掉所有核心而是用并发任务把核心充分利用起来。5. 提速之外的坑安装、License 与硬件环境5.1 从安装开始就别给自己挖坑很多中大型工程跑得慢其实有一半原因出在环境本身。先说安装版本我建议优先使用稳定版本比如 2020.2、2021.1、2022.2不要盲目追新新版本在兼容性和已知问题修复上需要时间沉淀。安装时只勾选自己用的器件系列就好比如 UltraScale 工程就只选 UltraScale 和相关 IP 支持不要全选。全选安装不仅多占用几十 GB 磁盘还会让后续组件扫描和工具链初始化变慢。安装过程中经常有人遇到“WinPcap 安装失败”的提示。这是 Vivado 安装包自带的 WinPcap 组件和新版 Windows 兼容性不佳导致的。如果你不用 System Generator 里涉及网络抓包的仿真环境这个失败可以直接忽略不影响正常综合、实现和下载。另外如果板卡插上后 Vivado 识别不到多半是 JTAG Cable 驱动问题。设备管理器里手动更新驱动指向Vivado安装目录/data/xicom/cable_drivers/nt64重新插拔 USB 线一般就能解决。5.2 硬件环境优化SSD、内存与 CPU 选型再回到性能本身。Vivado 在综合和实现过程中会生成大量临时文件和 checkpoint大到几个 GB 很常见。所以磁盘 IO 是除了 CPU 核心数之外最容易被忽略的瓶颈。我自己的一个明显例子把工程目录从机械硬盘迁到 NVMe SSD 之后工程打开时间从原来的 5 分钟降到 40 秒综合过程中的中间文件写入也明显变快。如果只有一块机械硬盘CPU 多核优化做得再好也会被磁盘等待拖垮。内存方面大工程在布局布线阶段吃 16GB 以上内存很正常大型 UltraScale 设计甚至可能吃到 64GB。内存不足时系统开始换页你会发现 CPU 利用率上不去线程数怎么调都白搭。所以大工程优先保证内存容量其次再考虑 CPU 和 SSD。内存不够时多开并行任务反而容易 OOM得不偿失。我的经验值参考综合阶段每个并行任务预留 2~4GB实现阶段每个任务预留 8~16GB具体看器件规模和利用率。CPU 选型方面不要只看核心数还要看主频和 IPC。Vivado 不是纯并行计算工具内部有大量串行逻辑一颗 8 核 16 线程、主频 3.5GHz 以上的 CPU往往比一颗 16 核但主频只有 2.1GHz 的 CPU 在实际编译里更舒服。Windows 环境下还要注意杀毒软件实时扫描的影响把 Vivado 安装目录、工程目录和 Xilinx 临时目录加入白名单通常能带来肉眼可见的速度提升。阶段主要耗时占比多线程收益预期推荐做法综合中高开启多线程大模块做 OOC 并行综合布局中中place.maxThreads 设置到物理核数附近布线高低增量实现或多策略并行 run仿真编译低中选择多线程编译选项并行编译 IP 库仿真运行高中多进程并行跑回归测试6. 常见问题与排查技巧实录6.1 多核设置“不生效”的三个原因很多人会遇到这种情况明明设置了set_param general.maxThreads 8编译时间却没什么变化。我总结过三个最常见的原因。第一是 License 限制。使用浮动 License 时并行综合或并行实现会同时占用多个 License 席位如果 License 数量不足工具会退化成串行等待。解决方法是检查 License 类型和可用席位大型并行任务建议用 Node-Locked License或者确保服务器上有足够多的可用席位。第二是超线程干扰。如果机器是 8 核 16 线程直接把线程数设成 16虚拟核心带来的调度开销往往会让任务更慢。比较简单的经验是先按物理核心数设置比如 8 核设 8如果 CPU 有高性能架构加成再试 10 或 12找到收益拐点。Vivado 对超线程的利用并不像普通渲染、压缩任务那么理想这一点在布线阶段尤其明显。第三是磁盘 IO 变成瓶颈。线程数提高后中间文件读取和写入的并发度也会提高但如果磁盘本身很慢CPU 会长时间处于等待 IO 状态。判断方法很简单跑任务时打开任务管理器或iostat如果磁盘占用基本打满而 CPU 占用率不高那瓶颈就在磁盘不在线程数。6.2 implement design 变红的快速定位法Vivado 工程里implement design变红是新手最容易慌的问题。变红本质上是 implementation run 失败或生成的报告里有严重违例但具体原因千奇百怪。我一般按三个步骤定位。第一步点开对应 run 的 log 文件直接搜索ERROR和CRITICAL WARNING。大多数问题能在这里直接看到原因比如引脚冲突、约束语法错误、时钟分组缺失等。第二步如果 log 里看不到明显错误但 run 还是红色就检查时序是否严重违例比如 WNS 为负且负得离谱log 里通常会有时序报告摘要。第三步如果从 log 里找不到答案优先检查 License 和内存。License 不可用时实现阶段可能中途退出报错内存不足则可能直接 OOM工具崩溃后 run 状态也会变红。还有一个很实用的排查技巧重新跑之前先reset_run清掉中间文件和运行状态很多时候红色状态只是上一次异常退出留下的脏标记不清理直接重跑容易延续错误。最后再说一点我个人的体会Vivado 多核优化的核心不是把某个参数调到最大而是先找到瓶颈再围绕瓶颈选择对应策略。我已经把优化流程固化成一张工程级 checklist先确认磁盘是 SSD、内存够大、License 充裕然后把general.maxThreads设置为物理核心数综合阶段用 OOC 或并行 run 处理大模块实现阶段小改动走增量、大改动多跑几个策略副本仿真则尽量把回归任务拆成并行进程。这些技巧单个拿出来都不复杂组合在一起后迭代效率的提升会非常明显。如果你也在被 Vivado 的编译时间折磨不妨先从看磁盘占用率和核对线程参数开始试起。
返回列表