power use propagted activities for internal power
This commit is contained in:
parent
a8e15ae64f
commit
e6ff991859
268
search/Power.cc
268
search/Power.cc
|
|
@ -56,14 +56,13 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
typedef std::pair<float, int> SumCount;
|
||||
typedef Map<const char*, SumCount, CharPtrLess> SupplySumCounts;
|
||||
static int
|
||||
funcExprPortCount(FuncExpr *expr);
|
||||
|
||||
Power::Power(Sta *sta) :
|
||||
StaState(sta),
|
||||
global_activity_{0.0, 0.0, PwrActivityOrigin::unknown},
|
||||
input_activity_{0.1, 0.5, PwrActivityOrigin::input},
|
||||
default_activity_(.1),
|
||||
activities_valid_(false)
|
||||
{
|
||||
}
|
||||
|
|
@ -111,19 +110,19 @@ Power::hasPinActivity(const Pin *pin)
|
|||
|
||||
void
|
||||
Power::setPinActivity(const Pin *pin,
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
PwrActivity &activity)
|
||||
{
|
||||
activity_map_[pin] = {activity, duty, origin};
|
||||
activity_map_[pin] = activity;
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setPinActivity(const Pin *pin,
|
||||
PwrActivity &activity)
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
{
|
||||
activity_map_[pin] = activity;
|
||||
activity_map_[pin] = {activity, duty, origin};
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +317,10 @@ PropActivityVisitor::visit(Vertex *vertex)
|
|||
Instance *inst = network_->instance(pin);
|
||||
PwrActivity activity = power_->evalActivity(func, inst);
|
||||
power_->setPinActivity(pin, activity);
|
||||
debugPrint3(debug_, "power_activity", 3, "set %s %.2e %.2f\n",
|
||||
vertex->name(network_),
|
||||
activity.activity(),
|
||||
activity.duty());
|
||||
}
|
||||
}
|
||||
bfs_->enqueueAdjacentVertices(vertex);
|
||||
|
|
@ -331,7 +334,7 @@ Power::evalActivity(FuncExpr *expr,
|
|||
case FuncExpr::op_port: {
|
||||
Pin *pin = network_->findPin(inst, expr->port()->name());
|
||||
if (pin)
|
||||
return pinActivity(pin);
|
||||
return findActivity(pin);
|
||||
}
|
||||
case FuncExpr::op_not: {
|
||||
PwrActivity activity1 = evalActivity(expr->left(), inst);
|
||||
|
|
@ -418,14 +421,14 @@ Power::seedActivities(BfsFwdIterator &bfs)
|
|||
// Clock activities are baked in.
|
||||
if (!sdc_->isVertexPinClock(pin)
|
||||
&& network_->direction(pin) != PortDirection::internal()) {
|
||||
debugPrint1(debug_, "power_activity", 3, "seed %s\n",
|
||||
vertex->name(network_));
|
||||
PwrActivity &activity = pinActivity(pin);
|
||||
PwrActivityOrigin origin = activity.origin();
|
||||
// Default inputs without explicit activities to the input default.
|
||||
if (origin != PwrActivityOrigin::user)
|
||||
setPinActivity(pin, input_activity_);
|
||||
Vertex *vertex = graph_->pinDrvrVertex(pin);
|
||||
debugPrint1(debug_, "power_activity", 3, "seed %s\n",
|
||||
vertex->name(network_));
|
||||
bfs.enqueueAdjacentVertices(vertex);
|
||||
}
|
||||
}
|
||||
|
|
@ -498,12 +501,12 @@ Power::power(const Instance *inst,
|
|||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, TransRiseFall::rise(), dcalc_ap)
|
||||
: 0.0;
|
||||
PwrActivity activity = findActivity(to_pin, inst_clk);
|
||||
PwrActivity activity = findClkedActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput())
|
||||
findSwitchingPower(cell, to_port, activity, load_cap,
|
||||
dcalc_ap, result);
|
||||
findInternalPower(inst, cell, to_port, activity,
|
||||
load_cap, dcalc_ap, result);
|
||||
findInternalPower(to_port, inst, cell, activity,
|
||||
inst_clk, load_cap, dcalc_ap, result);
|
||||
}
|
||||
delete pin_iter;
|
||||
findLeakagePower(inst, cell, result);
|
||||
|
|
@ -525,10 +528,11 @@ Power::findInstClk(const Instance *inst)
|
|||
}
|
||||
|
||||
void
|
||||
Power::findInternalPower(const Instance *inst,
|
||||
Power::findInternalPower(const LibertyPort *to_port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
PwrActivity &activity,
|
||||
PwrActivity &to_activity,
|
||||
const Clock *inst_clk,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
|
|
@ -538,73 +542,123 @@ Power::findInternalPower(const Instance *inst,
|
|||
network_->pathName(inst),
|
||||
to_port->name(),
|
||||
cell->name());
|
||||
SupplySumCounts supply_sum_counts;
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
debugPrint1(debug_, "power", 2, " cap = %s\n",
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
debugPrint0(debug_, "power", 2, " when act/ns duty energy power\n");
|
||||
float input_duty_sum = inputDutySum(inst);
|
||||
float internal = 0.0;
|
||||
LibertyCellInternalPowerIterator pwr_iter(cell);
|
||||
while (pwr_iter.hasNext()) {
|
||||
InternalPower *pwr = pwr_iter.next();
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
const LibertyPort *from_port = pwr->relatedPort();
|
||||
if (pwr->port() == to_port) {
|
||||
if (from_port == nullptr)
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
const LibertyPort *from_port = pwr->relatedPort();
|
||||
if (from_port == nullptr) {
|
||||
// Input port internal power.
|
||||
from_port = to_port;
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
FuncExpr *when = pwr->when();
|
||||
PwrActivity when_activity = when ? evalActivity(when, inst)
|
||||
: findActivity(from_pin);
|
||||
float duty = when_activity.duty();
|
||||
float port_energy = 0.0;
|
||||
float port_internal = 0.0;
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *to_tr = tr_iter.next();
|
||||
// Should use unateness to find from_tr.
|
||||
TransRiseFall *from_tr = to_tr;
|
||||
float slew = delayAsFloat(graph_->slew(from_vertex,
|
||||
from_tr,
|
||||
dcalc_ap->index()));
|
||||
float tr_energy = (from_port)
|
||||
? pwr->power(to_tr, pvt, slew, load_cap)
|
||||
: pwr->power(to_tr, pvt, 0.0, 0.0);
|
||||
float tr_internal = tr_energy * activity.activity();
|
||||
port_energy += tr_energy;
|
||||
port_internal += tr_internal;
|
||||
}
|
||||
debugPrint8(debug_, "power", 2, " %s -> %s %s %.2f %.2f %9.2e %9.2e %s\n",
|
||||
from_port->name(),
|
||||
to_port->name(),
|
||||
pwr->when() ? pwr->when()->asString() : " ",
|
||||
activity.activity() * 1e-9,
|
||||
duty,
|
||||
port_energy,
|
||||
port_internal,
|
||||
related_pg_pin ? related_pg_pin : "no pg_pin");
|
||||
|
||||
// Sum/count internal power arcs by supply to average across conditions.
|
||||
SumCount &supply_sum_count = supply_sum_counts[related_pg_pin];
|
||||
// Average rise/fall internal power.
|
||||
supply_sum_count.first += port_internal / 2.0;
|
||||
supply_sum_count.second++;
|
||||
FuncExpr *when = pwr->when();
|
||||
// If all the "when" clauses exist VSS internal power is ignored.
|
||||
if ((when && internalPowerMissingWhen(cell, to_port, related_pg_pin))
|
||||
|| pgNameVoltage(cell, related_pg_pin, dcalc_ap) != 0.0) {
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
float duty;
|
||||
if (when)
|
||||
duty = evalActivity(when, inst).duty();
|
||||
else if (search_->isClock(from_vertex))
|
||||
duty = 1.0;
|
||||
else {
|
||||
PwrActivity from_activity = findClkedActivity(from_pin, inst_clk);
|
||||
float duty1 = 1.0 - (input_duty_sum - from_activity.duty());
|
||||
duty = from_activity.activity() * duty1 / to_activity.activity();
|
||||
}
|
||||
float port_energy = 0.0;
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *to_tr = tr_iter.next();
|
||||
// Should use unateness to find from_tr.
|
||||
TransRiseFall *from_tr = to_tr;
|
||||
float slew = delayAsFloat(graph_->slew(from_vertex,
|
||||
from_tr,
|
||||
dcalc_ap->index()));
|
||||
float table_energy = pwr->power(to_tr, pvt, slew, load_cap);
|
||||
float tr_energy = table_energy * duty;
|
||||
debugPrint4(debug_, "power", 3, " %s energy = %9.2e * %.2f = %9.2e\n",
|
||||
to_tr->shortName(),
|
||||
table_energy,
|
||||
duty,
|
||||
tr_energy);
|
||||
port_energy += tr_energy;
|
||||
}
|
||||
float port_internal = port_energy * to_activity.activity();
|
||||
debugPrint8(debug_, "power", 2, " %s -> %s %s %.2f %.2f %9.2e %9.2e %s\n",
|
||||
from_port->name(),
|
||||
to_port->name(),
|
||||
pwr->when() ? pwr->when()->asString() : " ",
|
||||
to_activity.activity() * 1e-9,
|
||||
duty,
|
||||
port_energy,
|
||||
port_internal,
|
||||
related_pg_pin ? related_pg_pin : "no pg_pin");
|
||||
internal += port_internal;
|
||||
}
|
||||
}
|
||||
}
|
||||
float internal = 0.0;
|
||||
for (auto supply_sum_count : supply_sum_counts) {
|
||||
SumCount sum_count = supply_sum_count.second;
|
||||
float supply_internal = sum_count.first;
|
||||
int supply_count = sum_count.second;
|
||||
internal += supply_internal / (supply_count > 0 ? supply_count : 1);
|
||||
}
|
||||
|
||||
debugPrint2(debug_, "power", 2, " %s internal = %.3e\n",
|
||||
to_port->name(),
|
||||
internal);
|
||||
result.setInternal(result.internal() + internal);
|
||||
}
|
||||
|
||||
// Return true if some a "when" clause for the internal power to_port
|
||||
// is missing.
|
||||
bool
|
||||
Power::internalPowerMissingWhen(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
const char *related_pg_pin)
|
||||
{
|
||||
int when_input_count = 0;
|
||||
int when_count = 0;
|
||||
LibertyCellInternalPowerIterator pwr_iter(cell);
|
||||
while (pwr_iter.hasNext()) {
|
||||
auto pwr = pwr_iter.next();
|
||||
auto when = pwr->when();
|
||||
if (pwr->port() == to_port
|
||||
&& pwr->relatedPort() == nullptr
|
||||
&& stringEq(pwr->relatedPgPin(), related_pg_pin)
|
||||
&& when) {
|
||||
when_count++;
|
||||
when_input_count = funcExprPortCount(when);
|
||||
}
|
||||
}
|
||||
return when_count != (1 << when_input_count);
|
||||
}
|
||||
|
||||
static int
|
||||
funcExprPortCount(FuncExpr *expr)
|
||||
{
|
||||
int port_count = 0;
|
||||
FuncExprPortIterator port_iter(expr);
|
||||
while (port_iter.hasNext()) {
|
||||
port_iter.next();
|
||||
port_count++;
|
||||
}
|
||||
return port_count;
|
||||
}
|
||||
|
||||
float
|
||||
Power::inputDutySum(const Instance *inst)
|
||||
{
|
||||
float duty_sum = 0.0;
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *pin = pin_iter->next();
|
||||
if (network_->direction(pin)->isAnyInput())
|
||||
duty_sum += findClkedActivity(pin).duty();
|
||||
}
|
||||
delete pin_iter;
|
||||
return duty_sum;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findLeakagePower(const Instance *,
|
||||
LibertyCell *cell,
|
||||
|
|
@ -671,7 +725,7 @@ Power::findSwitchingPower(LibertyCell *cell,
|
|||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
float volt = voltage(cell, to_port, dcalc_ap);
|
||||
float volt = portVoltage(cell, to_port, dcalc_ap);
|
||||
float switching = .5 * load_cap * volt * volt * activity.activity();
|
||||
debugPrint5(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e\n",
|
||||
cell->name(),
|
||||
|
|
@ -679,21 +733,20 @@ Power::findSwitchingPower(LibertyCell *cell,
|
|||
activity.activity(),
|
||||
volt,
|
||||
switching);
|
||||
volt = voltage(cell, to_port, dcalc_ap);
|
||||
result.setSwitching(result.switching() + switching);
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findActivity(const Pin *pin)
|
||||
Power::findClkedActivity(const Pin *pin)
|
||||
{
|
||||
const Instance *inst = network_->instance(pin);
|
||||
const Clock *inst_clk = findInstClk(inst);
|
||||
return findActivity(pin, inst_clk);
|
||||
return findClkedActivity(pin, inst_clk);
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findActivity(const Pin *pin,
|
||||
const Clock *inst_clk)
|
||||
Power::findClkedActivity(const Pin *pin,
|
||||
const Clock *inst_clk)
|
||||
{
|
||||
const Clock *clk = findClk(pin);
|
||||
if (clk == nullptr)
|
||||
|
|
@ -701,36 +754,51 @@ Power::findActivity(const Pin *pin,
|
|||
if (clk) {
|
||||
float period = clk->period();
|
||||
if (period > 0.0) {
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
if (search_->isClock(vertex))
|
||||
return PwrActivity(2.0 / period, 0.5, PwrActivityOrigin::clock);
|
||||
else if (global_activity_.isSet())
|
||||
return PwrActivity(global_activity_.activity() / period,
|
||||
0.5, PwrActivityOrigin::global);
|
||||
else {
|
||||
if (activity_map_.hasKey(pin)) {
|
||||
PwrActivity &activity = activity_map_[pin];
|
||||
if (activity.origin() != PwrActivityOrigin::unknown)
|
||||
return PwrActivity(activity.activity() / period,
|
||||
activity.duty(),
|
||||
activity.origin());
|
||||
}
|
||||
return PwrActivity(default_activity_ / period,
|
||||
0.5, PwrActivityOrigin::defaulted);
|
||||
}
|
||||
PwrActivity activity = findActivity(pin);
|
||||
return PwrActivity(activity.activity() / period,
|
||||
activity.duty(),
|
||||
activity.origin());
|
||||
}
|
||||
}
|
||||
return PwrActivity();
|
||||
// gotta find a clock someplace...
|
||||
return PwrActivity(input_activity_.activity(),
|
||||
input_activity_.duty(),
|
||||
PwrActivityOrigin::defaulted);
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findActivity(const Pin *pin)
|
||||
{
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
if (search_->isClock(vertex))
|
||||
return PwrActivity(2.0, 0.5, PwrActivityOrigin::clock);
|
||||
else if (global_activity_.isSet())
|
||||
return global_activity_;
|
||||
else {
|
||||
if (activity_map_.hasKey(pin)) {
|
||||
PwrActivity &activity = activity_map_[pin];
|
||||
if (activity.origin() != PwrActivityOrigin::unknown)
|
||||
return activity;
|
||||
}
|
||||
}
|
||||
return input_activity_;
|
||||
}
|
||||
|
||||
float
|
||||
Power::voltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
Power::portVoltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
auto power_pin = port->relatedPowerPin();
|
||||
if (power_pin) {
|
||||
auto pg_port = cell->findPgPort(power_pin);
|
||||
return pgNameVoltage(cell, port->relatedPowerPin(), dcalc_ap);
|
||||
}
|
||||
|
||||
float
|
||||
Power::pgNameVoltage(LibertyCell *cell,
|
||||
const char *pg_port_name,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
if (pg_port_name) {
|
||||
auto pg_port = cell->findPgPort(pg_port_name);
|
||||
if (pg_port) {
|
||||
auto volt_name = pg_port->voltageName();
|
||||
auto library = cell->libertyLibrary();
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ enum class PwrActivityOrigin
|
|||
propagated,
|
||||
clock,
|
||||
constant,
|
||||
defaulted, // temporary
|
||||
defaulted,
|
||||
unknown
|
||||
};
|
||||
|
||||
|
|
@ -89,14 +89,14 @@ public:
|
|||
float duty);
|
||||
PwrActivity &pinActivity(const Pin *pin);
|
||||
bool hasPinActivity(const Pin *pin);
|
||||
void setPinActivity(const Pin *pin,
|
||||
PwrActivity &activity);
|
||||
void setPinActivity(const Pin *pin,
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin);
|
||||
void setPinActivity(const Pin *pin,
|
||||
PwrActivity &activity);
|
||||
// Activity is toggles per second.
|
||||
PwrActivity findActivity(const Pin *pin);
|
||||
PwrActivity findClkedActivity(const Pin *pin);
|
||||
|
||||
protected:
|
||||
void preamble();
|
||||
|
|
@ -107,10 +107,11 @@ protected:
|
|||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findInternalPower(const Instance *inst,
|
||||
void findInternalPower(const LibertyPort *to_port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
PwrActivity &activity,
|
||||
PwrActivity &to_activity,
|
||||
const Clock *inst_clk,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
|
|
@ -128,11 +129,15 @@ protected:
|
|||
PowerResult &result);
|
||||
const Clock *findInstClk(const Instance *inst);
|
||||
const Clock *findClk(const Pin *to_pin);
|
||||
PwrActivity findActivity(const Pin *pin,
|
||||
const Clock *inst_clk);
|
||||
float voltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
PwrActivity findClkedActivity(const Pin *pin,
|
||||
const Clock *inst_clk);
|
||||
PwrActivity findActivity(const Pin *pin);
|
||||
float portVoltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
float pgNameVoltage(LibertyCell *cell,
|
||||
const char *pg_port_name,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
void seedActivities(BfsFwdIterator &bfs);
|
||||
void seedRegOutputActivities(const Instance *reg,
|
||||
Sequential *seq,
|
||||
|
|
@ -142,11 +147,14 @@ protected:
|
|||
BfsFwdIterator &bfs);
|
||||
PwrActivity evalActivity(FuncExpr *expr,
|
||||
const Instance *inst);
|
||||
float inputDutySum(const Instance *inst);
|
||||
bool internalPowerMissingWhen(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
const char *related_pg_pin);
|
||||
|
||||
private:
|
||||
PwrActivity global_activity_;
|
||||
PwrActivity input_activity_;
|
||||
float default_activity_;
|
||||
PwrActivityMap activity_map_;
|
||||
bool activities_valid_;
|
||||
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ getProperty(const Port *port,
|
|||
else if (stringEqual(property, "activity")) {
|
||||
const Instance *top_inst = network->topInstance();
|
||||
const Pin *pin = network->findPin(top_inst, port);
|
||||
PwrActivity activity = sta->power()->findActivity(pin);
|
||||
PwrActivity activity = sta->power()->findClkedActivity(pin);
|
||||
return PropertyValue(&activity);
|
||||
}
|
||||
|
||||
|
|
@ -664,7 +664,7 @@ getProperty(const Pin *pin,
|
|||
return PropertyValue(&clks);
|
||||
}
|
||||
else if (stringEqual(property, "activity")) {
|
||||
PwrActivity activity = sta->power()->findActivity(pin);
|
||||
PwrActivity activity = sta->power()->findClkedActivity(pin);
|
||||
return PropertyValue(&activity);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ using sta::StaException;
|
|||
Tcl_SetResult(interp, const_cast<char*>(excp.what()), TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
catch (std::bad_alloc) {
|
||||
catch (std::bad_alloc &) {
|
||||
fprintf(stderr, "Error: out of memory.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue