1. 从时序报告到路径分组:为什么path group值得单独拿出来讲
数字后端做到时序收敛阶段,很多人会陷入一个误区:盯着report_timing的slack数字反复调,却忽略了这些路径到底被归到了哪个组里。我在带新人的时候发现,十有八九的人第一次打开Innovus的时序报告,看到path group那一列是懵的——明明只关心setup和hold,怎么冒出来reg2reg、reg2cgate、in2reg、reg2out、feedthru一堆分类。更麻烦的是,当你试图用setPathGroupOptions去调某个组的effort时,发现命令执行了但报告里毫无变化,原因往往是你调的那个组根本不是这条路径实际归属的组。
这就是path group这个机制的核心价值所在:它不是一个可有可无的报告分类标签,而是Innovus做时序优化时的调度单元。工具在决定先修哪条路径、给多少优化资源、用什么策略去修的时候,依据的就是路径所属的group以及这个group上配置的选项。换句话说,path group是你和优化引擎之间的一个控制接口,你通过它告诉工具“哪类路径更重要、哪类可以放一放”,工具则据此分配算力和策略。
上篇我们聊了path group的基本概念和默认分组逻辑,这篇重点落在策略配置和实际应用上。具体来说,会覆盖几个实操中绕不开的问题:setPathGroupOptions里那些参数到底怎么选、weight和effort之间是什么关系、什么时候该自定义path group、以及path group和useful skew、MMMC这些机制怎么配合。适合已经能跑通基本流程、开始追求时序收敛质量的后端工程师参考,刚入门的同学也能从中理解工具优化决策的底层逻辑。
2. path group策略配置的核心参数拆解
2.1 setPathGroupOptions的参数体系与作用机制
setPathGroupOptions是控制path group行为的核心命令,它的参数大致可以分成三类:资源分配类、优化策略类和约束覆盖类。资源分配类包括-effort和-weight,前者决定工具在这个组上投入多少优化力度,后者决定多个组竞争资源时的优先级排序。优化策略类主要是-targetSlack和-slackAdjustment,用来设定该组的收敛目标和松弛调整量。约束覆盖类则涉及-earlyLaunch、-lateCapture这类对launch和capture时钟路径的干预。
先说说-effort。它有三个档位:low、medium、high。默认情况下,大多数组是medium。这个参数的本质是告诉优化引擎“在这个组上愿意花多少迭代次数和优化动作”。设成high之后,工具会尝试更多的size up、更多的buffer插入、更激进的restructure,代价是运行时间上升,而且可能对相邻路径产生副作用。我实测下来,high effort用在关键组上效果明显,但如果所有组都设high,等于没设——资源被摊薄,整体收敛反而变慢。
-weight是一个相对值,默认是1。它的作用场景是当多个组的路径在同一个优化窗口里竞争时,工具按weight比例分配优化机会。比如reg2reg设weight 3,reg2out设weight 1,那么在资源紧张时,工具会优先保证reg2reg的优化质量。这里有个容易踩的坑:weight不是越大越好。设得太悬殊会导致低weight组长期得不到优化,最后那些组的违例积累到无法收拾。我的经验是weight比例控制在1:3以内比较稳妥,极端情况不超过1:5。
-targetSlack这个参数值得单独说。它允许你给某个组设定一个比全局约束更紧或更松的目标。比如全局setup约束是0,你可以给某个关键组设targetSlack 0.05,让工具往正slack方向多推一点,留出余量。反过来,对于一些非关键组,设一个负的targetSlack可以让工具不要在那上面浪费资源。这个参数在时序紧张、需要精细分配优化预算的时候特别好用。
2.2 effort与weight的配合逻辑:资源分配的底层原理
很多人搞不清effort和weight的区别,觉得两个都是“加大力度”的意思。实际上它们的作用层面完全不同。effort是组内的优化深度,weight是组间的资源竞争权重。打个比方,effort像是给一个部门拨的预算,weight像是这个部门在公司整体资源分配中的话语权。预算多但话语权低,可能钱还没花出去就被别的部门抢走了资源;话语权高但预算少,抢到了资源也干不了太多事。
实际配置的时候,我通常的套路是:先给所有组设统一的medium effort和weight 1作为基线,跑一轮看报告,找出违例最严重、对整体WNS影响最大的组,把这个组的effort提到high,weight提到2到3。然后再跑一轮,观察其他组有没有因为资源被抢而恶化。如果出现恶化,要么适当回调weight,要么给恶化的组也提一点effort。这个迭代过程一般两到三轮就能找到平衡点。
有一个细节容易被忽略:effort的提升是有边际递减的。从low到medium的提升幅度通常很明显,从medium到high的提升幅度取决于设计本身的可优化空间。如果一轮high effort跑下来WNS只改善了几个ps,那说明这个组的瓶颈不在优化力度上,而可能在约束设置、floorplan或者时钟结构上,继续加effort是浪费机时。
2.3 targetSlack与slackAdjustment的精细调控
-slackAdjustment这个参数用得少但很关键。它是在计算组内路径优先级时对slack做一个偏移。举个例子,某个组里有两条路径,slack分别是-0.1和-0.15,正常情况工具会优先修-0.15那条。但如果你给这个组设了slackAdjustment -0.05,那么工具看到的有效slack就变成-0.15和-0.2,优先级排序会变化。这个参数的典型用途是让工具更关注某些特定类型的路径,或者在多corner分析时对齐不同corner的优化重点。
targetSlack和slackAdjustment经常配合使用。一个常见的组合是:给关键组设targetSlack 0(或略正),同时设一个小的负slackAdjustment,让工具在满足目标的前提下仍然优先处理最差的路径。这种组合在时序余量紧张、需要“保底线”的项目里很实用。
注意:targetSlack设得比实际可达值紧太多,会导致工具在这个组上反复迭代却无法收敛,白白消耗运行时间。设之前最好先看一轮报告,了解这个组的slack分布,目标定在比当前WNS好10%到20%的位置比较合理。
3. 自定义path group的划分策略与实操
3.1 什么时候需要自定义path group
默认的path group划分(reg2reg、reg2cgate、in2reg、reg2out、feedthru等)是按路径端点类型自动分的,大多数情况下够用。但有几类场景默认分组不够精细,需要手动切分。
第一类是跨时钟域路径。默认分组不区分时钟域,所有reg2reg路径混在一个组里。如果设计里有多个异步或半同步时钟域,某个域的路径特别难收敛,你没法单独给它加effort。这时候可以按时钟域自定义group,把难收敛的域单独拎出来。
第二类是特定功能模块的内部路径。比如某个高速接口模块的内部reg2reg路径时序很紧,而其他模块相对宽松。默认分组下它们混在一起,你调effort是全局生效的,没法精准打击。自定义group可以按instance范围或者按clock定义来切。
第三类是特殊约束路径,比如需要做useful skew的路径、需要特殊NDR的路径。把这些路径单独成组,配合setPathGroupOptions的特定参数,可以实现更精细的控制。
自定义path group的命令是createPathGroup或者用group_path(取决于你用的命令集),核心是指定group name和成员条件。成员条件可以基于from/to的点、时钟、instance层次等。我一般习惯用-from和-to配合-through来精确定义,避免误伤。
3.2 按时钟域切分的实操步骤与参数
假设设计里有两个时钟域clk_core和clk_ddr,clk_ddr的路径收敛困难,想单独成组。操作步骤如下。
第一步,确认现有分组情况。跑report_path_group或者看时序报告里的path group列,确认clk_ddr的路径当前落在哪个组。通常它们混在reg2reg里。
第二步,创建自定义组。用类似这样的命令:
group_path -name ddr_reg2reg -from [get_clocks clk_ddr] -to [get_clocks clk_ddr]这条命令把launch和capture都在clk_ddr域内的reg2reg路径归到ddr_reg2reg组。注意-from和to用clock而不是pin,这样覆盖面更全,不会漏掉某些instance。
第三步,给新组配置选项:
setPathGroupOptions ddr_reg2reg -effort high -weight 3 -targetSlack 0.02第四步,确认原reg2reg组里不再包含clk_ddr的路径。有时候group_path的优先级和默认分组有交互,需要跑一轮report确认。如果发现路径同时出现在两个组里,检查是不是-from/-to的条件写得不够精确,或者有路径的launch和capture跨了域。
第五步,跑一轮优化,对比自定义分组前后的WNS和TNS变化。我遇到过一种情况:单独给ddr组加effort后,ddr的WNS改善了,但core组的WNS恶化了,原因是总优化资源被重新分配。这时候要么给core组也适当加weight,要么回调ddr的weight,找到平衡。
3.3 自定义分组的粒度控制与常见误区
自定义path group最容易犯的错是切得太细。有人恨不得每个模块、每个时钟域、每种路径类型都单独成组,结果组数量膨胀到几十个,每个组的路径数很少。这样做的问题在于:优化引擎在组间调度是有开销的,组太多会导致调度效率下降;而且每个组路径少,统计意义弱,effort和weight的调整效果不明显,反而增加了调参的盲目性。
我的经验是自定义组控制在5到8个以内,加上默认组总共不超过15个。切分的依据应该是“优化策略确实需要不同”,而不是“想看得更清楚”。如果只是想看清楚某类路径的情况,用report的filter就够了,不必动分组。
另一个误区是自定义组和默认组的覆盖关系没理清。group_path创建的组和默认组之间可能存在路径重叠,一条路径可能同时满足两个组的条件。Innovus的处理是有优先级的,但具体行为取决于版本和命令顺序。稳妥的做法是:创建自定义组后,用report确认路径归属唯一,必要时用-exclude参数把某些路径从默认组里排除。
4. path group与其他时序收敛机制的配合
4.1 path group与useful skew的联动
useful skew是时序收敛的利器,但它的效果高度依赖path group的划分。useful skew的本质是借用相邻路径的时序余量来改善关键路径,而“相邻”的判断依据就是path group内的路径关系。如果关键路径和它想借余量的路径不在同一个组里,useful skew就借不到。
实操中,我通常会把需要做useful skew的路径和它潜在的“供体”路径放在同一个自定义组里,然后在这个组上开启useful skew相关的选项。具体来说,setPathGroupOptions配合setUsefulSkewMode使用,前者定义组,后者定义skew策略。需要注意的是,useful skew会改变时钟树的latency分布,对hold时序有影响,所以做完之后必须重新检查hold,必要时在hold组上补buffer。
还有一个细节:useful skew的优化是在组内路径之间做平衡,如果组内路径的slack分布很均匀(都差不多),skew的空间就很小;如果分布悬殊(有的很紧有的很松),skew的收益就大。所以自定义分组的时候,把slack分布相近的路径放在一起,useful skew的效果会更好。
4.2 多corner多模式下的path group策略
MMMC环境下,path group的配置需要按scenario分别考虑。同一个组在不同corner下的表现可能完全不同:在ff corner下setup很松,在ss corner下setup很紧。如果你只按一个corner的感受去设effort和weight,另一个corner可能就吃亏了。
我的做法是:先跑一轮所有scenario的时序报告,统计每个组在每个corner下的WNS和违例路径数,做成一张表。然后按“最差corner优先”的原则配置。比如reg2reg组在ss corner下WNS -0.2,在ff corner下WNS +0.1,那effort和weight就按ss corner的需求来设,ff corner那边松一点没关系。
| 组名 | ss corner WNS | ff corner WNS | 违例路径数 | effort | weight |
|---|---|---|---|---|---|
| reg2reg | -0.20 | +0.10 | 1250 | high | 3 |
| reg2out | -0.08 | -0.02 | 320 | medium | 2 |
| in2reg | -0.15 | +0.05 | 680 | high | 2 |
| reg2cgate | -0.05 | +0.08 | 90 | low | 1 |
这张表是我实际项目里常用的格式,一目了然。配置的时候按最差corner的需求来,同时留意其他corner有没有因为资源倾斜而恶化。如果某个组在某个corner下本来很松,但因为别的组抢资源导致它恶化了,那就需要重新平衡。
提示:MMMC下path group的选项是按scenario生效的,同一个组在不同scenario下可以有不同的effort和weight。用
setPathGroupOptions的时候记得带上-scenario参数,否则可能只对当前active scenario生效,其他scenario没吃到配置。
4.3 path group与optMode、drv优化的交互
path group的优化不是孤立的,它和optMode(优化模式)以及DRV(design rule violation)优化有交互。optMode决定了工具整体的优化策略倾向,比如是偏向WNS还是偏向TNS,是激进还是保守。path group的effort是在optMode的大框架下起作用的,如果optMode本身设得很保守,你把某个组设成high effort,效果也会打折扣。
DRV优化和path group的关系更微妙。DRV违例(比如max transition、max capacitance)的修复会消耗优化资源,而这些资源是从path group的预算里出的。如果某个组的路径上DRV违例很多,工具会先花资源修DRV,留给时序优化的就少了。这种情况下,要么先单独跑一轮DRV修复把违例清掉,要么给这个组更高的effort来覆盖DRV的开销。
我踩过的一个坑是:某个组设了high effort但WNS纹丝不动,查了半天发现是那个组的路径上max transition违例太多,工具一直在修DRV没空修时序。后来先把DRV清干净再跑,effort的效果就出来了。所以看path group效果之前,先确认DRV是否干净,这是个容易被忽略的前置条件。
5. 常见问题排查与实操避坑指南
5.1 path group配置不生效的排查思路
配置了setPathGroupOptions但报告没变化,这是最高频的问题。排查顺序我一般是这样走的。
先确认组名拼写和路径归属。跑report_path_group -summary看所有组的列表和每组路径数,确认你配置的组确实存在且有路径。有时候组名大小写或者下划线写错了,命令不报错但配置落到了不存在的组上,自然不生效。
再确认配置是否被后续命令覆盖。Innovus的配置是有顺序的,如果后面又跑了一次setPathGroupOptions或者某个脚本重新初始化了分组,前面的配置可能被冲掉。检查脚本执行顺序,确保配置命令在分组确定之后、优化开始之前。
然后确认scenario。MMMC下如果没带-scenario,配置可能只落在active scenario上。用report_path_group -scenario <name>逐个确认。
最后确认优化是否真的跑了。有时候配置生效了,但优化阶段因为某种原因跳过了这个组(比如组内路径都被设了dont_touch),那也看不到变化。检查路径的dont_touch属性。
5.2 组间资源争夺导致此消彼长的处理
给一个组加weight或effort之后,另一个组恶化了,这是资源争夺的典型表现。处理思路不是简单回调,而是先判断哪个组的恶化是可以接受的。
如果恶化的是非关键组,且恶化幅度在可接受范围内(比如WNS从+0.05变成-0.02,但整体还有余量),那可以接受,不必调整。如果恶化的是关键组,或者恶化幅度大到影响整体收敛,那就需要重新平衡。
平衡的手段有三个:一是回调高优先级组的weight,二是给恶化组也加effort,三是用targetSlack给恶化组设一个保底目标。我一般优先用第三个,因为targetSlack是“保底线”性质的,不会像weight那样剧烈改变资源分配,副作用小。
还有一个进阶手段是分阶段优化:先集中资源修最难的组,修到一定程度后,再放开资源给其他组。这需要手动控制优化阶段,用optDesign的分步执行配合path group配置的切换来实现。操作上稍微繁琐,但在时序极度紧张的项目里很有效。
5.3 path group相关的典型报错与速查表
| 现象 | 可能原因 | 排查动作 | 解决方式 |
|---|---|---|---|
| setPathGroupOptions报错组不存在 | 组名拼写错误或组未创建 | report_path_group确认组列表 | 修正组名或先创建组 |
| 配置后报告无变化 | 配置被覆盖或scenario不对 | 检查脚本顺序,确认scenario | 调整顺序,补-scenario参数 |
| 某组路径数为0 | 分组条件写错或路径被排除 | 检查group_path的from/to条件 | 修正条件,确认路径归属 |
| 加effort后WNS不变 | DRV违例占用资源或无可优化空间 | 检查DRV报告和路径结构 | 先清DRV,或换优化策略 |
| 组间此消彼长严重 | 资源争夺 | 对比各组WNS变化 | 调weight或加targetSlack保底 |
| useful skew无效果 | 组内slack分布均匀 | 看组内slack分布 | 重新分组,让分布有梯度 |
这张表是我自己整理的问题速查表,实际项目里遇到问题先对一遍,大部分情况能快速定位。表里没覆盖的情况,多半是设计本身的结构问题,需要回到floorplan或时钟树层面去查。
5.4 几个只有踩过才知道的实操心得
第一个心得:path group的配置要在优化前定好,优化中途频繁改配置效果很差。工具在优化过程中会基于当前配置做一系列决策,中途改配置会让之前的优化成果部分失效,而且工具需要重新评估路径优先级,反而拖慢收敛。我的习惯是在optDesign之前把分组和选项定下来,跑完一轮再看要不要微调,而不是边跑边调。
第二个心得:report_path_group的summary比detail更有用。detail报告路径太多看不过来,summary给出每组的路径数、WNS、TNS,一眼就能看出哪个组是瓶颈。我一般先看summary定位问题组,再针对性地看detail。
第三个心得:自定义组的命名要有规律。我见过有人用group1、group2这种命名,过两天自己都忘了哪个组是什么。我的命名习惯是“时钟域_路径类型”或者“模块名_路径类型”,比如ddr_reg2reg、core_in2reg,一看就知道是什么。
第四个心得:path group的调整要和整体时序收敛策略对齐。如果项目整体策略是保WNS,那path group的配置就围绕最差路径所在的组来做;如果策略是保TNS,那就要关注违例路径多的组,哪怕单条路径不是最差的。这两个策略下path group的配置重点完全不同,搞混了会事倍功半。
第五个心得:别忘了hold的path group。大家注意力都在setup上,hold的path group配置经常被忽略。hold违例虽然单条影响小,但数量多的时候修复成本很高。给hold组适当设effort和weight,在setup收敛之后专门跑一轮hold优化,比事后补buffer效率高得多。
6. 从策略到落地:一套可复用的path group配置流程
把前面聊的内容串起来,形成一套我实际项目里反复用的流程。这套流程不是死板的步骤,而是一个迭代框架,根据项目情况调整。
第一步,基线跑一轮,拿到所有组的时序summary。不做任何path group配置,用默认设置跑optDesign,然后report_path_group -summary,记录每组的路径数、WNS、TNS。这一步的目的是建立参照系,知道默认配置下各组的表现。
第二步,识别瓶颈组。按WNS排序,最差的几个组是重点;按TNS排序,违例路径最多的组也要关注。两者可能有重叠也可能不同,都要看。同时检查这些组的路径是否适合用path group来优化——如果瓶颈是DRV或者结构问题,调path group没用。
第三步,决定是否自定义分组。如果瓶颈组在默认分组下已经能单独控制(比如就是reg2reg组),那不需要自定义;如果瓶颈路径混在某个大组里没法单独调,就按第3章的方法切分。
第四步,配置effort和weight。按第2章的逻辑,瓶颈组提effort到high,weight提到2到3,其他组保持基线。targetSlack按需设置,一般给瓶颈组设一个略紧的目标。
第五步,跑优化,对比结果。重点看三件事:瓶颈组改善了没有、其他组恶化了没有、整体WNS和TNS变化如何。如果瓶颈组改善明显且其他组没大恶化,配置有效;如果瓶颈组没改善,回到第5章排查;如果其他组恶化严重,按5.2的方法平衡。
第六步,微调迭代。根据第五步的结果调整配置,再跑一轮。一般两到三轮就能收敛到比较理想的配置。迭代过程中记录每轮的配置和结果,形成配置-效果的对应关系,方便后续项目复用。
这套流程的核心逻辑是“先看后调、小步迭代、关注副作用”。path group的配置没有放之四海而皆准的最优解,每个设计的瓶颈分布不同,最优配置也不同。但有了这套框架,至少能保证调整是有依据的、效果是可衡量的,而不是凭感觉瞎调。
最后分享一个我在多个项目里验证过的小技巧:把path group的配置和时序结果做成一张对照表,项目结束后归档。下次遇到类似结构的设计,直接拿这张表做起点,能省掉大量试错时间。这张表积累得越多,path group的配置就越有章可循,从“调参玄学”变成“工程方法”。