scons,python: Fix `--without-python` flag
[gem5.git] / ext / dsent / DSENT.cc
1 /* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
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:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
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
19 * THE SOFTWARE.
20 */
21
22 #include <cstdlib>
23 #include <iostream>
24
25 #include "DSENT.h"
26 #include "model/std_cells/StdCellLib.h"
27
28 using namespace std;
29
30 namespace DSENT
31 {
32 static void performTimingOpt(const map<String, String> &params,
33 Model *ms_model)
34 {
35 // Get the frequency it is optimizing to
36 double freq = params.at("Frequency").toDouble();
37
38 // Get all the starting net names
39 const vector<String>& start_net_names =
40 params.at("TimingOptimization->StartNetNames").split("[,]");
41
42 ASSERT((start_net_names.size() > 0),
43 "[Error] Expecting net names in TimingOptimization->StartNetNames");
44
45 if(start_net_names[0] == "*")
46 {
47 // Optimize from all input ports
48 ElectricalModel* electrical_model = (ElectricalModel*)ms_model;
49
50 ElectricalTimingOptimizer timing_optimizer(
51 "Optimizer", electrical_model->getTechModel());
52 timing_optimizer.setModel(electrical_model);
53 timing_optimizer.construct();
54 timing_optimizer.update();
55
56 ElectricalTimingTree timing_tree(
57 timing_optimizer.getInstanceName(), &timing_optimizer);
58
59 const Map<PortInfo*>* input_ports = timing_optimizer.getInputs();
60 Map<PortInfo*>::ConstIterator it_begin = input_ports->begin();
61 Map<PortInfo*>::ConstIterator it_end = input_ports->end();
62 Map<PortInfo*>::ConstIterator it;
63 for(it = it_begin; it != it_end; ++it)
64 {
65 const String& net_name = it->first;
66 Log::printLine("Optimizing net: " + net_name);
67 timing_tree.performTimingOpt(
68 timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq);
69 }
70
71 // Loop the second times
72 for(it = it_begin; it != it_end; ++it)
73 {
74 const String& net_name = it->first;
75 Log::printLine("Optimizing net: " + net_name);
76 }
77 }
78 else
79 {
80 // TODO : parse the net name so that we could do hierarchical optimization
81 // Currently we can only optimize timing at the top level
82 ElectricalModel* electrical_model = (ElectricalModel*)ms_model;
83 ElectricalTimingTree timing_tree(
84 electrical_model->getInstanceName(), electrical_model);
85
86 for(unsigned int i = 0; i < start_net_names.size(); ++i)
87 {
88 const String& net_name = start_net_names[i];
89 timing_tree.performTimingOpt(
90 electrical_model->getNet(net_name), 1.0 / freq);
91 }
92 }
93 }
94
95 static void reportTiming(const map<String, String> &params, Model *ms_model)
96 {
97 // Get all the starting net names
98 const vector<String>& start_net_names =
99 params.at("ReportTiming->StartNetNames").split("[,]");
100
101 ElectricalModel* electrical_model = (ElectricalModel*)ms_model;
102 ElectricalTimingTree timing_tree(
103 electrical_model->getInstanceName(), electrical_model);
104
105 cout << "Report timing:" << endl;
106 cout << "==============" << endl;
107 for(unsigned int i = 0; i < start_net_names.size(); ++i)
108 {
109 const String& net_name = start_net_names[i];
110 double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name));
111 cout << net_name << " = " << timing << endl;
112 }
113 cout << "==============" << endl;
114 }
115
116 static Model *buildModel(const map<String, String> &params,
117 TechModel *tech_model)
118 {
119 // Create the model specified
120 const String& model_name = params.at("ModelName");
121 Model *ms_model = ModelGen::createModel(model_name, model_name,
122 tech_model);
123
124 // Construct the model
125 // Read all parameters the model requires
126 const vector<String>* parameter_names = ms_model->getParameterNames();
127 // For all parameters, grab values from the config file
128 for(vector<String>::const_iterator it = parameter_names->begin();
129 it != parameter_names->end(); ++it)
130 {
131 const String& parameter_name = *it;
132 // If it exists in the config file, set the parameter
133 if(params.count(parameter_name) > 0)
134 {
135 ms_model->setParameter(parameter_name,
136 params.at(parameter_name));
137 }
138 }
139
140 ms_model->construct();
141
142 // Update the model
143 // Read all properties the model requires
144 const vector<String>* property_names = ms_model->getPropertyNames();
145 // For all properties, grab values from the config file
146 for(vector<String>::const_iterator it = property_names->begin();
147 it != property_names->end(); ++it)
148 {
149 const String& property_name = *it;
150 // If it exists in the config file, set the parameter
151 if(params.count(property_name) > 0)
152 {
153 ms_model->setProperty(property_name,
154 params.at(property_name));
155 }
156 }
157 ms_model->update();
158
159 // Evaluate the model
160 // Perform timing optimization if needed
161 if(params.find("IsPerformTimingOptimization") != params.end() &&
162 params.at("IsPerformTimingOptimization").toBool())
163 {
164 performTimingOpt(params, ms_model);
165 }
166 ms_model->evaluate();
167
168 // Report timing if needed
169 if(params.count("IsReportTiming") > 0 &&
170 params.at("IsReportTiming") != "false")
171 {
172 reportTiming(params, ms_model);
173 }
174
175 return ms_model;
176 }
177
178 static const void* processQuery(const String& query_str_,
179 Model *ms_model, bool is_print_)
180 {
181 vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR);
182 ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_);
183 String query_type = type_split[0];
184
185 vector<String> detail_split =
186 type_split[1].splitByString(Model::DETAIL_SEPARATOR);
187
188 ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
189 String query_detail = detail_split[1];
190
191 vector<String> subfield_split =
192 detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR);
193
194 ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)),
195 "[Error] Invalid query format: " + query_str_);
196
197 String query_hier = subfield_split[0];
198 String query_subfield = "";
199
200 if(subfield_split.size() == 2)
201 {
202 query_subfield = subfield_split[1];
203 }
204
205 const void* query_result = ms_model->parseQuery(query_type, query_hier,
206 query_subfield);
207 if(query_type == "Property")
208 {
209 const PropertyMap* property = (const PropertyMap*)query_result;
210 if(is_print_)
211 {
212 cout << *property;
213 }
214 }
215 else if(query_type == "Parameter")
216 {
217 const ParameterMap* parameter = (const ParameterMap*)query_result;
218 if(is_print_)
219 {
220 cout << *parameter;
221 }
222 }
223 else if(query_type.contain("Hier"))
224 {
225 const Model* model = (const Model*)query_result;
226 if(is_print_)
227 {
228 model->printHierarchy(query_type, query_subfield, "", query_detail, cout);
229 }
230 }
231 else
232 {
233 const Result* result = (const Result*)query_result;
234 if(is_print_)
235 {
236 result->print(query_type + Model::TYPE_SEPARATOR + query_hier +
237 Model::SUBFIELD_SEPARATOR + query_subfield, query_detail, cout);
238 }
239 }
240 return query_result;
241 }
242
243 void processQuery(const vector<String> &queries,
244 Model *ms_model, vector<String> &outputs)
245 {
246 for(unsigned int i = 0; i < queries.size(); ++i)
247 {
248 const String& curr_query = queries[i];
249 processQuery(curr_query, ms_model, true);
250
251 }
252 }
253
254 static TechModel* constructTechModel(const map<String, String>& params)
255 {
256 // Allocate static TechModel instance
257 const String& electrical_tech_model_filename =
258 params.at("ElectricalTechModelFilename");
259
260 TechModel* tech_model = new TechModel();
261 tech_model->readFile(electrical_tech_model_filename);
262
263 if (params.count("PhotonicTechModelFilename") != 0) {
264 const String& photonic_tech_model_filename =
265 params.at("PhotonicTechModelFilename");
266 tech_model->readFile(photonic_tech_model_filename);
267 }
268
269 // Allocate static StdCellLib instance
270 StdCellLib* std_cell_lib = new StdCellLib(tech_model);
271
272 // Set the StdCellLib pointer in static TechModel instance
273 tech_model->setStdCellLib(std_cell_lib);
274 return tech_model;
275 }
276
277 Model *initialize(const char *config_file_name, map<String, String> &config)
278 {
279 // Init the log file
280 Log::allocate("/tmp/dsent.log");
281
282 // Init the config file
283 LibUtil::readFile(config_file_name, config);
284
285 // Overwrite the technology file
286 TechModel *tech_model = constructTechModel(config);
287
288 // Build the specified model in the config file
289 return buildModel(config, tech_model);
290 }
291
292 void finalize(map<String, String> &config, Model *ms_model)
293 {
294 // Delete the model
295 delete ms_model;
296
297 // Discard all the (key, value) pairs.
298 config.clear();
299
300 // Release the log file
301 Log::release();
302 }
303
304 void run(const map<String, String> &params, Model *ms_model,
305 map<string, double> &outputs)
306 {
307 // Process the specified queries
308 const auto &it = params.find("EvaluateString");
309 if(it == params.end()) {
310 return;
311 }
312
313 String eval_str = it->second;
314
315 if (eval_str == "") {
316 return;
317 }
318
319 DSENTCalculator calc;
320 calc.evaluateString(eval_str, params, ms_model, outputs);
321 }
322
323 DSENTCalculator::DSENTCalculator() {}
324
325 DSENTCalculator::~DSENTCalculator() {}
326
327 double DSENTCalculator::getEnvVar(const String& var_name_,
328 const map<String, String> &config,
329 Model *ms_model) const
330 {
331 if (m_var_.keyExist(var_name_)) {
332 return m_var_.get(var_name_);
333 } else if (config.count(var_name_) > 0) {
334 return config.at(var_name_);
335 } else {
336 // Wish there was a way to not have to pass in a stream if we aren't
337 // doing anything with it
338 const Result* result = (const Result*)DSENT::processQuery(
339 var_name_ + "@0", ms_model, false);
340 return result->calculateSum();
341 }
342 }
343 } // namespace DSENT