1 /* Copyright (c) 2012 Massachusetts Institute of Technology
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 #include "model/timing_graph/ElectricalTimingTree.h"
25 #include "model/ElectricalModel.h"
26 #include "model/timing_graph/ElectricalTimingNode.h"
27 #include "model/timing_graph/ElectricalDriver.h"
28 #include "model/timing_graph/ElectricalNet.h"
32 // Initialize the next visited number to be one above the initial number
33 // used by ElectricalTimingNode
34 int ElectricalTimingTree::msTreeNum
= ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM
+ 1;
36 ElectricalTimingTree::ElectricalTimingTree(const String
& instance_name_
, ElectricalModel
* model_
)
37 : m_instance_name_(instance_name_
), m_model_(model_
)
42 ElectricalTimingTree::~ElectricalTimingTree()
47 const String
& ElectricalTimingTree::getInstanceName() const
49 return m_instance_name_
;
52 bool ElectricalTimingTree::performTimingOpt(ElectricalTimingNode
* node_
, double required_delay_
)
54 // Extract the critical path from all timing paths branching out from the starting node
55 double delay
= performCritPathExtract(node_
);
56 double min_delay
= delay
;
58 unsigned int iteration
= 0;
59 unsigned int crit_path_iteration
= 0;
60 unsigned int max_iterations
= 8000; //TODO: make this not hard-coded
61 unsigned int max_iterations_single_crit_path
= 400; //TODO: make this not hard-coded
63 Log::printLine(getInstanceName() + " -> Beginning Incremental Timing Optimization");
65 // Size up the nodes if timing is not met
66 while(required_delay_
< delay
)
68 Log::printLine(getInstanceName() + " -> Timing Optimization Iteration " + (String
) iteration
+
69 ": Required delay = " + (String
) required_delay_
+ ", Delay = " +
70 (String
) delay
+ ", Slack = " + (String
) (required_delay_
- delay
));
72 ElectricalTimingNode
* node_for_timing_opt
= NULL
;
73 // Go into the less expensive critical path delay calculation
74 // While the timing is not met for this critical path
75 while (required_delay_
< delay
)
77 // Find the node to optimize timing for, it would return a node to size up
78 node_for_timing_opt
= findNodeForTimingOpt(node_
);
79 // Give up if there are no appropriate nodes to size up or
80 // max number of iterations has been reached
81 // Size up the chosen node if there is an appropriate node to size up
82 if(node_for_timing_opt
== NULL
|| iteration
> max_iterations
|| crit_path_iteration
> max_iterations_single_crit_path
)
85 node_for_timing_opt
->increaseDrivingStrength();
87 // Re-evaluate the delay of the critical path
88 delay
= calculateCritPathDelay(node_
);
90 crit_path_iteration
++;
91 Log::printLine(getInstanceName() + " -> Critical Path Slack: " + (String
) (required_delay_
- delay
));
93 // Give up if there are no appropriate nodes to size up or
94 // max number of iterations has been reached
95 if (node_for_timing_opt
== NULL
|| iteration
> max_iterations
|| crit_path_iteration
> max_iterations_single_crit_path
)
98 crit_path_iteration
= 0;
99 // Once the critical path timing is met, extract a new critical path from
100 // all timing paths branching out from the starting node
101 delay
= performCritPathExtract(node_
);
102 min_delay
= (min_delay
> delay
) ? delay
: min_delay
;
104 Log::printLine(getInstanceName() + " -> Timing Optimization Ended after Iteration: " + (String
) iteration
+
105 ": Required delay = " + (String
) required_delay_
+ ", Delay = " +
106 (String
) delay
+ ", Slack = " + (String
) (required_delay_
- delay
));
108 min_delay
= (min_delay
> delay
) ? delay
: min_delay
;
110 // Check if the timing meets the required delay
111 if(required_delay_
< delay
)
113 // Timing not met. Return false and print out a warning message
114 const String
& warning_msg
= "[Warning] " + getInstanceName() + " -> Timing not met: Required delay = " +
115 (String
) required_delay_
+ ", Minimum Delay = " + (String
) min_delay
+ ", Slack = " +
116 (String
) (required_delay_
- delay
);
117 Log::printLine(std::cerr
, warning_msg
);
122 //-------------------------------------------------------------------------
123 // Extract Crit Path Delay (and marks the crit path)
124 //-------------------------------------------------------------------------
125 double ElectricalTimingTree::performCritPathExtract(ElectricalTimingNode
* node_
)
127 setTreeNum(getTreeNum() + 1);
128 return extractCritPathDelay(node_
);
131 double ElectricalTimingTree::extractCritPathDelay(ElectricalTimingNode
* node_
)
133 //TODO: Replace with a stack data structure instead of recursion to prevent
134 //stack overflow problems with long chains of logic (4000+ nodes) and/or better
135 //performance. Nvm, stack data structure version seems to run much slower
137 // If the node has already been visited, return the delay!
138 if (node_
->getVisitedNum() == getTreeNum())
139 return node_
->getDelayLeft();
140 // If the node has been marked as a false path, return 0.0
141 else if (node_
->getFalsePath())
144 // Set the new parity for this node
145 node_
->setVisitedNum(getTreeNum());
146 node_
->setDelayLeft(0.0);
148 double max_delay
= 0;
149 double current_delay
= 0;
151 // Traverse downstream nodes to calculate the delay through each downstream path
152 vector
<ElectricalTimingNode
*>* d_nodes
= node_
->getDownstreamNodes();
153 for (unsigned int i
= 0; i
< d_nodes
->size(); ++i
)
155 current_delay
= extractCritPathDelay(d_nodes
->at(i
));
156 // Update the critical path
157 if (current_delay
> max_delay
)
159 node_
->setCritPath(i
);
160 max_delay
= current_delay
;
163 // Calculate the delay left from this node
164 double delay_left
= node_
->calculateDelay() + max_delay
;
165 node_
->setDelayLeft(delay_left
);
171 double ElectricalTimingTree::calculateCritPathDelay(ElectricalTimingNode
* node_
) const
173 // Simplest case where theres nothing to optimize
180 // Traverse the critical path and sum up delays
181 while (crit_path
>= 0)
183 delay
+= node_
->calculateDelay();
184 //Move on to the next node in the critical path
185 crit_path
= node_
->getCritPath();
187 node_
= node_
->getDownstreamNodes()->at(crit_path
);
191 //-------------------------------------------------------------------------
193 //-------------------------------------------------------------------------
194 // Find Worst Slew Helpers
195 //-------------------------------------------------------------------------
196 ElectricalTimingNode
* ElectricalTimingTree::findNodeForTimingOpt(ElectricalTimingNode
* node_
) const
198 // Simplest case where theres nothing to optimize
202 double max_transition_ratio
= -10.0;
203 double current_transition_ratio
= 0.0;
204 double previous_transition
= 1e3
* node_
->getTotalDownstreamCap();
205 double current_transition
= 0.0;
206 ElectricalTimingNode
* worst
= NULL
;
209 // Find the node with the highest max_transition_ratio to return
210 while (crit_path
>= 0)
212 current_transition
= node_
->calculateDelay();
214 //If the node is not yet at max size, it is a potential choice for size up
215 if (!node_
->hasMaxDrivingStrength())
217 current_transition_ratio
= current_transition
/ previous_transition
;
219 if (current_transition_ratio
> max_transition_ratio
)
222 max_transition_ratio
= current_transition_ratio
;
226 if (node_
->isDriver())
227 previous_transition
= 0.0;
228 previous_transition
+= current_transition
;
230 //Move on to the next node in the critical path
231 crit_path
= node_
->getCritPath();
234 node_
= node_
->getDownstreamNodes()->at(crit_path
);
239 //-------------------------------------------------------------------------
241 double ElectricalTimingTree::calculateNodeTransition(ElectricalTimingNode
* node_
) const
243 return node_
->calculateTransition();
246 ElectricalTimingTree::ElectricalTimingTree(const ElectricalTimingTree
& /* graph_ */)
251 ElectricalModel
* ElectricalTimingTree::getModel()
256 void ElectricalTimingTree::setTreeNum(int tree_num_
)
258 msTreeNum
= tree_num_
;
262 int ElectricalTimingTree::getTreeNum()