dbSta: Adds iteration free delay model to STA#10975
Conversation
This new delay model removes all iteration from DmpCeffTwoPole series of delay models. This is accomplished via two different methods. This commit replaces the computationally expensive Newton-Raphson iteration loop in the DMPCeff algorithm with a fully feed-forward, O(1) rational function (Padé approximant). The legacy iterative approach suffers from branch mispredictions and cache misses, bottlenecking physical synthesis inner loops. The new technique pre-characterizes the Pi-model shielding factor (k) offline and evaluates it at runtime using a 12-parameter polynomial optimized for FMA instructions. To ensure the surrogate model is universal (PDK-agnostic) and strictly respects physical boundaries at extreme asymptotes, the Pi-model physicals are mapped into a dimensionless 3D parameter space: * x = R_pi / R_d : The resistance ratio. Dictates the primary shielding effect. Squaring this term in the denominator guarantees complete shielding (k=0) as wire resistance approaches infinity. * y = C_2 / (C_1 + C_2) : The capacitance ratio. Represents the far-end fraction of the total load, strictly bounded between 0.0 and 1.0. * z = t_r / (R_d * C_tot) : The normalized slew ratio. Maps the driver's unshielded transition time against the intrinsic RC time constant of the network. The surrogate model evaluates the shielding factor as k = f(x,y,z), allowing effective capacitance to be resolved instantly via: C_eff = C_1 + k * C_2 The resulting C_eff is subsequently passed to a Boost Lambert W (W0) analytical solver to compute the exact timing threshold crossings without any runtime iteration. Signed-off-by: Ethan Mahintorabi <ethanmoon@google.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a new delay calculator, DmpCeffLambertWDelayCalc, which utilizes a Lambert W function solver and a bivariate Padé approximation for Ceff shielding calculations. It also adds a training data generator, a Python fitting script, and corresponding unit tests. The review feedback highlights two critical issues in DmpCeffLambertWDelayCalc.cc: first, the real parts of the poles returned by poleResidue must be negated to prevent exponential overflow and NaN values in the mathematical derivations; second, adding 1e-15 to a single-precision float capacitance value will underflow, causing a division-by-zero error when calculating rd.
| double p1 = pole1.real(); | ||
| double k1 = residue1.real(); | ||
| double p2 = pole2.real(); | ||
| double k2 = residue2.real(); |
There was a problem hiding this comment.
In stable RC networks, the real parts of the poles returned by poleResidue are negative (i.e., pole1.real() < 0 and pole2.real() < 0). However, the mathematical derivations and formulas implemented in loadDelaySlew and loadDelay (such as std::exp(-p1 * tt) in line 225, arg_vth in line 230, and std::exp(p1 * tt) - 1.0 in line 276) strictly assume that p1 and p2 are positive values representing the absolute magnitudes of the poles.
If p1 and p2 are negative:
std::exp(-p1 * tt)will grow exponentially and overflow.std::exp(p1 * tt) - 1.0will be negative, causingstd::log(arg)to returnNaN.
To fix this, define p1 and p2 as positive by negating the real parts of the poles. This also aligns the runtime behavior with the unit tests (which generated positive poles).
| double p1 = pole1.real(); | |
| double k1 = residue1.real(); | |
| double p2 = pole2.real(); | |
| double k2 = residue2.real(); | |
| double p1 = -pole1.real(); | |
| double k1 = residue1.real(); | |
| double p2 = -pole2.real(); | |
| double k2 = residue2.real(); |
| float cap1 = c1 + c2; | ||
| float cap2 = cap1 + 1e-15; | ||
| float d1, d2, s1, s2; | ||
| gate_model->gateDelay(pvt, in_slew, cap1, d1, s1); | ||
| gate_model->gateDelay(pvt, in_slew, cap2, d2, s2); | ||
| double vth = cell->libertyLibrary()->outputThreshold(rf); | ||
| float rd = -std::log(vth) * std::abs(d1 - d2) / (cap2 - cap1); |
There was a problem hiding this comment.
Adding 1e-15 to cap1 in single-precision float (which has only 24 bits of mantissa, ~7 decimal digits of precision) will underflow to 0.0 for typical capacitance values (e.g., 1.0 to 100.0 fF or pF). This results in cap2 being exactly equal to cap1, leading to cap2 - cap1 == 0.0f and causing a division by zero (producing NaN) when calculating rd.
To prevent this, use a relative delta or a safe minimum absolute delta that is representable in float relative to cap1 (e.g., cap1 * 1e-4f or 1e-4f).
| float cap1 = c1 + c2; | |
| float cap2 = cap1 + 1e-15; | |
| float d1, d2, s1, s2; | |
| gate_model->gateDelay(pvt, in_slew, cap1, d1, s1); | |
| gate_model->gateDelay(pvt, in_slew, cap2, d2, s2); | |
| double vth = cell->libertyLibrary()->outputThreshold(rf); | |
| float rd = -std::log(vth) * std::abs(d1 - d2) / (cap2 - cap1); | |
| float cap1 = c1 + c2; | |
| float delta = std::max(cap1 * 1e-4f, 1e-4f); | |
| float cap2 = cap1 + delta; | |
| float d1, d2, s1, s2; | |
| gate_model->gateDelay(pvt, in_slew, cap1, d1, s1); | |
| gate_model->gateDelay(pvt, in_slew, cap2, d2, s2); | |
| double vth = cell->libertyLibrary()->outputThreshold(rf); | |
| float rd = -std::log(vth) * std::abs(d1 - d2) / delta; |
| pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") | ||
| pip.parse( | ||
| extra_pip_args = [ | ||
| "--index-url=https://pypi.org/simple", |
There was a problem hiding this comment.
Is this just to make the default explicit?
There was a problem hiding this comment.
Google uses an internal proxy by default that doesn't seem to be compatible with this bazel module because it requires authentication. This ensures that it uses the correct upstream url which is the default. The other option would be to turn off the isolated setting which would let it pick up the authentication tokens required connected to the google default url
This new delay model removes all iteration from DmpCeffTwoPole series of delay models. This is accomplished via two different methods.
This commit replaces the computationally expensive Newton-Raphson iteration loop in the DMPCeff algorithm with a fully feed-forward, O(1) rational function (Padé approximant).
The new technique pre-characterizes the Pi-model shielding factor (k) offline and evaluates it at runtime using a 18-parameter polynomial optimized for FMA instructions.
To ensure the surrogate model is universal (PDK-agnostic) and strictly respects physical boundaries at extreme asymptotes, the Pi-model physicals are mapped into a dimensionless 3D parameter space:
The surrogate model evaluates the shielding factor as k = f(x,y,z), allowing effective capacitance to be resolved instantly via: C_eff = C_1 + k * C_2
The resulting C_eff is subsequently passed to a Boost Lambert W (W0) analytical solver to compute the exact timing threshold crossings without any runtime iteration.
Type of Change
Impact
DmpCeffTwoPoleDelayCalc::gateDelay(OpenSTA internal NR loop)DmpCeffLambertWDelayCalc::gateDelay(Iteration-free Padé surrogate)Verification
./etc/Build.sh).