The-OpenROAD-Project / OpenSTA

OpenSTA engine
GNU General Public License v3.0
389 stars 170 forks source link

Power inconsistent over corners #62

Closed gadfort closed 3 years ago

gadfort commented 3 years ago

I was trying to analyze the power of my design across different corners, but I noticed I was getting different results for the same corners. It appears that the power only partially uses the corner to compute the power.

Looking through the code, I think it's because the power uses the first liberty file loaded to determine the voltages, leakage, etc, which results in incorrect results. On line 1068 of Power.cc, it appears to request the voltage of the library, which returns the wrong value. This could be because the LibertyCell input was collected from the first library loaded instead of the liberty library for that specific corner. https://github.com/The-OpenROAD-Project/OpenSTA/blob/a4df141cbcf2db3a5d8c63acdb92c582e6c7844f/search/Power.cc#L1068

I've attached three examples based on example5 from your repository, in all cases the report_power is supposed to report the typical power. example.zip

In A, the slow corner is loaded first and it results in a low power result for the typical corner (total power: 1.33uW) In B, the fast corner is loaded first and it results in a high power result for the typical corner (total power: 3.06uW) In C, only the typical corner was loaded and serves as a basis for comparison (total power: 1.82uW)

Below is except from the output to help illustrate that the power computed is different, but should all have been the same.

  1. Example A - incorrect slow corner loaded first (notice the volt = 0.95) Group Internal Switching Leakage Total Power Power Power Power Sequential 1.08e-06 1.27e-08 1.63e-07 1.26e-06 94.2% Combinational 3.47e-08 1.23e-08 3.08e-08 7.78e-08 5.8% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Total 1.12e-06 2.51e-08 1.94e-07 1.33e-06 100.0% 83.6% 1.9% 14.5% power: switching DFF_X1/Q activity = 1.00e+07 volt = 0.95 1.398e-09

  2. Example B - incorrect fast corner loaded first (notice the volt = 1.25) Group Internal Switching Leakage Total Power Power Power Power Sequential 1.95e-06 2.20e-08 8.31e-07 2.80e-06 91.6% Combinational 6.61e-08 2.14e-08 1.69e-07 2.56e-07 8.4% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Total 2.01e-06 4.34e-08 9.99e-07 3.06e-06 100.0% 65.9% 1.4% 32.7% power: switching DFF_X1/Q activity = 1.00e+07 volt = 1.25 2.420e-09

  3. Example C - correct single corner loaded (notice the volt = 1.10) Group Internal Switching Leakage Total Power Power Power Power Sequential 1.45e-06 1.71e-08 2.37e-07 1.71e-06 94.0% Combinational 4.64e-08 1.65e-08 4.65e-08 1.09e-07 6.0% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Total 1.50e-06 3.36e-08 2.84e-07 1.82e-06 100.0% 82.5% 1.9% 15.6% power: switching DFF_X1/Q activity = 1.00e+07 volt = 1.10 1.874e-09

jjcherry56 commented 3 years ago

Thanks for a concise and detailed report and test case. fixed in 7e4e9207 power multi-corner support but I know better than to close the issue until you have tried it...

gadfort commented 3 years ago

Thanks for taking a look at it.

I checked on our internal design and the power numbers across the corners are much more consistent. However, there is a minor different between the total powers. The combinational internal power differs slightly depending on the order the libraries are loaded.

  1. Combinational 8.13e-04 3.65e-04 8.41e-06 1.19e-03 75.4%

  2. Combinational 8.18e-04 3.65e-04 8.41e-06 1.19e-03 75.5%

When looking at specific instances, it looks like the duty and weight are different (the example below is a 2-input NOR) reporting power for the typical corner:

  1. (wc loaded first) power: A -> Y 0.19 0.50 0.50 2.65e-16 2.50e-08 VDD

  2. (typ loaded first) power: A -> Y 0.19 0.98 0.98 2.66e-16 4.95e-08 VDD

  3. (bc loaded first) power: A -> Y 0.19 0.50 0.50 2.65e-16 2.50e-08 VDD

reporting power for the wc corner:

  1. (wc loaded first) power: A -> Y 0.19 0.98 0.98 2.26e-16 4.21e-08 VDD

  2. (typ loaded first) power: A -> Y 0.19 0.50 0.50 2.65e-16 2.50e-08 VDD

  3. (bc loaded first) power: A -> Y 0.19 0.50 0.50 3.15e-16 2.98e-08 VDD

Notice how the duty and weight parameters are 0.98 when the first loaded library corner matches the reporting corner and is 0.50 when they not not match. When only loading one library, the 0.98 appears to be the correct answer.

I think what's happing is that for the first loaded corner findInputDuty returns a number, while not he other corners it's falling back to the value 0.5 on line 878 https://github.com/The-OpenROAD-Project/OpenSTA/blob/7e4e92076a579ad6e90d38b0ab5e231f9241a531/search/Power.cc#L878

Stepping through the code, it looks like func->hasPort(from_port) is returning true on the correct values and false on the incorrect values. https://github.com/The-OpenROAD-Project/OpenSTA/blob/7e4e92076a579ad6e90d38b0ab5e231f9241a531/search/Power.cc#L859

I've updated the examples to replicate the issue: dutydiff.zip In this these examples, you can see the typical power changes between powerA and powerB, and the difference is the duty of the u2 gate. In these examples, you can see the combinational internal power should be 1.09e-07, but in powerA it is 1.07e-07

Thanks again for taking a look at these. Let me know if you need any additional examples.

jjcherry56 commented 3 years ago

I push an update. It fixes this example.

gadfort commented 3 years ago

Thanks. It looks the power is now consistent across the corners in our internal design. Thanks for all your help.