diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 16:16:00 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 16:16:00 -0500 |
commit | c1aecc05e6cad977423a15905f6bd4f5f33b53c8 (patch) | |
tree | b013259fe0a6ec5e4fca8c47f757b50e92871f4d /ext/dsent/DSENT.cc | |
parent | e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 (diff) | |
download | gem5-c1aecc05e6cad977423a15905f6bd4f5f33b53c8.tar.xz |
ext: dsent: adds a Python interface, drops C++ one
This patch extensively modifies DSENT so that it can be accessed using Python.
To access the Python interface, DSENT needs to compiled as a shared library.
For this purpose a CMakeLists.txt file has been added. Some of the code that
is not required is being removed.
Diffstat (limited to 'ext/dsent/DSENT.cc')
-rw-r--r-- | ext/dsent/DSENT.cc | 478 |
1 files changed, 199 insertions, 279 deletions
diff --git a/ext/dsent/DSENT.cc b/ext/dsent/DSENT.cc index 576cbbebc..da9163a50 100644 --- a/ext/dsent/DSENT.cc +++ b/ext/dsent/DSENT.cc @@ -1,237 +1,209 @@ -#include "DSENT.h" +/* Copyright (c) 2012 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include <cstdlib> #include <iostream> -namespace DSENT -{ - Model* DSENT::ms_model_ = NULL; - bool DSENT::ms_is_verbose_ = false; - - void DSENT::run(int argc_, char** argv_) - { - // Initialize DSENT framework (setup log file, config file, ...) - initialize(argc_, argv_); - - // Build the specified model in the config file - buildModel(); - - // Process the specified queries - processQuery(); - // Process the specified evaluation - processEvaluate(); - - // Finalize DSENT framework (close log file, ...) - finalize(); - return; - } - - void DSENT::setRuntimeOptions(OptionParser* option_parser_) - { - option_parser_->addOption("-cfg", "ConfigFilename", true, "filename", false, "", - "Specify the config filename."); - - option_parser_->addOption("-available_models", "IsListModels", false, "", true, "false", - "List available DSENT models."); - - option_parser_->addOption("-log", "LogFilename", true, "filename", true, "./dsent.log", - "Specify the log filename."); - - option_parser_->addOption("-overwrite", "OverwriteString", true, "options", true, "", - "Overwrite dynamically the options set in the config file. Options are separated by a comma (;)."); - - option_parser_->addOption("-overwrite_tech", "OverwriteTechString", true, "options", true, "", - "Overwrite dynamically the options set in the technology file. Options are separated by a comma (;)."); - - option_parser_->addOption("-print_config", "IsPrintConfig", false, "", true, "false", - "Print the config used at DSENT runtime."); - - option_parser_->addOption("-query", "QueryString", true, "query string", true, "", - "Specify the list of items to query. This command is the same as owerwriting the 'QueryString'."); +#include "DSENT.h" +#include "model/std_cells/StdCellLib.h" - option_parser_->addOption("-eval", "EvaluateString", true, "evaluate string", true, "", - "Specify the list of statements to evaluate. This command is the same as owerwriting the 'EvaluateString'."); +using namespace std; - option_parser_->addOption("-verbose", "IsVerbose", false, "", true, "false", - "Enable verbose mode which prints out more detailed messages."); - return; - } - - void DSENT::initialize(int argc_, char** argv_) +namespace DSENT +{ + static void performTimingOpt(const map<String, String> ¶ms, + Model *ms_model) { - OptionParser* option_parser = new OptionParser(); + // Get the frequency it is optimizing to + double freq = params.at("Frequency").toDouble(); - // Init the option parser and setup available options - setRuntimeOptions(option_parser); + // Get all the starting net names + const vector<String>& start_net_names = + params.at("TimingOptimization->StartNetNames").split("[,]"); - // Parse the options - option_parser->parseArguments(argc_, argv_); + ASSERT((start_net_names.size() > 0), + "[Error] Expecting net names in TimingOptimization->StartNetNames"); - // If -available_models is specified, print out a list of available - // models and exit DSENT. - if(option_parser->get("IsListModels").toBool()) + if(start_net_names[0] == "*") { - ModelGen::printAvailableModels(); - exit(0); - } - - // Init the log file - Log::allocate(option_parser->get("LogFilename")); - - // Init the config file - Config::allocate(option_parser->get("ConfigFilename")); - Config* dsent_config = Config::getSingleton(); - - // Overwrite the existing options - dsent_config->readString(option_parser->get("OverwriteString")); - - // Overwrite the technology file - dsent_config->constructTechModel(option_parser->get("OverwriteTechString")); + // Optimize from all input ports + ElectricalModel* electrical_model = (ElectricalModel*)ms_model; - ms_is_verbose_ = option_parser->get("IsVerbose").toBool(); + ElectricalTimingOptimizer timing_optimizer( + "Optimizer", electrical_model->getTechModel()); + timing_optimizer.setModel(electrical_model); + timing_optimizer.construct(); + timing_optimizer.update(); - // Overwrite the query string if it is specified from command line - if(option_parser->get("QueryString").size() != 0) - { - dsent_config->set("QueryString", option_parser->get("QueryString")); - } - // Overwrite the evaluation string if it is specified from command line - if(option_parser->get("EvaluateString").size() != 0) - { - dsent_config->set("EvaluateString", option_parser->get("EvaluateString")); - } + ElectricalTimingTree timing_tree( + timing_optimizer.getInstanceName(), &timing_optimizer); - // Print the config used for this run - if(option_parser->get("IsPrintConfig").toBool()) - { - if(ms_is_verbose_) + const Map<PortInfo*>* input_ports = timing_optimizer.getInputs(); + Map<PortInfo*>::ConstIterator it_begin = input_ports->begin(); + Map<PortInfo*>::ConstIterator it_end = input_ports->end(); + Map<PortInfo*>::ConstIterator it; + for(it = it_begin; it != it_end; ++it) { - cout << "Configuration:" << endl; - cout << "==============" << endl; + const String& net_name = it->first; + Log::printLine("Optimizing net: " + net_name); + timing_tree.performTimingOpt( + timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq); } - cout << *dsent_config; - if(ms_is_verbose_) + // Loop the second times + for(it = it_begin; it != it_end; ++it) { - cout << "==============" << endl; + const String& net_name = it->first; + Log::printLine("Optimizing net: " + net_name); } } + else + { + // TODO : parse the net name so that we could do hierarchical optimization + // Currently we can only optimize timing at the top level + ElectricalModel* electrical_model = (ElectricalModel*)ms_model; + ElectricalTimingTree timing_tree( + electrical_model->getInstanceName(), electrical_model); - delete option_parser; - return; + for(unsigned int i = 0; i < start_net_names.size(); ++i) + { + const String& net_name = start_net_names[i]; + timing_tree.performTimingOpt( + electrical_model->getNet(net_name), 1.0 / freq); + } + } } - void DSENT::buildModel() + static void reportTiming(const map<String, String> ¶ms, Model *ms_model) { - Config* dsent_config = Config::getSingleton(); + // Get all the starting net names + const vector<String>& start_net_names = + params.at("ReportTiming->StartNetNames").split("[,]"); + + ElectricalModel* electrical_model = (ElectricalModel*)ms_model; + ElectricalTimingTree timing_tree( + electrical_model->getInstanceName(), electrical_model); + cout << "Report timing:" << endl; + cout << "==============" << endl; + for(unsigned int i = 0; i < start_net_names.size(); ++i) + { + const String& net_name = start_net_names[i]; + double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name)); + cout << net_name << " = " << timing << endl; + } + cout << "==============" << endl; + } + + static Model *buildModel(const map<String, String> ¶ms, + TechModel *tech_model) + { // Create the model specified - const String& model_name = dsent_config->get("ModelName"); - ms_model_ = ModelGen::createModel(model_name, model_name, dsent_config->getTechModel()); + const String& model_name = params.at("ModelName"); + Model *ms_model = ModelGen::createModel(model_name, model_name, + tech_model); // Construct the model // Read all parameters the model requires - const vector<String>* parameter_names = ms_model_->getParameterNames(); + const vector<String>* parameter_names = ms_model->getParameterNames(); // For all parameters, grab values from the config file - for(vector<String>::const_iterator it = parameter_names->begin(); it != parameter_names->end(); ++it) + for(vector<String>::const_iterator it = parameter_names->begin(); + it != parameter_names->end(); ++it) { const String& parameter_name = *it; // If it exists in the config file, set the parameter - if(dsent_config->keyExist(parameter_name)) + if(params.count(parameter_name) > 0) { - ms_model_->setParameter(parameter_name, dsent_config->get(parameter_name)); + ms_model->setParameter(parameter_name, + params.at(parameter_name)); } } - ms_model_->construct(); + + ms_model->construct(); // Update the model // Read all properties the model requires - const vector<String>* property_names = ms_model_->getPropertyNames(); + const vector<String>* property_names = ms_model->getPropertyNames(); // For all properties, grab values from the config file - for(vector<String>::const_iterator it = property_names->begin(); it != property_names->end(); ++it) + for(vector<String>::const_iterator it = property_names->begin(); + it != property_names->end(); ++it) { const String& property_name = *it; // If it exists in the config file, set the parameter - if(dsent_config->keyExist(property_name)) + if(params.count(property_name) > 0) { - ms_model_->setProperty(property_name, dsent_config->get(property_name)); + ms_model->setProperty(property_name, + params.at(property_name)); } } - ms_model_->update(); + ms_model->update(); // Evaluate the model // Perform timing optimization if needed - if(dsent_config->getIfKeyExist("IsPerformTimingOptimization", "false").toBool()) + if(params.find("IsPerformTimingOptimization") != params.end() && + params.at("IsPerformTimingOptimization").toBool()) { - performTimingOpt(); + performTimingOpt(params, ms_model); } - ms_model_->evaluate(); + ms_model->evaluate(); // Report timing if needed - if(dsent_config->getIfKeyExist("IsReportTiming", "false").toBool()) + if(params.count("IsReportTiming") > 0 && + params.at("IsReportTiming") != "false") { - reportTiming(); + reportTiming(params, ms_model); } - return; - } - - void DSENT::processQuery() - { - Config* dsent_config = Config::getSingleton(); - vector<String> queries = dsent_config->get("QueryString").split(" ;\r\n"); - - if(ms_is_verbose_) - { - cout << "Query results:" << endl; - cout << "==============" << endl; - } - - for(unsigned int i = 0; i < queries.size(); ++i) - { - const String& curr_query = queries[i]; - - if(ms_is_verbose_) - { - String str = "Process query: '" + curr_query + "'"; - cout << str << endl; - cout << String(str.size(), '-') << endl; - } - - processQuery(curr_query, true); - - if(ms_is_verbose_) - { - cout << endl; - } - } - if(ms_is_verbose_) - { - cout << "==============" << endl; - } - return; + return ms_model; } - const void* DSENT::processQuery(const String& query_str_, bool is_print_) + static const void* processQuery(const String& query_str_, + Model *ms_model, bool is_print_) { vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR); ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_); String query_type = type_split[0]; - vector<String> detail_split = type_split[1].splitByString(Model::DETAIL_SEPARATOR); + vector<String> detail_split = + type_split[1].splitByString(Model::DETAIL_SEPARATOR); + ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_); String query_detail = detail_split[1]; - vector<String> subfield_split = detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR); - ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), "[Error] Invalid query format: " + query_str_); + vector<String> subfield_split = + detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR); + + ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), + "[Error] Invalid query format: " + query_str_); + String query_hier = subfield_split[0]; String query_subfield = ""; + if(subfield_split.size() == 2) { query_subfield = subfield_split[1]; } - const void* query_result = ms_model_->parseQuery(query_type, query_hier, query_subfield); + const void* query_result = ms_model->parseQuery(query_type, query_hier, + query_subfield); if(query_type == "Property") { const PropertyMap* property = (const PropertyMap*)query_result; @@ -268,156 +240,104 @@ namespace DSENT return query_result; } - void DSENT::finalize() + void processQuery(const vector<String> &queries, + Model *ms_model, vector<String> &outputs) { - // Release the constructed model - delete ms_model_; - ms_model_ = NULL; - - // Release the config file - Config::release(); - - // Release the log file - Log::release(); + for(unsigned int i = 0; i < queries.size(); ++i) + { + const String& curr_query = queries[i]; + processQuery(curr_query, ms_model, true); - return; + } } - void DSENT::performTimingOpt() + static TechModel* constructTechModel(const map<String, String>& params) { - Config* dsent_config = Config::getSingleton(); + // Allocate static TechModel instance + const String& electrical_tech_model_filename = + params.at("ElectricalTechModelFilename"); - // Get the frequency it is optimizing to - double freq = dsent_config->get("Frequency").toDouble(); + TechModel* tech_model = new TechModel(); + tech_model->readFile(electrical_tech_model_filename); - // Get all the starting net names - const vector<String>& start_net_names = dsent_config->get("TimingOptimization->StartNetNames").split("[,]"); - - ASSERT((start_net_names.size() > 0), "[Error] Expecting net names in TimingOptimization->StartNetNames"); - - if(start_net_names[0] == "*") - { - // Optimize from all input ports - ElectricalModel* electrical_model = (ElectricalModel*)ms_model_; - - ElectricalTimingOptimizer timing_optimizer("Optimizer", electrical_model->getTechModel()); - timing_optimizer.setModel(electrical_model); - timing_optimizer.construct(); - timing_optimizer.update(); + if (params.count("PhotonicTechModelFilename") != 0) { + const String& photonic_tech_model_filename = + params.at("PhotonicTechModelFilename"); + tech_model->readFile(photonic_tech_model_filename); + } - ElectricalTimingTree timing_tree(timing_optimizer.getInstanceName(), &timing_optimizer); + // Allocate static StdCellLib instance + StdCellLib* std_cell_lib = new StdCellLib(tech_model); - const Map<PortInfo*>* input_ports = timing_optimizer.getInputs(); - Map<PortInfo*>::ConstIterator it_begin = input_ports->begin(); - Map<PortInfo*>::ConstIterator it_end = input_ports->end(); - Map<PortInfo*>::ConstIterator it; - for(it = it_begin; it != it_end; ++it) - { - const String& net_name = it->first; - Log::printLine("Optimizing net: " + net_name); - timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq); - //timing_tree.performTimingOpt(electrical_model->getNet(net_name, makeNetIndex(0)), 1.0 / freq); - } - // Loop the second times - for(it = it_begin; it != it_end; ++it) - { - const String& net_name = it->first; - Log::printLine("Optimizing net: " + net_name); - //timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq); - } - } - else - { - // TODO : parse the net name so that we could do hierarchical optimization - // Currently we can only optimize timing at the top level - ElectricalModel* electrical_model = (ElectricalModel*)ms_model_; - ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model); - for(unsigned int i = 0; i < start_net_names.size(); ++i) - { - const String& net_name = start_net_names[i]; - timing_tree.performTimingOpt(electrical_model->getNet(net_name), 1.0 / freq); - } - } - return; + // Set the StdCellLib pointer in static TechModel instance + tech_model->setStdCellLib(std_cell_lib); + return tech_model; } - void DSENT::reportTiming() + Model *initialize(const char *config_file_name, map<String, String> &config) { - Config* dsent_config = Config::getSingleton(); + // Init the log file + Log::allocate("/tmp/dsent.log"); - // Get all the starting net names - const vector<String>& start_net_names = dsent_config->get("ReportTiming->StartNetNames").split("[,]"); + // Init the config file + LibUtil::readFile(config_file_name, config); - ElectricalModel* electrical_model = (ElectricalModel*)ms_model_; - ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model); + // Overwrite the technology file + TechModel *tech_model = constructTechModel(config); - cout << "Report timing:" << endl; - cout << "==============" << endl; - for(unsigned int i = 0; i < start_net_names.size(); ++i) - { - const String& net_name = start_net_names[i]; - double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name)); - cout << net_name << " = " << timing << endl; - } - cout << "==============" << endl; - return; + // Build the specified model in the config file + return buildModel(config, tech_model); } - void DSENT::processEvaluate() + void finalize(map<String, String> &config, Model *ms_model) { - Config* dsent_config = Config::getSingleton(); - - // Return if EvaluatString is empty or not exists - if(!dsent_config->keyExist("EvaluateString")) return; + // Delete the model + delete ms_model; - String eval_str = dsent_config->get("EvaluateString"); + // Discard all the (key, value) pairs. + config.clear(); - if(eval_str == "") return; + // Release the log file + Log::release(); + } - if(ms_is_verbose_) - { - cout << "Eval results:" << endl; - cout << "==============" << endl; + void run(const map<String, String> ¶ms, Model *ms_model, + map<string, double> &outputs) + { + // Process the specified queries + const auto &it = params.find("EvaluateString"); + if(it == params.end()) { + return; } - //if(ms_is_verbose_) - //{ - // String str = "Process evaluation: '" + eval_str + "'"; - // cout << str << endl; - // cout << String(str.size(), '-') << endl; - //} - DSENTCalculator calc; - calc.evaluateString(eval_str); + String eval_str = it->second; - if(ms_is_verbose_) - { - cout << "==============" << endl; + if (eval_str == "") { + return; } - return; - return; + + DSENTCalculator calc; + calc.evaluateString(eval_str, params, ms_model, outputs); } - DSENT::DSENTCalculator::DSENTCalculator() - {} + DSENTCalculator::DSENTCalculator() {} - DSENT::DSENTCalculator::~DSENTCalculator() - {} + DSENTCalculator::~DSENTCalculator() {} - double DSENT::DSENTCalculator::getEnvVar(const String& var_name_) const + double DSENTCalculator::getEnvVar(const String& var_name_, + const map<String, String> &config, + Model *ms_model) const { - if(m_var_.keyExist(var_name_)) - { + if (m_var_.keyExist(var_name_)) { return m_var_.get(var_name_); - } - else if(Config::getSingleton()->keyExist(var_name_)) - { - return Config::getSingleton()->get(var_name_); - } - else - { - const Result* result = (const Result*)DSENT::processQuery(var_name_ + "@0", false); + } else if (config.count(var_name_) > 0) { + return config.at(var_name_); + } else { + // Wish there was a way to not have to pass in a stream if we aren't + // doing anything with it + const Result* result = (const Result*)DSENT::processQuery( + var_name_ + "@0", ms_model, false); return result->calculateSum(); } } } // namespace DSENT - |