DSENT.cc (10447:a465576671d4) DSENT.cc (10448:bc1a3b7ab5ef)
1#include "DSENT.h"
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 */
2
3#include <cstdlib>
4#include <iostream>
5
21
22#include <cstdlib>
23#include <iostream>
24
25#include "DSENT.h"
26#include "model/std_cells/StdCellLib.h"
27
28using namespace std;
29
6namespace DSENT
7{
30namespace DSENT
31{
8 Model* DSENT::ms_model_ = NULL;
9 bool DSENT::ms_is_verbose_ = false;
10
11 void DSENT::run(int argc_, char** argv_)
32 static void performTimingOpt(const map<String, String> &params,
33 Model *ms_model)
12 {
34 {
13 // Initialize DSENT framework (setup log file, config file, ...)
14 initialize(argc_, argv_);
35 // Get the frequency it is optimizing to
36 double freq = params.at("Frequency").toDouble();
15
37
16 // Build the specified model in the config file
17 buildModel();
38 // Get all the starting net names
39 const vector<String>& start_net_names =
40 params.at("TimingOptimization->StartNetNames").split("[,]");
18
41
19 // Process the specified queries
20 processQuery();
21 // Process the specified evaluation
22 processEvaluate();
42 ASSERT((start_net_names.size() > 0),
43 "[Error] Expecting net names in TimingOptimization->StartNetNames");
23
44
24 // Finalize DSENT framework (close log file, ...)
25 finalize();
26 return;
27 }
28
29 void DSENT::setRuntimeOptions(OptionParser* option_parser_)
30 {
31 option_parser_->addOption("-cfg", "ConfigFilename", true, "filename", false, "",
32 "Specify the config filename.");
33
34 option_parser_->addOption("-available_models", "IsListModels", false, "", true, "false",
35 "List available DSENT models.");
36
37 option_parser_->addOption("-log", "LogFilename", true, "filename", true, "./dsent.log",
38 "Specify the log filename.");
39
40 option_parser_->addOption("-overwrite", "OverwriteString", true, "options", true, "",
41 "Overwrite dynamically the options set in the config file. Options are separated by a comma (;).");
42
43 option_parser_->addOption("-overwrite_tech", "OverwriteTechString", true, "options", true, "",
44 "Overwrite dynamically the options set in the technology file. Options are separated by a comma (;).");
45
46 option_parser_->addOption("-print_config", "IsPrintConfig", false, "", true, "false",
47 "Print the config used at DSENT runtime.");
48
49 option_parser_->addOption("-query", "QueryString", true, "query string", true, "",
50 "Specify the list of items to query. This command is the same as owerwriting the 'QueryString'.");
51
52 option_parser_->addOption("-eval", "EvaluateString", true, "evaluate string", true, "",
53 "Specify the list of statements to evaluate. This command is the same as owerwriting the 'EvaluateString'.");
54
55 option_parser_->addOption("-verbose", "IsVerbose", false, "", true, "false",
56 "Enable verbose mode which prints out more detailed messages.");
57 return;
58 }
59
60 void DSENT::initialize(int argc_, char** argv_)
61 {
62 OptionParser* option_parser = new OptionParser();
63
64 // Init the option parser and setup available options
65 setRuntimeOptions(option_parser);
66
67 // Parse the options
68 option_parser->parseArguments(argc_, argv_);
69
70 // If -available_models is specified, print out a list of available
71 // models and exit DSENT.
72 if(option_parser->get("IsListModels").toBool())
45 if(start_net_names[0] == "*")
73 {
46 {
74 ModelGen::printAvailableModels();
75 exit(0);
76 }
47 // Optimize from all input ports
48 ElectricalModel* electrical_model = (ElectricalModel*)ms_model;
77
49
78 // Init the log file
79 Log::allocate(option_parser->get("LogFilename"));
50 ElectricalTimingOptimizer timing_optimizer(
51 "Optimizer", electrical_model->getTechModel());
52 timing_optimizer.setModel(electrical_model);
53 timing_optimizer.construct();
54 timing_optimizer.update();
80
55
81 // Init the config file
82 Config::allocate(option_parser->get("ConfigFilename"));
83 Config* dsent_config = Config::getSingleton();
56 ElectricalTimingTree timing_tree(
57 timing_optimizer.getInstanceName(), &timing_optimizer);
84
58
85 // Overwrite the existing options
86 dsent_config->readString(option_parser->get("OverwriteString"));
87
88 // Overwrite the technology file
89 dsent_config->constructTechModel(option_parser->get("OverwriteTechString"));
90
91 ms_is_verbose_ = option_parser->get("IsVerbose").toBool();
92
93 // Overwrite the query string if it is specified from command line
94 if(option_parser->get("QueryString").size() != 0)
95 {
96 dsent_config->set("QueryString", option_parser->get("QueryString"));
97 }
98 // Overwrite the evaluation string if it is specified from command line
99 if(option_parser->get("EvaluateString").size() != 0)
100 {
101 dsent_config->set("EvaluateString", option_parser->get("EvaluateString"));
102 }
103
104 // Print the config used for this run
105 if(option_parser->get("IsPrintConfig").toBool())
106 {
107 if(ms_is_verbose_)
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)
108 {
64 {
109 cout << "Configuration:" << endl;
110 cout << "==============" << endl;
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);
111 }
69 }
112 cout << *dsent_config;
113
70
114 if(ms_is_verbose_)
71 // Loop the second times
72 for(it = it_begin; it != it_end; ++it)
115 {
73 {
116 cout << "==============" << endl;
74 const String& net_name = it->first;
75 Log::printLine("Optimizing net: " + net_name);
117 }
118 }
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);
119
85
120 delete option_parser;
121 return;
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 }
122 }
123
93 }
94
124 void DSENT::buildModel()
95 static void reportTiming(const map<String, String> &params, Model *ms_model)
125 {
96 {
126 Config* dsent_config = Config::getSingleton();
97 // Get all the starting net names
98 const vector<String>& start_net_names =
99 params.at("ReportTiming->StartNetNames").split("[,]");
127
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 {
128 // Create the model specified
119 // Create the model specified
129 const String& model_name = dsent_config->get("ModelName");
130 ms_model_ = ModelGen::createModel(model_name, model_name, dsent_config->getTechModel());
120 const String& model_name = params.at("ModelName");
121 Model *ms_model = ModelGen::createModel(model_name, model_name,
122 tech_model);
131
132 // Construct the model
133 // Read all parameters the model requires
123
124 // Construct the model
125 // Read all parameters the model requires
134 const vector<String>* parameter_names = ms_model_->getParameterNames();
126 const vector* parameter_names = ms_model->getParameterNames();
135 // For all parameters, grab values from the config file
127 // For all parameters, grab values from the config file
136 for(vector<String>::const_iterator it = parameter_names->begin(); it != parameter_names->end(); ++it)
128 for(vector::const_iterator it = parameter_names->begin();
129 it != parameter_names->end(); ++it)
137 {
138 const String& parameter_name = *it;
139 // If it exists in the config file, set the parameter
130 {
131 const String& parameter_name = *it;
132 // If it exists in the config file, set the parameter
140 if(dsent_config->keyExist(parameter_name))
133 if(params.count(parameter_name) > 0)
141 {
134 {
142 ms_model_->setParameter(parameter_name, dsent_config->get(parameter_name));
135 ms_model->setParameter(parameter_name,
136 params.at(parameter_name));
143 }
144 }
137 }
138 }
145 ms_model_->construct();
146
139
140 ms_model->construct();
141
147 // Update the model
148 // Read all properties the model requires
142 // Update the model
143 // Read all properties the model requires
149 const vector<String>* property_names = ms_model_->getPropertyNames();
144 const vector* property_names = ms_model->getPropertyNames();
150 // For all properties, grab values from the config file
145 // For all properties, grab values from the config file
151 for(vector<String>::const_iterator it = property_names->begin(); it != property_names->end(); ++it)
146 for(vector::const_iterator it = property_names->begin();
147 it != property_names->end(); ++it)
152 {
153 const String& property_name = *it;
154 // If it exists in the config file, set the parameter
148 {
149 const String& property_name = *it;
150 // If it exists in the config file, set the parameter
155 if(dsent_config->keyExist(property_name))
151 if(params.count(property_name) > 0)
156 {
152 {
157 ms_model_->setProperty(property_name, dsent_config->get(property_name));
153 ms_model->setProperty(property_name,
154 params.at(property_name));
158 }
159 }
155 }
156 }
160 ms_model_->update();
157 ms_model->update();
161
162 // Evaluate the model
163 // Perform timing optimization if needed
158
159 // Evaluate the model
160 // Perform timing optimization if needed
164 if(dsent_config->getIfKeyExist("IsPerformTimingOptimization", "false").toBool())
161 if(params.find("IsPerformTimingOptimization") != params.end() &&
162 params.at("IsPerformTimingOptimization").toBool())
165 {
163 {
166 performTimingOpt();
164 performTimingOpt(params, ms_model);
167 }
165 }
168 ms_model_->evaluate();
166 ms_model->evaluate();
169
170 // Report timing if needed
167
168 // Report timing if needed
171 if(dsent_config->getIfKeyExist("IsReportTiming", "false").toBool())
169 if(params.count("IsReportTiming") > 0 &&
170 params.at("IsReportTiming") != "false")
172 {
171 {
173 reportTiming();
172 reportTiming(params, ms_model);
174 }
175
173 }
174
176 return;
175 return ms_model;
177 }
178
176 }
177
179 void DSENT::processQuery()
178 static const void* processQuery(const String& query_str_,
179 Model *ms_model, bool is_print_)
180 {
180 {
181 Config* dsent_config = Config::getSingleton();
182 vector<String> queries = dsent_config->get("QueryString").split(" ;\r\n");
183
184 if(ms_is_verbose_)
185 {
186 cout << "Query results:" << endl;
187 cout << "==============" << endl;
188 }
189
190 for(unsigned int i = 0; i < queries.size(); ++i)
191 {
192 const String& curr_query = queries[i];
193
194 if(ms_is_verbose_)
195 {
196 String str = "Process query: '" + curr_query + "'";
197 cout << str << endl;
198 cout << String(str.size(), '-') << endl;
199 }
200
201 processQuery(curr_query, true);
202
203 if(ms_is_verbose_)
204 {
205 cout << endl;
206 }
207 }
208 if(ms_is_verbose_)
209 {
210 cout << "==============" << endl;
211 }
212 return;
213 }
214
215 const void* DSENT::processQuery(const String& query_str_, bool is_print_)
216 {
217 vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR);
218 ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_);
219 String query_type = type_split[0];
220
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
221 vector<String> detail_split = type_split[1].splitByString(Model::DETAIL_SEPARATOR);
185 vector detail_split =
186 type_split[1].splitByString(Model::DETAIL_SEPARATOR);
187
222 ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
223 String query_detail = detail_split[1];
224
188 ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
189 String query_detail = detail_split[1];
190
225 vector<String> subfield_split = detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR);
226 ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), "[Error] Invalid query format: " + query_str_);
191 vector 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
227 String query_hier = subfield_split[0];
228 String query_subfield = "";
197 String query_hier = subfield_split[0];
198 String query_subfield = "";
199
229 if(subfield_split.size() == 2)
230 {
231 query_subfield = subfield_split[1];
232 }
233
200 if(subfield_split.size() == 2)
201 {
202 query_subfield = subfield_split[1];
203 }
204
234 const void* query_result = ms_model_->parseQuery(query_type, query_hier, query_subfield);
205 const void* query_result = ms_model->parseQuery(query_type, query_hier,
206 query_subfield);
235 if(query_type == "Property")
236 {
237 const PropertyMap* property = (const PropertyMap*)query_result;
238 if(is_print_)
239 {
240 cout << *property;
241 }
242 }

--- 20 unchanged lines hidden (view full) ---

263 {
264 result->print(query_type + Model::TYPE_SEPARATOR + query_hier +
265 Model::SUBFIELD_SEPARATOR + query_subfield, query_detail, cout);
266 }
267 }
268 return query_result;
269 }
270
207 if(query_type == "Property")
208 {
209 const PropertyMap* property = (const PropertyMap*)query_result;
210 if(is_print_)
211 {
212 cout << *property;
213 }
214 }

--- 20 unchanged lines hidden (view full) ---

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
271 void DSENT::finalize()
243 void processQuery(const vector<String> &queries,
244 Model *ms_model, vector<String> &outputs)
272 {
245 {
273 // Release the constructed model
274 delete ms_model_;
275 ms_model_ = NULL;
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);
276
250
277 // Release the config file
278 Config::release();
279
280 // Release the log file
281 Log::release();
282
283 return;
251 }
284 }
285
252 }
253
286 void DSENT::performTimingOpt()
254 static TechModel* constructTechModel(const map<String, String>& params)
287 {
255 {
288 Config* dsent_config = Config::getSingleton();
256 // Allocate static TechModel instance
257 const String& electrical_tech_model_filename =
258 params.at("ElectricalTechModelFilename");
289
259
290 // Get the frequency it is optimizing to
291 double freq = dsent_config->get("Frequency").toDouble();
260 TechModel* tech_model = new TechModel();
261 tech_model->readFile(electrical_tech_model_filename);
292
262
293 // Get all the starting net names
294 const vector<String>& start_net_names = dsent_config->get("TimingOptimization->StartNetNames").split("[,]");
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 }
295
268
296 ASSERT((start_net_names.size() > 0), "[Error] Expecting net names in TimingOptimization->StartNetNames");
269 // Allocate static StdCellLib instance
270 StdCellLib* std_cell_lib = new StdCellLib(tech_model);
297
271
298 if(start_net_names[0] == "*")
299 {
300 // Optimize from all input ports
301 ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
302
303 ElectricalTimingOptimizer timing_optimizer("Optimizer", electrical_model->getTechModel());
304 timing_optimizer.setModel(electrical_model);
305 timing_optimizer.construct();
306 timing_optimizer.update();
307
308 ElectricalTimingTree timing_tree(timing_optimizer.getInstanceName(), &timing_optimizer);
309
310 const Map<PortInfo*>* input_ports = timing_optimizer.getInputs();
311 Map<PortInfo*>::ConstIterator it_begin = input_ports->begin();
312 Map<PortInfo*>::ConstIterator it_end = input_ports->end();
313 Map<PortInfo*>::ConstIterator it;
314 for(it = it_begin; it != it_end; ++it)
315 {
316 const String& net_name = it->first;
317 Log::printLine("Optimizing net: " + net_name);
318 timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq);
319 //timing_tree.performTimingOpt(electrical_model->getNet(net_name, makeNetIndex(0)), 1.0 / freq);
320 }
321 // Loop the second times
322 for(it = it_begin; it != it_end; ++it)
323 {
324 const String& net_name = it->first;
325 Log::printLine("Optimizing net: " + net_name);
326 //timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq);
327 }
328 }
329 else
330 {
331 // TODO : parse the net name so that we could do hierarchical optimization
332 // Currently we can only optimize timing at the top level
333 ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
334 ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model);
335 for(unsigned int i = 0; i < start_net_names.size(); ++i)
336 {
337 const String& net_name = start_net_names[i];
338 timing_tree.performTimingOpt(electrical_model->getNet(net_name), 1.0 / freq);
339 }
340 }
341 return;
272 // Set the StdCellLib pointer in static TechModel instance
273 tech_model->setStdCellLib(std_cell_lib);
274 return tech_model;
342 }
343
275 }
276
344 void DSENT::reportTiming()
277 Model *initialize(const char *config_file_name, map<String, String> &config)
345 {
278 {
346 Config* dsent_config = Config::getSingleton();
279 // Init the log file
280 Log::allocate("/tmp/dsent.log");
347
281
348 // Get all the starting net names
349 const vector<String>& start_net_names = dsent_config->get("ReportTiming->StartNetNames").split("[,]");
282 // Init the config file
283 LibUtil::readFile(config_file_name, config);
350
284
351 ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
352 ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model);
285 // Overwrite the technology file
286 TechModel *tech_model = constructTechModel(config);
353
287
354 cout << "Report timing:" << endl;
355 cout << "==============" << endl;
356 for(unsigned int i = 0; i < start_net_names.size(); ++i)
357 {
358 const String& net_name = start_net_names[i];
359 double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name));
360 cout << net_name << " = " << timing << endl;
361 }
362 cout << "==============" << endl;
363 return;
288 // Build the specified model in the config file
289 return buildModel(config, tech_model);
364 }
365
290 }
291
366 void DSENT::processEvaluate()
292 void finalize(map<String, String> &config, Model *ms_model)
367 {
293 {
368 Config* dsent_config = Config::getSingleton();
294 // Delete the model
295 delete ms_model;
369
296
370 // Return if EvaluatString is empty or not exists
371 if(!dsent_config->keyExist("EvaluateString")) return;
297 // Discard all the (key, value) pairs.
298 config.clear();
372
299
373 String eval_str = dsent_config->get("EvaluateString");
300 // Release the log file
301 Log::release();
302 }
374
303
375 if(eval_str == "") return;
376
377 if(ms_is_verbose_)
378 {
379 cout << "Eval results:" << endl;
380 cout << "==============" << endl;
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;
381 }
382
311 }
312
383 //if(ms_is_verbose_)
384 //{
385 // String str = "Process evaluation: '" + eval_str + "'";
386 // cout << str << endl;
387 // cout << String(str.size(), '-') << endl;
388 //}
389 DSENTCalculator calc;
390 calc.evaluateString(eval_str);
313 String eval_str = it->second;
391
314
392 if(ms_is_verbose_)
393 {
394 cout << "==============" << endl;
315 if (eval_str == "") {
316 return;
395 }
317 }
396 return;
397 return;
318
319 DSENTCalculator calc;
320 calc.evaluateString(eval_str, params, ms_model, outputs);
398 }
399
321 }
322
400 DSENT::DSENTCalculator::DSENTCalculator()
401 {}
323 DSENTCalculator::DSENTCalculator() {}
402
324
403 DSENT::DSENTCalculator::~DSENTCalculator()
404 {}
325 DSENTCalculator::~DSENTCalculator() {}
405
326
406 double DSENT::DSENTCalculator::getEnvVar(const String& var_name_) const
327 double DSENTCalculator::getEnvVar(const String& var_name_,
328 const map<String, String> &config,
329 Model *ms_model) const
407 {
330 {
408 if(m_var_.keyExist(var_name_))
409 {
331 if (m_var_.keyExist(var_name_)) {
410 return m_var_.get(var_name_);
332 return m_var_.get(var_name_);
411 }
412 else if(Config::getSingleton()->keyExist(var_name_))
413 {
414 return Config::getSingleton()->get(var_name_);
415 }
416 else
417 {
418 const Result* result = (const Result*)DSENT::processQuery(var_name_ + "@0", false);
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);
419 return result->calculateSum();
420 }
421 }
422} // namespace DSENT
340 return result->calculateSum();
341 }
342 }
343} // namespace DSENT
423