Before the staged comparison, look at the shape of the differences across all endpoints. A uniform shift points at a global setting; a handful of large differences at specific constraints or nets; a broad scatter at several causes at once. The shape sets the order of the investigation.
import statistics
def classify(diffs):
if max(abs(d) for d in diffs) < 1e-9:
return "no difference"
mean = statistics.fmean(diffs)
sd = statistics.pstdev(diffs)
frac_large = sum(1 for d in diffs if abs(d) > 0.05) / len(diffs)
if sd < 0.2 * abs(mean):
return "uniform shift"
if frac_large <= 0.10:
return "localised"
return "mixed"
uniform = [-0.050, -0.048, -0.052, -0.049, -0.051, -0.050, -0.047, -0.053]
local = [0.0, 0.001, 0.0, -0.002, 0.0, 0.0, -0.150, 0.001, 0.0, 0.0, -0.002, 0.001, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.001, 0.0]
mixed = [-0.01, -0.08, 0.02, -0.03, -0.12, 0.00, -0.05, 0.04]
none = [0.0, 0.0, 0.0, 0.0]
assert (classify(uniform), classify(local), classify(mixed), classify(none)) == ("uniform shift", "localised", "mixed", "no difference")
print("PASS:", classify(uniform), "/", classify(local), "/", classify(mixed), "/", classify(none))Shape | Most likely cause | First thing to check |
|---|---|---|
Uniform shift | A global input: derates, uncertainty, units, a global parasitic scale | Run manifests and settings |
Localised (a few large) | A constraint, a net, a macro model or one block's data | The endpoints with the largest differences: shared startpoints, clocks, exceptions |
Mixed | Several causes | Staged comparison; resolve the first stage first |
The uniform example shifts every endpoint by about 50 ps with a spread of 2 ps: a single global cause. The localised example differs by under 3 ps almost everywhere but by 150 ps at one endpoint: look at what that endpoint's path has that the others do not. The mixed example has large differences of both signs, so more than one cause is present and the staged comparison from the first lesson is the way in. Derates and parasitic scaling shift endpoints in proportion to path delay, so a classifier based on spread alone calls them mixed: check proportionality to path delay before concluding several causes. The 20% and 10% limits are working values; adjust them to your design.
Step | Question |
|---|---|
1 | Are the run manifests identical (netlist, constraints, libraries, parasitics, settings)? |
2 | What shape do the per-endpoint differences have? |
3 | Is the same reference path the same path in both runs? |
4 | Where is the first stage at which a staged comparison diverges? |
5 | Do the library and parasitic sanity checks pass? |
6 | Did any constraint change between the runs, and what did it cover? |
The distribution shape is recorded in the mismatch ticket before any path-level work starts.
Each step of the checklist has an answer written down, not just remembered.
The resolved cause is classified (global setting, constraint, library, parasitics) so patterns across projects can be seen.
Mixed: the spread is not small relative to the mean, and about a quarter of large differences is well above the 10% limit for 'localised', so several causes are likely.