导航提示

左侧边栏提供全文目录导航,点击即可跳转。以下是各章节概览:
入门:总览 → 快速上手 → 算法框架 → 数据结构  |  算法:粗化 → 初始划分 → 细化  |  约束:约束体系 → 时序驱动详解  |  集成:COCP/V-Cycle → API → 参数 → FAQ

1. 模块总览与定位

Partition 模块是 EDIF_Part 项目中负责多片 FPGA 自动化逻辑分割的核心算法引擎。它接收一个以超图(Hypergraph)形式建模的电路网表,在满足资源容量、拓扑连通、固定分配等多种约束的条件下,将电路节点分配到不同的 FPGA 块上,使得跨片连线数(Cut Size)最小,同时兼顾时序质量。

输入 网表 + 约束 Partition 模块 粗化 → 初始划分 → 细化 COCP / V-Cycle 后处理 多约束感知 + 时序驱动 输出 节点 → FPGA 映射 graph + fpga + PartitionParams → parts[]
Partition 模块在整体流程中的定位
设计哲学

Partition 模块采用 V-型多级框架(Multilevel Paradigm),即「粗化缩小 → 初始求解 → 逐层细化还原」。这种将大规模 NP-hard 问题分而治之的策略,能在可接受的时间内产出高质量解。通过多候选解并行探索、COCP 和 V-Cycle 后处理等机制进一步提升解的质量。

模块源码结构

src/partition/ 目录结构
partition.h / .cpp          # 主入口与流程控制
defs.h                      # 核心数据结构定义(graph, fpga, PartitionParams 等)
coarsen.h / .cpp            # 多层粗化引擎(MultilevelCoarsener)
initial.h / .cpp            # 初始划分(Initial)
tools.h / .cpp              # 工具函数(并查集、约束校验等)
refine/
  RefinementFacade.h/.cpp   # 细化阶段门面类(Refinement)
  core/
    RefineTypes.h           # 细化基础类型(Gain, NetPartition, PartitionState)
    RefinementRunTypes.h    # 候选解管理(CandidateBuffers, LevelWorkset)
    RefinementContext.h     # 配置与会话上下文
  engine/
    GainEvaluator.h/.cpp    # 增益计算引擎
    MoveApplier.h/.cpp      # 移动执行与回滚
  bucket/
    MoveBucket.h            # 增益桶(PerPart / Global 两种)
    PerPartBucket.cpp       # 分区级增益桶实现
    GlobalBucket.cpp        # 全局增益桶实现
  pipeline/
    CandidatePoolService    # 并行候选解批处理
    CandidateSelector       # 最优解选择
    CandidateProjection     # 层间投影与拓扑重映射
    StrategyRunner          # 策略执行驱动
    StrategyPlanner         # 策略选择规划
    TimingMetricService     # 时序度量服务
    FPGARemapper            # FPGA 编号拓扑优化
  strategy/
    IRefineStrategy.h       # 策略抽象接口
    StrategyFactory         # 策略工厂
    FM / PM / DSFM / Greedy # 各细化策略实现

2. 快速上手(30 秒最小调用)

Step 1 — 构造 graph

填写你的网表:节点(nodes)、超边(nets)、展平索引(incident_nodes, incident_nets

Step 2 — 构造 fpga

填写目标硬件:资源容量(resources)、拓扑矩阵(topology)、距离矩阵(dist

Step 3 — 构造 PartitionParams

使用默认参数或按需调整(候选解数、线程数、策略开关等)

Step 4 — 调用 partition()

得到 parts[i],即节点 i 被分配到的 FPGA 块编号

C++#include "partition/partition.h"
#include "partition/defs.h"
using namespace std;

// 1. 构造超图(详见第 4 节数据结构)
graph finest;
// ... 填充 nodes, nets, incident_nodes, incident_nets ...

// 2. 构造硬件平台(划分块数由 resources.size() 决定)
fpga fpgas;
// ... 填充 resources, topology, dist ...

// 3. 使用默认参数
PartitionParams para;
para.constraints.has_fix    = false;
para.constraints.has_timing = false;

// 4. 调用
vector<int> parts;                                    // 输出
HSFullTiming::HSPartitionFlow pFlow;                   // 不用时序时传空对象
int ret = partition(finest, fpgas, parts, para, 8, pFlow);

if (ret == 1) {
    // 划分成功: parts[i] = 节点 i 归属的 FPGA 编号
    for (int i = 0; i < (int)parts.size(); i++)
        printf("Node %d -> FPGA %d\n", i, parts[i]);
} else {
    // 划分失败(通常因资源总量超出容量)
    printf("Partition failed\n");
}

3. 算法框架:多级超图划分

Partition 模块的核心算法是多级超图划分(Multilevel Hypergraph Partitioning),这是一种经典的「分而治之」策略,将大规模组合优化问题分解为三个阶段:

Coarsening 节点合并,图逐步缩小 Initial Partitioning Uncoarsening + Refinement 逐层还原并优化解 Finest Graph Coarsest Graph Optimized Solution 最粗层(几十~几百个节点) 全流程: 粗化(下行)→ 初始划分(谷底)→ 细化(上行) 后处理: COCP(粗化再优化)+ V-Cycle(迭代深度优化)
V-型多级超图划分算法框架

三阶段职责

粗化 (Coarsening)
  • 将高度连通的节点合并为超节点(Supernode)
  • 采用重边匹配(HEM)策略优先合并共享超边多的节点对
  • 逐层缩小图规模,直到节点数降至阈值
  • 保留层间映射表用于后续还原
初始划分 (Initial Partitioning)
  • 在最粗层图上生成多个多样化的候选解
  • 策略包括:随机分配、贪心生长、SPFA 扩展、全局生长、轮询生长等
  • 保证资源约束满足
  • 选出精英解进入细化阶段
细化 (Refinement)
  • 将候选解从最粗层逐层映射回最细层
  • 每层使用 FM/PM/DSFM/Greedy 等策略局部优化
  • 通过增益桶(Gain Bucket)驱动节点移动
  • 支持移动回滚,确保解只向更优方向前进

完整执行流程

partition() 处理约束 (fixed / region / group) 多线程并行调用 multilevel() × solution_num 每次使用不同的随机种子 Coarsening Initial Part. Refinement 收集所有候选解 & 指标 (Metrics) [可选] COCP 后处理粗化-细化 [可选] V-Cycle 迭代深度优化 多解评估 → 选择综合最优解 parts[] 输出
partition() 内部完整执行流程

4. 核心数据结构设计

4.1 超图模型:graph

graph 类是整个模块的核心负载,封装了超图的全部信息。它使用 CSR(Compressed Sparse Row)展平索引格式存储节点与超边的关联关系,以获得紧凑的内存布局和高效的遍历性能。

Node 0 w=1 Node 1 w=1 Node 2 w=1 Node 3 w=1 Net 0 Net 1 CSR 展平索引 0 1 1 2 3 incident_nodes: [0,1, 1,2, 1,2,3] Net 0: begin=0, size=2 → nodes [0,1] Net 1: begin=2, size=3 → nodes [1,2,3] incident_nets: [0, 0,1, 1] Node 0: begin=0, size=1 → nets [0] Node 1: begin=1, size=2 → nets [0,1] Node 2: begin=3, size=1 → nets [1] Node (资源向量 + CSR索引) Net (超边/线网)
graph 的 CSR 展平索引结构示意(4 节点,2 超边)
字段类型说明
nodesvector<node>所有节点。每个 node 包含 weightbegin(incident_nets 起始偏移)、size(关联超边数)、resources(资源向量,如 [LUT, FF, DSP, BRAM])
netsvector<net>所有超边。每个 net 包含 weight(割边权重)、begin(incident_nodes 起始偏移)、size(端点数)
incident_nodesvector<int>超边端点展平数组。通过 nets[i].beginnets[i].size 索引
incident_netsvector<int>节点关联超边展平数组。通过 nodes[i].beginnodes[i].size 索引
fixed_assignvector<int>固定分配约束。初始化全 -1;若节点 i 必须固定在某块,设为块号
region_fixedvector<bool>区域约束标记。若节点受区域约束则为 true
candidatesvector<set<int>>每个节点的候选 FPGA 集合(区域约束时有效)
communityvector<int>初始划分提示或粗化中间结果
关于 timingInfo 字段

graph.timingInfo 类型为 timing,保留了时序路径(TimingPath)、引脚 slack(pinSlack)等数据结构的定义,但在当前流程中已不参与细化阶段的时序评估。实际的时序驱动划分完全依赖外部传入的 HSFullTiming::HSPartitionFlow &pFlow 对象(详见第 9 节)。

4.2 硬件平台:fpga

字段类型说明
resourcesvector<VectorXi>每个 FPGA 块的资源容量向量(维度与 node.resources 一致)
topologyvector<vector<int>>连通性邻接矩阵。非零表示直连
distvector<vector<int>>最短跳数矩阵(可用 Floyd-Warshall 从 topology 推导)
maxDistvector<int>每个块允许的最大跳数
cutweights_assignmentvector<vector<int>>FPGA 对间的通道带宽配置
bound_constraintbool是否启用资源严格上下限
upper_resourcesVectorXi资源上限向量(需 bound_constraint=true)
lower_resourcesVectorXi资源下限向量
tdmEstimateHSIOTdmDelayTDM 延迟评估引擎(来自 sta 模块)
关键方法

computeCutWeight(g, parts) — 计算割边总权重  |  computeCutWeights(g, parts, cut_weights) — 计算完整的带 TDM 评估的割边矩阵  |  computeCutWeightsOld(g, parts, cut_weights) — 基础版本,不含 TDM 深度评估

4.3 参数配置:PartitionParams

PartitionParams 采用分层结构体设计,将参数按阶段分组。所有子结构体均支持 JSON 序列化(通过 nlohmann/json 的 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT 宏)。

PartitionParams PartitionFlowConfig COCP/V-Cycle开关 候选解保留数 PartitionConstraintConfig has_fix / has_region / has_io has_timing / force_topo CoarsenConfig level / coarsen_method large_net_threshold InitialPartitionConfig num_initial_solutions RefineStageConfig 策略开关 / 迭代参数 max_move / refine_iters TimingPartitionConfig 延迟模型 / 惩罚系数 slack 传播策略
PartitionParams 分层参数结构

4.4 评价指标:Metrics

字段类型说明
cutint跨 FPGA 超边总权重(核心指标)
tdmintTDM 拥塞指标
topoint拓扑违规罚分
violationint约束违反次数/权重
costdouble综合代价分数
worstSlackdouble最差时序冗余 (WNS)
maxHopint最大路由跳数
tdmDelayfloat最大 TDM 通信延迟

5. 粗化阶段详解

粗化阶段由 MultilevelCoarsener 类实现,负责将原始大图逐层收缩为更小的抽象图。核心思想是:将紧密连通的节点对合并为超节点,从而在不损失重要结构信息的前提下指数级缩小问题规模。

5.1 粗化策略

coarsen_method名称原理适用场景
1 推荐 重边匹配 (HEM) 遍历超边计算节点对合并得分,将多条超边中重复出现的邻居对权重累加后选最高分匹配。对输入顺序不敏感。 通用场景,默认选择
0 基础贪心匹配 同样基于邻居权重匹配,但不做去重累加:每条超边独立产生一组邻居配对。对输入顺序敏感,cut 差距可达数倍。 快速模式 (mode=2) 或测试对比
2 首次选择匹配 (First Choice) 在匹配得分计算上与 HEM 类似,但核心区别在于:已匹配到粗图节点(cluster)的邻居得分记入 matched_score_map(而非 score_map)。匹配时优先选择已形成的 clustermatched=true),允许将多个节点持续吸收到同一 cluster 中,不限制为两两配对。 COCP 粗化等需要更大粒度聚合的场景
三种方法的打分与合并差异

method=0:邻居得分不累加,同一条超边内同 cluster 不重复计分 → 节点对两两配对。
method=1:邻居得分全累加到 score_map,已匹配 cluster 也参与打分 → 节点对两两配对,但合并后可追加到已有 cluster。
method=2:已匹配 cluster 的得分单独记入 matched_score_map,且匹配时优先选择 cluster(即使分数相同也优先 matched)→ 允许多节点聚合成一个 cluster,形成更大粒度的超节点。

5.2 粗化流程

构建邻居关系

遍历超边,为每对邻居节点计算合并得分。大超边(> large_net_threshold)被跳过。

节点排序

按配置的 CoarsenOrder 策略排序:RANDOM(随机扰动)、DEGREE(按度数)、SIZE(按体量)、TIMING(按时序关键度)

贪心匹配

按排序顺序,每个节点尝试与得分最高的未匹配邻居合并。检查资源容量约束,确保合并后的超节点不超过单个 FPGA 的资源上限。固定节点不与非固定节点合并。

图收缩 (Contraction)

根据匹配结果构建新的粗图:合并节点、更新超边端点、删除被吞并的空超边。保存层间映射表。

停止条件

当节点数 < fpga_num × thr_coarsen_vertice 或达到 level 上限时停止。若单层缩减比低于 coarsening_ratio 也会提前停止。

5.3 关键数据结构

成员说明
graphs层次图栈:[0] = 最细层(原始图),[level] = 最粗层
maps层间映射表:粗层节点 → 细层节点
map2origins反查表:粗层节点 → 原始图节点
isolated_nodes孤立节点(无超边连接),在初始划分后单独分配
粗化阶段的约束处理

固定节点约束:固定节点只与具有相同固定归属的节点合并。区域约束:候选区域取交集,若交集为空则不合并。组约束:在粗化之前,同一组的节点已预先合并为单个超节点。

6. 初始划分阶段详解

初始划分由 Initial 类实现,在最粗层图上生成多个满足资源约束的候选解。这些解的多样性直接决定了最终优化的质量。

6.1 多策略生成

Initial::initialPartition() 会综合运用以下多种策略来生成初始解:

策略原理特点
随机分配将节点随机分配到资源可容纳的 FPGA 块探索解空间,增加多样性
贪心生长 (Grow)从种子节点出发,按增益逐步扩展到邻域局部质量较好
SPFA 扩展基于改进最短路径算法,考虑跳距代价适用于拓扑约束场景
全局生长所有分区同时扩展,均衡增长平衡性好
顺序填充按硬件块顺序依次填满简单直接
轮询生长 (Round-Robin)各分区轮流扩展一个节点均衡同步增长
拓扑约束划分考虑跳数限制的专用策略force_topo 场景

6.2 精英选择

生成 num_initial_solutions 个候选解后,按 cut 指标排序,仅保留前 num_best_initial_solutions 个精英解进入细化阶段。这既控制了细化阶段的计算量,又保证了进入细化的解具有较高的起点质量。

流程// Initial::initialPartition() 内部逻辑
for seed in [0, num_initial_solutions):
    switch (seed % num_strategies):
        case 0: randomPart()        // 随机
        case 1: greedyPart()        // 贪心
        case 2: progressiveMinCutPart()  // 最小割生长
        case 3: globalGrowPart()    // 全局生长
        case 4: sequentialGrowPart() // 顺序填充
        case 5: roundRobinGrowPart() // 轮询
        ...

// 按指标排序,保留精英
sort candidates by cut
retain top num_best_initial_solutions candidates

7. 细化阶段详解

细化阶段是整个划分流程中最核心的优化环节,负责将初始解逐层映射回原始图的过程中持续优化。细化采用 门面模式(Refinement Facade)设计,通过统一的 Refinement::refinement() 接口屏蔽内部复杂的策略调度细节。

7.1 整体架构

Refinement (门面) CandidateProjection CandidatePool StrategyRunner TimingMetric StrategyFactory (策略工厂) PM FM DSFM_S DSFM_M Greedy GainEvaluator (增益计算) MoveApplier (移动执行) MoveBucket (增益桶) PartitionState: parts[] + occupied_resources[] + NetPartition[]
细化阶段内部架构层次

7.2 细化策略对比

PM (Pairwise Matching FM) 默认开启

算法:对 FPGA 块对(pair)排序,每对独立执行 FM 细化。
特点:成对处理降低了搜索空间,收敛快。支持回滚到最佳状态。
桶类型:PerPartBucketSet(分区级增益桶)

FM (Fiduccia-Mattheyses) 默认关闭

算法:经典 K-way FM 增益桶驱动细化。收集所有边界节点,每次选取最大增益移动。
特点:全局视角,适合复杂拓扑。支持回滚。
桶类型:PerPartBucketSet

DSFM_S (Directly Summed FM - Single Bucket) 默认关闭

算法:使用全局统一增益桶,引入约束延迟机制(不可行移入暂存队列)。
特点:避免「corking effect」导致的质量损失。单一视角简化调度。
桶类型:GlobalMoveBucket

DSFM_M (Directly Summed FM - Multi Bucket) 默认关闭

算法:保留分区级桶,但实现「corking」— 不可行时持续弹出直到找到可行移动。
特点:兼顾分区感知与约束延迟。
桶类型:PerPartBucketSet

Greedy (网级贪心) 默认开启

算法:以超边(而非节点)为单位,尝试将边界超边的所有端点移至最优分区。
特点:即时提交,无回滚。速度快,适合快速收敛。
桶类型:无(直接评估)

HER (High-Effort Refinement) 默认关闭

算法:高努力细化策略,消耗更多计算资源以获得更高质量的解。
特点:适合对质量要求极高的场景。
桶类型:视配置而定

7.3 策略组合机制

细化阶段支持 primary + suffix 策略组合。每次细化会先运行 primary 策略(如 PM),再运行 suffix 策略(如 Greedy),形成「先精细优化,再快速清扫」的效果。

PrimarySuffix组合名适用场景
PMGreedyPM+Greedy默认组合,通用场景
FMGreedyFM+Greedy需要更全局的优化
DSFM_MGreedyDSFM_M+Greedy严格约束场景
PMHERPM+HER高质量要求
DSFM_SHERDSFM_S+HER约束严格+高质量

7.4 增益计算与移动机制

增益计算 (GainEvaluator)

增益(Gain)= 移动节点前后的割边权重差。GainEvaluatorCore 计算时综合考虑:

  • 割边增益:移动节点减少的跨块超边权重
  • 拓扑增益:减少的跳数违规罚分
  • IO 增益:TDM 拥塞改善量
  • 时序增益:关键路径 slack 改善(时序模式下)

移动执行 (MoveApplier)

MoveStateApplierCore 提供三种操作:

  • applyMoveToState() — 试探性移动(更新状态)
  • acceptMove() — 确认移动(更新 NetPartition 快照)
  • cancelMove() — 回滚移动(恢复状态)

回滚机制确保细化过程「只进不退」— 每轮 Pass 结束后回退到 Pass 内的最佳状态。

7.5 增益桶 (MoveBucket)

增益桶是 FM 系列算法的核心数据结构,提供 O(log n) 的最大增益节点选取。模块提供两种实现:

PerPartBucketSet(分区级桶)

每个目标分区维护一个独立的优先队列。选取时比较所有桶的顶部元素。

优点:天然隔离不同目标分区的候选,避免分区间的干扰。

使用者:FM, PM, DSFM_M

GlobalMoveBucket(全局桶)

所有目标分区共享一个统一的优先队列,每个元素携带目标分区信息。

优点:简化调度逻辑,便于实现约束延迟。

使用者:DSFM_S

7.6 细化流程:逐层展开

最粗层局部搜索

在初始划分结果上直接运行策略(不解层),快速改善粗粒度解的质量。

候选解裁剪

按指标评估,裁剪较弱的候选解(trimInitialCandidates),保留精英解。

逐层投影 + 细化

level-10,每层:1) 将候选解通过映射表投影到细层;2) 运行策略优化;3) 更新指标并选择最优解。

时序度量更新

时序模式下,每层细化后调用 TimingMetricService 更新 slack、延迟等时序指标。

8. 约束体系

Partition 模块支持多种物理约束,贯穿粗化、初始划分、细化全流程。所有约束标志集中在 PartitionConstraintConfig 中。

PartitionConstraintConfig 贯穿全流程的硬约束 has_fix has_region has_io has_timing force_topo max_hop

固定分配约束 (Fixed Assignment)

某些节点必须放在指定的 FPGA 块上,不能被移动。通过 finest.fixed_assign[node_id] = fpga_id 设置。

影响阶段: 粗化:固定节点不与非同固定归属节点合并 初始划分:固定节点优先分配到指定块 细化:固定节点不参与移动
// 通过名字兼容入口设置
fixed_assignment["cpu_core"] = {2, {}};
para.constraints.has_fix = true;

区域约束 (Region Constraint)

某些节点只能在指定的几个 FPGA 块中选择。通过 finest.candidates[node_id] 设置候选集合。

影响阶段: 粗化:候选区域取交集,空集则不合并 初始划分:仅在候选集内分配 细化:仅在候选集内选择目标分区
// 设置区域约束(通过名字前缀匹配)
fixInfo info;
info.fpgaNo = -2;  // -2 表示区域约束
info.id = {{0,0,0}, {0,0,1}};  // 候选块 0 和 1
fixed_assignment["mem_ctrl"] = info;
para.constraints.has_region = true;

组约束 (Group Constraint)

某些节点必须被分到同一个 FPGA 块。在粗化之前,同组节点已预先合并为单个超节点。

处理方式: 粗化前:compute_group_constrain() 合并同组节点 划分完成后:展开超节点,恢复原始节点
// 设置组约束
group_assignment["group_a"] = {"node_1", "node_2", "node_3"};

IO 约束 (IO / Bandwidth Constraint)

确保跨 FPGA 连线不超过通道带宽限制。影响增益计算:割边代价考虑带宽倒数权重,而非简单计数。

影响阶段: 粗化:间接影响(通过 TDM 通道约束) 细化:增益计算中引入 IO 代价权重 评估:使用 tdmEstimate 计算精确 TDM 延迟

拓扑约束 (Topology Constraint)

强制满足 FPGA 间的跳数限制,不允许超出 max_hop 的分配。

影响阶段: 入口检查:校验固定约束与拓扑约束是否冲突 初始划分:使用 topology-aware 策略 细化:移动时检查跳数合法性 投影:FPGARemapper 优化 FPGA 编号映射

时序约束 (Timing Constraint)

启用时序感知划分,优化关键路径的 slack。依赖外部传入的 pFlowHSFullTiming::HSPartitionFlow)对象,由 sta 模块预先生成。详见下方第 9 节。

影响阶段: 流程入口:关闭非时序 COCP,使用独立时序 COCP 轮次 粗化:保留 timingInfo 数据用于映射 细化:关闭 PM 策略,使用 pFlow 评估时序指标 V-Cycle:每层结束后更新 pFlow 中的割边延迟
para.constraints.has_timing = true;
// pFlow 由 sta 模块解析生成:
// sta::parse(pFlow, circuitFolder);
// sta::buildNextObjInfo(pFlow);

9. 时序驱动划分详解

时序驱动划分是 Partition 模块中最复杂的运行模式。与纯 cut 优化不同,时序模式需要在减少割边数的同时兼顾关键路径的时序质量(Worst Negative Slack, WNS)。当前实现的核心机制是通过 HSFullTiming::HSPartitionFlow(简称 pFlow)对象与 sta 模块交互,而非模块内嵌的时序评估器。

9.1 时序数据的来源与传递

sta 模块 parse() + buildNextObjInfo() pFlow HSPartitionFlow 为每个候选解维护 LocalData 割边延迟矩阵 + 时序图 TDM 估计 + slack 查询 TimingMetricService 查询指标写入 Metrics
时序数据的传递路径:sta 模块 → pFlow → TimingMetricService → Metrics

pFlow 是由外部 sta 模块生成的时序分析上下文,内部为每个候选解维护一个独立的 LocalData 对象,负责:

9.2 时序模式下的流程调整

当时序模式开启(has_timing = true)时,partition() 内部会做以下关键调整:

调整项具体行为原因
候选解数使用 timing_hold_solution_num(默认 1)代替 hold_solution_num时序评估代价高,减少候选数控制耗时
并行策略时序模式下不拆分线程(thread = 1),每个 pFlow 需独立状态pFlow 的 LocalData 不支持并发写入
COCP 两阶段先以 has_timing=false 跑一轮 COCP(COCP_on=2),获得好的 cut 基础后再开启时序跑 V-Cycle时序优化需要较好的初始 cut
IO + 拓扑预处理若同时有 IO/区域/拓扑约束,先关闭这些约束跑一轮纯 cut,再恢复时序跑 V-Cycle多约束同时生效可能导致无解
细化策略V-Cycle 内关闭 PM(enable_PM = false),关闭混合细化PM 的成对处理不利于时序优化

9.3 TimingMetricService 的工作机制

初始化(最粗层)

initializeCoarsestLocalData():为每个候选解创建 LocalData,将粗图解映射回原始图后设置割边权重,构建时序边并执行首次时序更新。写入 cost(关键割边数)、worstSlackmaxHop 到 Metrics。

逐层细化后更新

每层细化完成后调用 fillMetricsFromPartitionFlow():从各候选解的 LocalData 提取最新 getMinSlack()getCriticalCut()getWorstIndex()getTopkMinSlackRatio() 写入 Metrics。

TDM 延迟刷新

refreshCutDelaysFromTdm():当 IO 带宽配置非空时,从 fpgas.tdmEstimate 获取最新的 TDM 割边延迟矩阵,更新到各候选解的 LocalData 中。

最细层清理

到达 level 0(原始图)后调用 pFlow.cleanOurPartition() 清理中间状态。

9.4 割边延迟矩阵

每对 FPGA 之间的割边延迟由 buildCutDelayMatrix() 计算:

9.5 时序解的评估与选择

时序模式下,CandidateSelector::chooseBestCandidate() 的选择逻辑变为:

  1. 优先选 worstSlack 最好(最大)的解 — 确保关键路径时序质量
  2. 在 slack 相近的解中,选 cost(关键路径割边数)更小的
  3. fewer_cuts 标志影响选择权重:当整体割边偏少时倾向选更小 cut

9.6 时序配置参数速查

参数默认值说明
timing.extra_delay_cut100.0FPGA 间割边固定延迟(ns),无 TDM 时使用
timing.extra_delay_cut_die2.0Die 间割边附加延迟
timing.timing_hold_solution_num1时序模式保留候选解数(通常 ≤ 4)
timing.guardband_flag1启用悲观时序保护带
timing.enable_partition_HSFulltiming1启用 HSFullTiming 时序算法
timing.timing_exp_factor2.0slack 惩罚指数因子
timing.path_timing_factor1.0关键路径惩罚权重

10. 完整流程控制(COCP / V-Cycle)

10.1 主流程模式

模式flow.mode说明
标准模式0完整流程:多候选解 → COCP → V-Cycle
快速模式2关闭 COCP、V-Cycle、PM 策略,使用贪心粗化。优先获得可行解。

10.2 COCP(Coarsening Optimization Candidate Processing)

COCP 是一种后处理优化机制:以当前最优候选解的分区信息作为社区提示(community hint),重新执行一轮粗化-细化,从而在已有解的基础上进行更深层次的结构优化。

COCP 粗化

使用当前最优解作为 community 提示,执行受引导的粗化(倾向于保留现有分区的社区结构)。

重新初始划分

在最粗层生成新的候选解,同时将 community 方案也作为候选。

细化

对所有候选解(包括新初始解和 community 方案)执行完整细化。

COCP 与时序模式的互斥

当时序模式 (has_timing) 开启时,COCP 会先在非时序模式下执行一轮以获得较好的 cut 基础,然后再切换到时序模式执行 V-Cycle。这是通过 COCP_on = 2 标志控制的。

10.3 V-Cycle 迭代优化

V-Cycle 是多级划分的经典增强技术:以当前最优解为起点,重复执行完整的「粗化 → 初始划分 → 细化」流程,每次都可能发现更优的解。

V-Cycle 伪代码for iter in [0, V_Cycle_run):
    community = candidate_parts[best]     // 以当前最优解为社区提示
    mc = MultilevelCoarsener(finest, ...)  // 新建粗化器
    mc.multilevelCoarsening(finest)        // 受引导粗化
    initial.initialPartition(mc, ...)      // 重新初始划分
    refinement.refinement(mc, ...)         // 细化
    candidate_parts[0] = best result      // 更新最优解

10.4 候选解选择 (CandidateSelector)

在多个候选解中,CandidateSelector::chooseBestCandidate() 综合以下指标选择最优解:

11. 层次化(多层级)划分

前面章节描述的 partition()扁平划分:它把所有 FPGA 视作平级节点,目标是把超图切成 K 块。而真实的多片 FPGA 系统具有物理层级——机柜(Rack)→ 簇(Cluster)→ 板(Board)→ FPGA,命名形如 R*.C*.B*.F*,其下还可细分 Die。同板 FPGA 之间的互连带宽远大于跨板,资源也需按层级管控。层次化(多层级)划分就是为这种场景设计的递归外壳。

「多级」vs「多层级」——不要混淆

本文有两个相近术语,含义完全不同:

  • 多级划分(Multilevel)=第 3 章的扁平内算法:粗化 → 初始划分 → 细化。它解决「在一个平级的 K 块上怎么分得好」。
  • 多层级划分(Hierarchical)=本章:按硬件物理层级 Rack → Cluster → Board → FPGA 自顶向下分治递归。它解决「分给哪个物理位置」。

二者关系是外层递归 / 内层多级:层次化的每一层内部,调用的仍是完整的扁平 partition()

11.1 动机与定位

扁平 partition() 有两个局限:① 它无法表达「同板近、跨板远」的层级拓扑,只能用一个统一的最短跳数矩阵近似;② 它无法按物理层级分层控制资源上限。层次化划分通过把硬件建模成一棵递归树,逐层分割、逐层约束,最终让每个电路节点落到一个叶子 FPGA,并记录其层次路径。

Rack R0 Cluster C0 Cluster C1 Board B0 Board B1 Board B2 Board B3 F0 F1 F2 F3 F4 F5 F6 F7
硬件物理层级树:Rack → Cluster → Board → FPGA(叶子),对应命名 R0.C0.B0.F0 等

11.2 层次数据结构

层次结构定义在 defs.h,核心是一个递归类 hierarchy:每个节点既描述本层资源与拓扑,又通过 contents 持有子节点,天然形成一棵与物理硬件同构的树。

类型 / 字段所在含义
enum class HierarchyTypedefs.h节点类型:RACK / CLUSTER / BOARD / FPGA / DIE
hierarchy::typedefs.h本节点的层级类型
hierarchy::fpgas0defs.h聚合前的原始资源快照(硬件物理容量上限)
hierarchy::fpgasdefs.h当前资源(含 reset 后的算法目标 + 本层拓扑约束)
hierarchy::contentsdefs.h子节点列表(递归构成下一层)
hierarchy::topology_linksdefs.h本层级的物理拓扑链路(HierarchyLink
hierarchy::alias / node_id / parent_node_id / children_node_ids / alias_to_node_iddefs.h别名(如 R0.C1)与节点 ID 索引
HierarchyLinkdefs.h两 FPGA 端点间的物理连接:left/right 端点、is_mgtchannel_capacityhio_channels / mgt_channelscable
HierarchyLinkEndpointdefs.h链路端点:node_iddie_idsocketfpga_alias
双层资源设计:fpgas0fpgas

这是层次化最关键的特殊设计。fpgas0 保存硬件真实物理容量(不可突破的天花板),fpgas 保存算法实际使用的资源目标(经 reset 校准后的值)。二者解耦,使得算法可以在不违反物理上限的前提下,按层级灵活分配资源余量。详见 11.4。

11.3 算法思路:自顶向下分治

层次化划分的入口是 partitionHierarchyGraph()(partition.h)。它按 hierarchy_root 定义的树自顶向下递归:在每一层调用扁平 partition() 把当前子图切成若干份,再用 separateGraph() 按结果拆成子图,递归交给下一层,直到叶子 FPGA。

递归伪代码// partition.cpp :partitionHierarchyNode(单节点递归)
int partitionHierarchyNode(graph &cur, const hierarchy &node, prefix, ...) {
    int part_num = node.contents.size();     // 本层要切成几份
    // 基线:只剩 1 份或已是叶子 → 把当前路径回填到 node_paths
    if (part_num == 1 || node.contents.empty()) {
        assignLeafPaths(cur, prefix, parts, node_paths);  // node_paths[i] = [rack,cluster,board,fpga]
        return 1;
    }
    // 递归:先扁平划分当前层,再切图,再对每个子节点递归
    partition(cur, node.fpgas, parts, para, thread, pFlow);   // 内层仍是完整多级划分
    separateGraph(cur, node.fpgas, parts, child_graphs, id2node);
    for (int c = 0; c < part_num; ++c)
        partitionHierarchyNode(child_graphs[c], node.contents[c], prefix + [c], ...);
}

separateGraph(finest, fpgas, parts, sub_graphs, id2node) 负责把划分结果落地:遍历所有节点与超边,按 parts 归入对应子图,并重建每个子图的 incident_nets 索引(id2node 记录子图节点到原图节点的映射,保证递归回溯时身份不丢)。最终每个 graph node 都获得一条层次路径,写入 node_paths[i]

finest 整图(入口) partitionHierarchyGraph(finest, hierarchy_root, …) ① Rack 层:partition() → separateGraph() ⇒ 切出 N 个 Cluster 子图 对每个 Cluster 子图递归 ② Cluster 层:partition() → separateGraph() ⇒ 切出 N 个 Board 子图 对每个 Board 子图递归 ③ Board 层:partition() → separateGraph() ⇒ 落到 FPGA 叶子 FPGA 叶子:assignLeafPaths() 回填 node_paths[i] = [rack, cluster, board, fpga]
自顶向下分治:四个层级依次递归,每层 partition()+separateGraph() 的输出子图作为下一层输入,到叶子回填路径
内层 / 外层职责分离

层次化(外层)只决定「每个子图分给哪个物理子节点」,扁平 partition()(内层)只决定「在当前这组 FPGA 上怎么切得割边最小」。因此前面所有章节(粗化、初始划分、细化、COCP/V-Cycle、时序)的能力在每一层都完整可用。

11.4 资源上限分层设置

层次化场景下,资源约束必须按层级分级设置:顶层不能直接占满所有叶子的物理容量,否则下层无平衡空间。本项目用「两层容量 + 自底向上 reset + 分布式 slack 衰减」三件套解决。

第一步:自底向上 reset(resetHierarchyResourcesFromLeaves,partEDIF.h)。先用 collectLeafResources() 把所有叶子 FPGA 的 fpgas0(物理容量)平铺成一维列表,交给 checkResources() 计算平衡后的目标值,再写回叶子并逐级聚合到上层 fpgascheckResources() 的核心是找瓶颈资源维度并按比例设定目标:

checkResources 核心逻辑(partEDIF.cpp)// 1. 找需求/容量比最高的资源维度作为瓶颈
int index = 0;
double ratio = required[0] / (double)total[0];
for (int r = 1; r < R; ++r)
    if (required[r] / (double)total[r] > ratio) { index = r; ratio = required[r]/total[r]; }
// 2. 按瓶颈比率和用户设定推导目标 FPGA 数与每块资源上限
int target_fpga_num = max(1, (int)ceil(ratio * f.resources.size() * fpgaResourceRatioSet));
// fpgaResourceRatioSet == 0 表示自动估计

第二步:分布式 slack 衰减(aggregateHierarchyResourcesWithDistributedSlack,tools.h)。并非所有资源维度都需要分布式限制——只有总容量超过实际需求的维度才需要。流程为:getDistributedResourceDims() 识别这些维度 → computeHierarchySlacks() 计算每维 slack(slack = 总容量 / 需求上界,上限 kMaxHierarchyResourceSlack = 2.0)→ 自底向上聚合时对分布式维度施加渐进式 slack 衰减

fpgas0(物理容量上限) 叶子 FPGA 的真实硬件容量(不可突破) fpgas(reset 后算法目标) 瓶颈维度按比率收紧,留出平衡余量 距叶子越远(上层)→ slack 衰减越强 → 上层资源限额越贴近真实需求,避免过度预留 slack 衰减方向 ↑
两层容量:物理上限 fpgas0 不变,算法目标 fpgas 自底向上 reset 并按层衰减
为什么不直接用物理容量做目标

若上层节点直接占满所有叶子的物理容量,下层就没有任何腾挪空间,极易导致「上层合法、下层无解」。引入 reset 把目标收紧到瓶颈维度、并用分布式 slack 让余量自底向上递减释放,保证每一层都有平衡空间,从根源上缓解多层级资源不可行问题。

11.5 超边去重

网表中常存在大量平行超边——端点集合完全相同的多条 net(例如同一组宏之间的多比特信号被拆成多条线)。它们会让粗化阶段的匹配打分重复计算,也干扰后续时序/路由评估。粗化器提供 MultilevelCoarsener::deduplicateHyperedges(finest)(coarsen.h)在粗化前压缩这类冗余。

算法(coarsen.cpp):① 为每条超边计算特征哈希(ContractedHyperedgeInformation.hash,含引脚数 size);② 按 (hash, size) 分桶排序;③ 桶内用 check_if_hyperedges_are_parallel()精确结构比对(逐端点比较 incident_nodes,仅当哈希相同且端点序列完全一致才认定平行);④ 合并平行超边——权重累加到保留边,重复边标记为 invalid 跳过。该步配合 parallelContraction()(TBB 并发收缩)使用。

超边去重小例// 两条 net 都连接节点 {0, 1, 2},是平行超边
net A: incident = [0,1,2], weight = 1.0
net B: incident = [0,1,2], weight = 1.0
          ↓ deduplicateHyperedges
net A: incident = [0,1,2], weight = 2.0   // 合并,权重累加
net B: 标记为 invalid,跳过                // 图规模下降,打分不再重复
dedup_root_graph:编号不变的去重图

partitionHierarchyGraph() 的可选出参 graph *dedup_root_graph 返回根层去重后的超图,且节点编号保持不变。因为编号不变,时序评价与路由需求评估可以直接复用这张更小的图,既加速又保证与原节点身份对齐。

11.6 时序评价(跨 FPGA 拓扑感知)

层次化把硬件拍平后,跨 FPGA 通信的代价取决于 FPGA 对的物理距离。本项目的时序评价由 TimingMetricService(构建延迟矩阵)、HSTimingLocalData(分区级时序状态)和 HSTimingDelta(增量评估器)协同完成,最近的提交又加入了拓扑距离去重图两项增强。

API所在作用
TimingMetricService::buildCutDelayMatrix(fpgas, fpga_num, default_cut_delay)TimingMetricService.h基于拍平后的 fpgas 拓扑构建 FPGA 对割边延迟矩阵(vector<vector<float>>
refreshCutDelaysFromTdm(...)TimingMetricService.h从 TDM 分配结果刷新分区间割边延迟
HSTimingLocalData::m_fpgaDistancesHSTimingLocalData.hFPGA 对最短拓扑距离矩阵 [fromPart][toPart]
setFPGADistances(...) / getFPGADistances()HSTimingLocalData.h下发 / 读取拓扑距离矩阵
getEdgeFPGADistance(edgeId)HSTimingLocalData.h查询某条边跨越的 FPGA 最短拓扑距离
HSTimingDelta::getFPGADistance / getOldFPGADistanceHSTimingDelta.hdelta 视图下当前 / 基准拓扑距离(试探移动时增量评估)
evaluatePartitionTimingComparison(finest, fpgas, parts, pFlow, topk)tools.h划分完成后对 top-K 候选解做时序对比评估

拓扑距离 vs 简单 hop。 简单 hop 只数跨越的 FPGA 跳数;拓扑距离则结合物理拓扑矩阵给出更贴合真实延迟的距离。时序引擎用拓扑距离为每条 timing edge 估延迟,使关键路径评估更准确。

去重图(net + FPGA pair 去重)。 同一条 net 在同一 FPGA pair 上可能被重复计入关键割线 slack。HSTimingLocalData / HSTimingDelta 维护按 net + FPGA pair 去重的最差 slack bucket 统计,避免重复计数导致评估偏置,让候选解排序更可靠。

增量时序评估。 HSTimingDelta 为一次候选分区变更维护独立的差分账本而不改写基准状态:用 traceInfohop / slack / preEdgeId / edgeId)记录单步传播轨迹,updateTimingEdge() 增量更新,并支持 rollbackUndo()。最终把 cut delays + fpga distances 下发到每个候选的 local data 后即可快速评价。

flattenHierarchy 叶子拍平为 flat fpgas buildCutDelayMatrix FPGA 对割边延迟矩阵 setCutDelays + setFPGADistances HSTimingLocalData 每候选时序状态 HSTimingDelta 试探移动 / 增量账本 net+FPGA pair 去重 关键割线 slack bucket 候选解排序 worst slack / top-K 拓扑距离矩阵 m_fpgaDistances 贯穿全流程:buildCutDelayMatrix 用拓扑算延迟,delta 评估用 getFPGADistance 取距离。
拓扑感知时序评价流程:拍平 → 割边延迟矩阵 → 下发 → 增量评估 → 去重排序

11.7 端到端编排

层次化的端到端入口是 partHierarchyOnly()(partEDIF.h),它串联起建模、图构建、资源校准、递归分割与可选输出:

建模 + 图构建

解析 EDIF 与约束,构造最细层超图 finesthierarchy_root(含 fpgas0 物理容量)。

资源校准

resetHierarchyResourcesFromLeaves() 自底向上 reset 各级 fpgas 目标(见 11.4)。

递归分割

partitionHierarchyGraph() 自顶向下分治,每层内部跑完整扁平 partition(),输出 node_paths

时序评价(可选)

flattenHierarchyToFpgasForRouting() 拍平 → buildCutDelayMatrix + 拓扑距离 → 增量时序评估(见 11.6)。

输出产物

writeHierarchyPartitionArtifacts() 写入分配 JSON(entries)与辅助 JSON(fpga_stats + 各层 cut 矩阵)。

flattenHierarchyToFpgasForRouting(hierarchy_root, flat_fpgas, flat_fpgas0, path_to_fpga, fallback_capacity, delay_lib_path) 是层次化与扁平世界的桥梁:它把所有叶子 FPGA 拍平成一组平级的 flat_fpgas(含拓扑、容量、TDM 互联),并建立层次路径到全局 FPGA ID 的映射 path_to_fpga,供时序与路由评估复用前面章节的扁平算法。

11.8 层次化 API / 产物速查

API所在说明
partitionHierarchyGraph(finest, hierarchy_root, para, thread, node_paths, pFlow, cut_records?, dedup_root_graph?)partition.h递归分割主入口;cut_records 记录每层 cut 指标与 cut 权重矩阵,dedup_root_graph 返回编号不变的去重根图
separateGraph(finest, fpgas, parts, sub_graphs, id2node)partition.h按分区结果把超图拆成子图,重建 incident_nets
HierarchyPartitionCutRecorddefs.h单层分割的 cut 指标与 cut_weights 矩阵记录
resetHierarchyResourcesFromLeaves(...)partEDIF.h自底向上资源校准(11.4)
writeHierarchyPartitionArtifacts(...)tools.h输出 parts(entries)+ aux(fpga_stats + 各层 cuts)两个 JSON
partHierarchyOnly(...)partEDIF.h端到端编排(建模→校准→递归分割→输出)
flattenHierarchyToFpgasForRouting(...)partEDIF.h叶子拍平 + TDM 互联初始化(层次↔扁平桥梁)
对应实现提交

本章覆盖 tsb-19 自 6/1 起的层次化工作:9f1cbf2(层次结构与递归)、4a1c1d1(reset 容量与资源报告)、ae13f5f(超边去重与分区后时序评估)、da819b4(路由需求评估)、ddc2987(去重图与拓扑距离)。

12. API 接口与调用方法

12.1 主入口(纯抽象版)

定义在 partition.h,直接操作图级别的约束:

C++int partition(
    graph &finest,                                  // [输入] 超图网表
    fpga &fpgas,                                    // [输入] 硬件平台
    vector<int> &parts,                             // [输出] 节点->FPGA 映射
    const PartitionParams &para,                     // [输入] 算法参数
    int thread,                                      // [输入] 线程数
    HSFullTiming::HSPartitionFlow &pFlow            // [输入] 时序上下文
);
// 返回值: 1 = 成功, -1 = 失败

12.2 兼容入口(名字级约束适配器)

提供了从名字级约束到图内节点 ID 的自动转换:

C++int partition(
    graph &finest,
    fpga &fpgas,
    vector<int> &parts,
    const PartitionParams &para,
    int thread,
    flat_hash_map<string, fixInfo> &fixed_assignment,        // 固定/区域约束
    unordered_map<string, vector<string>> &group_assignment,  // 组约束
    flat_hash_map<string, int> &name_map,                     // 名字->ID 映射
    HSFullTiming::HSPartitionFlow &pFlow
);
两个入口的关系

兼容入口会先将 fixed_assignment 转换为 finest.fixed_assign,将区域约束转换为 finest.candidates,将组约束通过 compute_group_constrain() 预聚合,然后调用纯抽象版入口。

12.3 完整调用示例

示例 1:纯图分割(无约束)

C++#include "partition/partition.h"
using namespace std;

graph g;
// ... 填充 nodes, nets, incident_nodes, incident_nets ...

fpga fpgas;
// ... 填充 resources, topology, dist ...

PartitionParams para;
para.refine.num_best_initial_solutions = 10;

vector<int> parts;
HSFullTiming::HSPartitionFlow pFlow;
int ret = partition(g, fpgas, parts, para, 8, pFlow);

示例 2:有固定分配约束

C++flat_hash_map<string, fixInfo> fixed_assignment;
flat_hash_map<string, int> name_map;
unordered_map<string, vector<string>> group_assignment;

name_map["cpu_core_0"] = 42;
fixed_assignment["cpu_core_0"] = {2, {}};  // 固定到块 2

para.constraints.has_fix = true;

int ret = partition(g, fpgas, parts, para, 8,
                    fixed_assignment, group_assignment, name_map, pFlow);

示例 3:使用时序数据

C++HSFullTiming::HSPartitionFlow pFlow;
// pFlow 由 sta 模块解析生成(需外部调用 sta::parse / sta::buildNextObjInfo)

para.constraints.has_timing = true;
para.timing.timing_hold_solution_num = 4;

int ret = partition(g, fpgas, parts, para, 8, pFlow);

示例 4:验证划分结果

C++// 计算割边权重
int cut = fpgas.computeCutWeight(g, parts);
printf("Cut = %d\n", cut);

// 计算完整指标(含 TDM)
vector<vector<int>> cut_weights(fpgas.resources.size(),
    vector<int>(fpgas.resources.size(), 0));
Metrics m = fpgas.computeCutWeights(g, parts, cut_weights);
printf("Cut=%d TDM=%d Topo=%d Violation=%d MaxHop=%d\n",
       m.cut, m.tdm, m.topo, m.violation, m.maxHop);

13. 参数配置速查

13.1 常用参数

参数路径默认值说明调优建议
flow.COCP_on1是否启用 COCP 后处理开启可提升质量,关闭可加速
flow.V_Cycle_on1是否启用 V-Cycle开启可显著提升质量
flow.V_Cycle_run2V-Cycle 迭代次数1~3 次性价比较好
flow.hold_solution_num4非时序模式保留候选解数2~8
coarsen.level30最大粗化层数通常不需修改
coarsen.coarsen_method1粗化方法(1=HEM)推荐 1(重边匹配)
coarsen.large_net_threshold200大超边过滤阈值设小可过滤更多大超边
initial.num_initial_solutions64初始候选解数32~128,越多越好但更慢
refine.num_best_initial_solutions8进入细化的精英解数4~16
refine.max_move1000单 Pass 最大移动次数增大可更充分优化
refine.refine_iters1每层细化迭代轮数1~3
refine.enable_PMtrue启用 PM 策略推荐开启
refine.enable_Greedytrue启用 Greedy 策略推荐开启
refine.enable_FMfalse启用 FM 策略按需开启
constraints.max_hop-1最大跳数(-1 自动估计)自动估计即可

13.2 时序相关参数

参数路径默认值说明
timing.extra_delay_cut100.0FPGA 间割边附加延迟(ns)
timing.extra_delay_cut_die2.0Die 间割边附加延迟
timing.timing_exp_factor2.0slack 惩罚指数因子
timing.path_timing_factor1.0关键路径惩罚系数
timing.timing_hold_solution_num1时序模式保留候选解数
timing.has_timing_propogate1slack 传播模式(0/1/2)
timing.guardband_flag1是否启用时序保护带

14. 常见问题与调优

Q1: 资源向量维度必须一致吗?

是的。node.resourcesfpga.resources[i]fpga.upper_resourcesfpga.lower_resources 的维度必须相同,代表同一组资源类型(如 LUT, FF, DSP, BRAM)。

Q2: 不需要时序优化时,pFlow 怎么传?

传一个默认构造的空 HSFullTiming::HSPartitionFlow 对象即可。确保 para.constraints.has_timing = false

Q3: name_map 是必须的吗?

如果不需要固定分配约束(has_fix=false)和区域约束(has_region=false),name_map 可以为空。否则必须包含约束中引用的所有节点名到 ID 的映射。

Q4: topology 和 dist 需要手算吗?

topology 是邻接矩阵,需要你提供。dist 可以用 Floyd-Warshall 从 topology 推导。如果不需要拓扑约束,可以不填 topology 和 dist,并将 force_topohas_io 设为 false。

Q5: 划分结果质量不满意怎么办?

调优优先级

按以下顺序调整参数,每步观察效果:

  1. 增加候选解数initial.num_initial_solutions = 128 或更高
  2. 开启 V-Cycleflow.V_Cycle_on = 1flow.V_Cycle_run = 3
  3. 开启 COCPflow.COCP_on = 1
  4. 增加细化迭代refine.refine_iters = 2
  5. 增大移动步数refine.max_move = 2000
  6. 尝试其他策略:开启 FM(refine.enable_FM = true)或 DSFM
  7. 增加线程:更多线程 = 更多并行候选解探索

Q6: 如何选择合适的粗化方法?

推荐使用默认的 HEM(coarsen_method=1)。它通过权重合并去重,显著降低了对输入顺序的敏感性。基础贪心(coarsen_method=0)仅在快速模式或特定测试中使用。

Q7: 时序模式和纯 cut 模式有什么区别?

方面纯 Cut 模式时序模式
优化目标最小化割边权重在 cut 可接受前提下优化 slack
候选解数hold_solution_numtiming_hold_solution_num(通常更少)
增益计算仅割边增益割边 + slack 惩罚
粗化策略SIZE/RANDOM可选用 TIMING 排序
需要额外输入是(pFlow 时序数据)