DSENT.cc revision 10447:a465576671d4
1#include "DSENT.h"
2
3#include <cstdlib>
4#include <iostream>
5
6namespace DSENT
7{
8    Model* DSENT::ms_model_ = NULL;
9    bool DSENT::ms_is_verbose_ = false;
10
11    void DSENT::run(int argc_, char** argv_)
12    {
13        // Initialize DSENT framework (setup log file, config file, ...)
14        initialize(argc_, argv_);
15
16        // Build the specified model in the config file
17        buildModel();
18
19        // Process the specified queries
20        processQuery();
21        // Process the specified evaluation
22        processEvaluate();
23
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())
73        {
74            ModelGen::printAvailableModels();
75            exit(0);
76        }
77
78        // Init the log file
79        Log::allocate(option_parser->get("LogFilename"));
80
81        // Init the config file
82        Config::allocate(option_parser->get("ConfigFilename"));
83        Config* dsent_config = Config::getSingleton();
84
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_)
108            {
109                cout << "Configuration:" << endl;
110                cout << "==============" << endl;
111            }
112            cout << *dsent_config;
113
114            if(ms_is_verbose_)
115            {
116                cout << "==============" << endl;
117            }
118        }
119
120        delete option_parser;
121        return;
122    }
123
124    void DSENT::buildModel()
125    {
126        Config* dsent_config = Config::getSingleton();
127
128        // 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());
131
132        // Construct the model
133        // Read all parameters the model requires
134        const vector<String>* parameter_names = ms_model_->getParameterNames();
135        // For all parameters, grab values from the config file
136        for(vector<String>::const_iterator it = parameter_names->begin(); it != parameter_names->end(); ++it)
137        {
138            const String& parameter_name = *it;
139            // If it exists in the config file, set the parameter
140            if(dsent_config->keyExist(parameter_name))
141            {
142                ms_model_->setParameter(parameter_name, dsent_config->get(parameter_name));
143            }
144        }
145        ms_model_->construct();
146
147        // Update the model
148        // Read all properties the model requires
149        const vector<String>* property_names = ms_model_->getPropertyNames();
150        // For all properties, grab values from the config file
151        for(vector<String>::const_iterator it = property_names->begin(); it != property_names->end(); ++it)
152        {
153            const String& property_name = *it;
154            // If it exists in the config file, set the parameter
155            if(dsent_config->keyExist(property_name))
156            {
157                ms_model_->setProperty(property_name, dsent_config->get(property_name));
158            }
159        }
160        ms_model_->update();
161
162        // Evaluate the model
163        // Perform timing optimization if needed
164        if(dsent_config->getIfKeyExist("IsPerformTimingOptimization", "false").toBool())
165        {
166            performTimingOpt();
167        }
168        ms_model_->evaluate();
169
170        // Report timing if needed
171        if(dsent_config->getIfKeyExist("IsReportTiming", "false").toBool())
172        {
173            reportTiming();
174        }
175
176        return;
177    }
178
179    void DSENT::processQuery()
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
221        vector<String> detail_split = type_split[1].splitByString(Model::DETAIL_SEPARATOR);
222        ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
223        String query_detail = detail_split[1];
224
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_);
227        String query_hier = subfield_split[0];
228        String query_subfield = "";
229        if(subfield_split.size() == 2)
230        {
231            query_subfield = subfield_split[1];
232        }
233
234        const void* query_result = ms_model_->parseQuery(query_type, query_hier, 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        }
243        else if(query_type == "Parameter")
244        {
245            const ParameterMap* parameter = (const ParameterMap*)query_result;
246            if(is_print_)
247            {
248                cout << *parameter;
249            }
250        }
251        else if(query_type.contain("Hier"))
252        {
253            const Model* model = (const Model*)query_result;
254            if(is_print_)
255            {
256                model->printHierarchy(query_type, query_subfield, "", query_detail, cout);
257            }
258        }
259        else
260        {
261            const Result* result = (const Result*)query_result;
262            if(is_print_)
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
271    void DSENT::finalize()
272    {
273        // Release the constructed model
274        delete ms_model_;
275        ms_model_ = NULL;
276
277        // Release the config file
278        Config::release();
279
280        // Release the log file
281        Log::release();
282
283        return;
284    }
285
286    void DSENT::performTimingOpt()
287    {
288        Config* dsent_config = Config::getSingleton();
289
290        // Get the frequency it is optimizing to
291        double freq = dsent_config->get("Frequency").toDouble();
292
293        // Get all the starting net names
294        const vector<String>& start_net_names = dsent_config->get("TimingOptimization->StartNetNames").split("[,]");
295
296        ASSERT((start_net_names.size() > 0), "[Error] Expecting net names in TimingOptimization->StartNetNames");
297
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;
342    }
343
344    void DSENT::reportTiming()
345    {
346        Config* dsent_config = Config::getSingleton();
347
348        // Get all the starting net names
349        const vector<String>& start_net_names = dsent_config->get("ReportTiming->StartNetNames").split("[,]");
350
351        ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
352        ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model);
353
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;
364    }
365
366    void DSENT::processEvaluate()
367    {
368        Config* dsent_config = Config::getSingleton();
369
370        // Return if EvaluatString is empty or not exists
371        if(!dsent_config->keyExist("EvaluateString")) return;
372
373        String eval_str = dsent_config->get("EvaluateString");
374
375        if(eval_str == "") return;
376
377        if(ms_is_verbose_)
378        {
379            cout << "Eval results:" << endl;
380            cout << "==============" << endl;
381        }
382
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);
391
392        if(ms_is_verbose_)
393        {
394            cout << "==============" << endl;
395        }
396        return;
397        return;
398    }
399
400    DSENT::DSENTCalculator::DSENTCalculator()
401    {}
402
403    DSENT::DSENTCalculator::~DSENTCalculator()
404    {}
405
406    double DSENT::DSENTCalculator::getEnvVar(const String& var_name_) const
407    {
408        if(m_var_.keyExist(var_name_))
409        {
410            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);
419            return result->calculateSum();
420        }
421    }
422} // namespace DSENT
423
424