Tracking Endpoint Slack Across Flow Steps

Tracking Endpoint Slack Across Flow Steps#

When working on an optimization (resizing, buffering, CTS, repair timing, …) it is useful to see how the slack of each timing endpoint moves from one flow step to the next, not just how WNS/TNS change. ORFS can record the setup and hold slack of every endpoint at the end of every flow step (1_synth, 2_1_floorplan, …, 3_3_place_gp, …, 6_final) and compare any two steps, including a scatter plot of slack (x: earlier step, y: later step).

Recording#

Set REPORT_ENDPOINT_SLACK=1:

cd flow
make DESIGN_CONFIG=designs/nangate45/gcd/config.mk REPORT_ENDPOINT_SLACK=1

Every step then writes $(REPORTS_DIR)/<step>_endpoint_slack.json, e.g. 3_3_place_gp_endpoint_slack.json. The snapshot is taken by write_endpoint_slack in flow/scripts/util.tcl, called from orfs_write_db so the step name is the name of the .odb the step writes. It works in the single-process flow/scripts/flow.tcl flow as well. Steps that just copy their input (orfs_copy_db, e.g. 5_3_fillcell without fill cells) re-time the design if it is loaded, or else copy the previous step’s snapshot. Intermediate .odb files written through orfs_write_db (e.g. CTS save_progress) also get a snapshot; *-failed ones don’t.

A placed step is timed with the parasitics OpenROAD has for it: a bare estimate_parasitics estimates from the global routes when there are any, else from placement, and does nothing once read_spef has read the extracted parasitics:

Steps

Parasitics

before placement, and 3_1_place_gp_skip_io while the pins are unplaced

none

placed, before global route

placement

global route and later

global_routing

6_final

spef: the extracted 6_final.spef, as in 6_finish.rpt (global_routing on platforms without RCX_RULES, or with SKIP_DETAILED_ROUTE=1)

The parasitics model is recorded in each snapshot and shown by endpointSlack.py. Slack changes between steps with different models (e.g. 2_4_floorplan_pdn to the first placed step, 4_1_cts to 5_1_grt, or 6_1_fill to 6_final) include the change of model. Detailed routing is only extracted in 6_final, so 5_2_route to 6_1_fill show global routing estimates.

Each file contains design, step, parasitics, time_unit (seconds per time unit of the values) and endpoints: a map from every endpoint pin (sta::endpoints) to [setup slack, hold slack], null where the endpoint is unconstrained. The slack is the pin’s worst slack over all path groups and clocks (get_property $pin slack_max|slack_min). On asap7/swerv_wrapper (about 30k endpoints) a snapshot is about 1 MB and takes about 10 s, mostly the timing update.

Analysis#

flow/util/endpointSlack.py only uses the Python standard library.

R=reports/nangate45/gcd/base

# Steps in execution order with parasitics, WNS, TNS and violation counts
python3 util/endpointSlack.py list $R

# Compare consecutive steps across the whole run; --html also writes a
# scatter for every step vs. its successor and an index.html to a directory
python3 util/endpointSlack.py track $R --html track

# Compare two steps; -o writes an interactive HTML scatter
python3 util/endpointSlack.py compare \
  $R/3_5_place_dp_endpoint_slack.json $R/4_1_cts_endpoint_slack.json \
  --unit ps -o compare.html

# Flatten all snapshots into one CSV (one row per endpoint per step)
python3 util/endpointSlack.py export $R -o slack.csv

For setup and hold, compare reports:

  • endpoints in both steps, and how many improved, degraded, stayed the same, became violating (newly failing) or stopped violating (newly passing), with statistics of the slack change (B - A). Improved, degraded and unchanged exclude endpoints with positive slack in both steps, which are not being optimized;

  • endpoints only in A or only in B, i.e. added or removed from the netlist;

  • endpoints in both netlists but constrained in only one of them;

  • how well the two steps agree on the critical endpoints (see below).

Unconstrained endpoints, such as the outputs of CTS dummy load cells, are ignored.

Agreement metrics#

Correlation over all endpoints is dominated by endpoints with large positive slack and is close to 1 even when the critical endpoints change a lot (0.9997 for setup on asap7/swerv_wrapper from 3_5_place_dp to 4_1_cts). The metrics are therefore measured on a critical set: the worst K endpoints of A or of B (--critical K, default 1000), excluding endpoints with positive slack in both steps, which are not being optimized. When fewer than K endpoints violate, the critical set is the endpoints violating in either step; when nothing violates (often hold) it is empty and the metrics are reported as -.

Metric

Meaning

spearman

Spearman rank correlation of A and B slack (ties get average ranks): is the order of the critical endpoints preserved?

top agreement

Fraction of the critical set that is in the worst K of both steps.

bias, MAE, RMSE, max|delta|

Mean, mean absolute, root mean square and maximum absolute slack change B - A, i.e. distance from the y = x line.

violator recall

Of the endpoints violating in B, the fraction already violating in A (over all endpoints).

violator precision

Of the endpoints violating in A, the fraction still violating in B (over all endpoints).

They are printed by compare and track, shown in the HTML stats, and the track index has Spearman, top agreement and MAE columns for every step transition.

Times are shown in --unit (default ns) with a fixed number of digits after the decimal point (3 for ns, 1 for ps, or --digits), in a fixed-width font in the HTML. Slack changes smaller than half the last displayed digit (0.5 ps with the default ns and 3 digits), or --tolerance in --unit, count as unchanged for the improved/degraded counts, the tables of most degraded and improved endpoints and the track row colors. Otherwise numerical noise, e.g. a few femtoseconds between 5_1_grt and 5_2_route, shows up as changes that display as 0.

--worst N restricts the endpoints in both to the union of the worst N endpoints of A and of B, to focus on the critical part of the design.

The HTML is self-contained (no network access needed). It has:

  • WNS, TNS and violation counts of both steps;

  • a scatter of endpoint slack with a y = x line, where above the line means the endpoint improved. It is drawn on a canvas so it handles hundreds of thousands of endpoints. Drag to zoom, double-click to reset, hover for the endpoint name;

  • a setup/hold toggle;

  • tables of the most degraded and most improved endpoints, excluding endpoints with positive slack in both steps, and of the endpoints only in one step.

track --html DIR writes the same page for every step and its successor (<step>__<next step>.html, with previous/next links) and DIR/index.html, a table of every transition with WNS/TNS and the improved, degraded, newly failing and newly passing counts for setup and hold. Endpoints with positive slack in both steps are not considered. Transitions where no considered endpoint changed (e.g. 2_2_floorplan_macro to 2_3_floorplan_tapcell) are greyed out, and transitions where every considered endpoint improved, for setup and hold, are green.

For other analyses, import the module (e.g. from a notebook): load_snapshot(), load_dir(), summary(), compare(), movement(), metrics() and spearman() return plain Python dicts and lists.

Testing#

flow/test/test_endpointSlack.py covers loading and comparison with synthetic snapshots and runs in the util CI job:

python3 flow/test/test_endpointSlack.py