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 */ |
21 22#include <cstdlib> 23#include <iostream> 24
|
25#include "DSENT.h" 26#include "model/std_cells/StdCellLib.h" 27 28using namespace std; 29 |
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> ¶ms, 33 Model *ms_model) |
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(); |
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("[,]"); |
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"); |
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] == "*") |
46 {
|
74 ModelGen::printAvailableModels();
75 exit(0);
76 }
|
47 // Optimize from all input ports 48 ElectricalModel* electrical_model = (ElectricalModel*)ms_model; |
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(); |
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); |
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) |
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); |
69 }
|
112 cout << *dsent_config;
|
70
|
114 if(ms_is_verbose_)
|
71 // Loop the second times 72 for(it = it_begin; it != it_end; ++it) |
73 {
|
116 cout << "==============" << endl;
|
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
|
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 } |
93 } 94
|
124 void DSENT::buildModel()
|
95 static void reportTiming(const map<String, String> ¶ms, Model *ms_model) |
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("[,]"); |
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> ¶ms, 117 TechModel *tech_model) 118 { |
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); |
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(); |
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) |
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) |
134 {
|
142 ms_model_->setParameter(parameter_name, dsent_config->get(parameter_name));
|
135 ms_model->setParameter(parameter_name, 136 params.at(parameter_name)); |
137 } 138 }
|
145 ms_model_->construct();
|
139
|
140 ms_model->construct(); 141 |
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(); |
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) |
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) |
152 {
|
157 ms_model_->setProperty(property_name, dsent_config->get(property_name));
|
153 ms_model->setProperty(property_name, 154 params.at(property_name)); |
155 } 156 }
|
160 ms_model_->update();
|
157 ms_model->update(); |
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()) |
163 {
|
166 performTimingOpt();
|
164 performTimingOpt(params, ms_model); |
165 }
|
168 ms_model_->evaluate();
|
166 ms_model->evaluate(); |
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") |
171 {
|
173 reportTiming();
|
172 reportTiming(params, ms_model); |
173 } 174
|
176 return;
|
175 return ms_model; |
176 } 177
|
179 void DSENT::processQuery()
|
178 static const void* processQuery(const String& query_str_, 179 Model *ms_model, bool is_print_) |
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 {
|
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 |
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 |
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
|
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); |
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
|
271 void DSENT::finalize()
|
243 void processQuery(const vector<String> &queries, 244 Model *ms_model, vector<String> &outputs) |
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); |
250
|
277 // Release the config file
278 Config::release();
279
280 // Release the log file
281 Log::release();
282
283 return;
|
251 } |
252 } 253
|
286 void DSENT::performTimingOpt()
|
254 static TechModel* constructTechModel(const map<String, String>& params) |
255 {
|
288 Config* dsent_config = Config::getSingleton();
|
256 // Allocate static TechModel instance 257 const String& electrical_tech_model_filename = 258 params.at("ElectricalTechModelFilename"); |
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); |
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 } |
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); |
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; |
275 } 276
|
344 void DSENT::reportTiming()
|
277 Model *initialize(const char *config_file_name, map<String, String> &config) |
278 {
|
346 Config* dsent_config = Config::getSingleton();
|
279 // Init the log file 280 Log::allocate("/tmp/dsent.log"); |
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); |
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); |
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); |
290 } 291
|
366 void DSENT::processEvaluate()
|
292 void finalize(map<String, String> &config, Model *ms_model) |
293 {
|
368 Config* dsent_config = Config::getSingleton();
|
294 // Delete the model 295 delete ms_model; |
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(); |
299
|
373 String eval_str = dsent_config->get("EvaluateString");
|
300 // Release the log file 301 Log::release(); 302 } |
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> ¶ms, 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
|
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; |
314
|
392 if(ms_is_verbose_)
393 {
394 cout << "==============" << endl;
|
315 if (eval_str == "") { 316 return; |
317 }
|
396 return;
397 return;
|
318 319 DSENTCalculator calc; 320 calc.evaluateString(eval_str, params, ms_model, outputs); |
321 } 322
|
400 DSENT::DSENTCalculator::DSENTCalculator()
401 {}
|
323 DSENTCalculator::DSENTCalculator() {} |
324
|
403 DSENT::DSENTCalculator::~DSENTCalculator()
404 {}
|
325 DSENTCalculator::~DSENTCalculator() {} |
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 |
330 {
|
408 if(m_var_.keyExist(var_name_))
409 {
|
331 if (m_var_.keyExist(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); |
340 return result->calculateSum(); 341 } 342 } 343} // namespace DSENT
|
423
|
|