CGRA-ME
Mapper.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 #include <CGRA/Mapper.h>
12 
13 #include <regex>
14 
15 namespace {
16  // avoid static initialization order problems
17  const auto& all_mapper_name() { static std::string v = "AllMappers"; return v; }
18  const auto& all_mapper_prefix() { static std::string v = all_mapper_name() + "."; return v; }
19 }
20 
21 Mapper::Mapper(std::shared_ptr<CGRA> cgra, int timelimit)
22  : cgra(cgra)
23  , timelimit(timelimit)
24 { }
25 
27 {
28 }
29 
31  : m_mapper_makers()
32 {
33  registerMapper(all_mapper_name(), nullptr, false, "Default arg storage", common_defaults, {});
34 }
35 
36 std::unique_ptr<Mapper> MapperRegistry::createMapper(const std::string& mapper_id, std::shared_ptr<CGRA> cgra, int timelimit, const ConfigStore& args) const {
37  const auto lookup = m_mapper_makers.find(mapper_id);
38  if (lookup == m_mapper_makers.end()) {
39  throw std::logic_error("No mapper registered with ID `" + mapper_id + "'");
40  } else if (not lookup->second.maker) {
41  throw std::logic_error("Mapper `" + mapper_id + "' has an invalid maker function");
42  }
43  const auto& maker_desc = m_mapper_makers.at(mapper_id);
44  const auto& key_prefix = makeKeyPrefix(mapper_id);
45  const ConfigStore final_inis = getMapperArgs(mapper_id, args);
46  const auto key_is_unset = [&](const auto& kv) { return not final_inis.hasKey(key_prefix + kv.first); };
47  const auto first_unset_default = std::find_if(maker_desc.registered_defaults.begin(), maker_desc.registered_defaults.end(), key_is_unset);
48  if (first_unset_default != maker_desc.registered_defaults.end()) {
49  throw std::logic_error("Required key `" + first_unset_default->first + "' missing when creating mapper `" + mapper_id + "'");
50  }
51 
52  for (const auto& kv : final_inis) {
53  if (maker_desc.is_composite) {
54  if (kv.first.substr(0, key_prefix.size()) != key_prefix) { continue; } // skip checking keys not meant for this mapper
55  if (kv.first.substr(key_prefix.size()).find('.') != kv.first.npos) { continue; } // skip checking nested keys
56  }
57  const auto key_no_prefix = std::string(std::next(kv.first.begin(), key_prefix.size()), kv.first.end());
58  if (not maker_desc.hasMatchingArg(key_no_prefix)) {
59  throw std::logic_error("Given key `" + key_no_prefix + "' does not match any of the allowed arguments for `" + mapper_id + "'");
60  }
61  }
62 
63  return maker_desc.maker(cgra, timelimit, final_inis);
64 }
65 
67  std::string mapper_id, MapperMaker maker, bool is_composite, std::string mapper_description,
68  std::vector<ImplicitTuple<std::string, ImplicitlyToString, std::string>> required_arg_names_defaults_and_descriptions,
69  std::vector<std::pair<std::string, std::string>> optional_arg_regexes_and_descriptions
70 ) {
71  const auto lookup = m_mapper_makers.find(mapper_id);
72  if (lookup != m_mapper_makers.end()) {
73  throw std::logic_error("There is already a mapper registered with ID `" + mapper_id + "' that has description:\n" + lookup->second.description);
74  }
75 
77  std::move(maker), is_composite, std::move(mapper_description), {} ,{}
78  };
79 
80  for (auto& name_default_desc : required_arg_names_defaults_and_descriptions) {
81  const auto& arg_name = std::get<0>(name_default_desc);
82  desc.registered_defaults.addString(arg_name, std::move(std::get<1>(name_default_desc).impl));
83  desc.allowed_arg_regexes_and_documentation.insert({arg_name, {std::regex(arg_name), std::move(std::get<2>(name_default_desc))}});
84  }
85 
86  for (auto& regex_and_desc : optional_arg_regexes_and_descriptions) {
87  auto& arg_regex = std::get<0>(regex_and_desc);
88  desc.allowed_arg_regexes_and_documentation.insert({arg_regex, {std::regex(arg_regex), std::move(std::get<1>(regex_and_desc))}});
89  }
90 
91  m_mapper_makers.emplace(std::move(mapper_id), std::move(desc));
92 }
93 
95  ConfigStore result;
96  for (const auto& id_and_mapper : m_mapper_makers) {
97  set_all(result, addPrefix(id_and_mapper.second.registered_defaults, id_and_mapper.first + '.'));
98  }
99  return result;
100 }
101 
102 ConfigStore MapperRegistry::getMapperArgs(const std::string& mapper_id, const ConfigStore& args) const {
103  const auto& maker_desc = m_mapper_makers.at(mapper_id);
104  const ConfigStore requested_all_mapper_defaults = addPrefix(
105  filterKeys(
106  getEntriesForPrefix(args, all_mapper_prefix()),
107  [&](const auto& k) { return maker_desc.hasMatchingArg(k); }
108  ),
109  makeKeyPrefix(mapper_id)
110  );
111  const ConfigStore mapper_specific_keys = getEntriesForPrefix(args, mapper_id + '.'); // keys for just this mapper
112 
113  if (maker_desc.is_composite) {
114  // find nested keys -- keys that should apply to mappers called by this composite mapper
115  ConfigStore nested_keys;
116  for (const auto& kv : mapper_specific_keys) {
117  if (kv.first.find('.') != kv.first.npos) { // has dot <=> is nested
118  nested_keys.setString(kv.first, kv.second);
119  }
120  }
121 
122  // add the computed args to the given args -- this is how the mapper specific keys get passed down for composite mappers
123  return with_set(requested_all_mapper_defaults, args, nested_keys);
124  } else {
125  // just pass the defaults overridden by the mapper specific keys -- non-composite mappers expect no prefixes
126  return with_set(requested_all_mapper_defaults, mapper_specific_keys);
127  }
128 }
129 
130 void MapperRegistry::printMapperList(std::ostream& os) const {
131  for (const auto& id_and_mapper : m_mapper_makers) {
132  if (id_and_mapper.first == all_mapper_name()) { continue; }
133  os << id_and_mapper.first << "\n\t";
134  for (const auto a_char : id_and_mapper.second.description) {
135  os << a_char;
136  if (a_char == '\n') {
137  os << '\t';
138  }
139  }
140  os << '\n';
141  }
142 }
143 
144 void MapperRegistry::printDefaultsAsINI(std::ostream& os) const {
145  const auto& all_mapper_maker = m_mapper_makers.at(all_mapper_name());
146  const auto maybe_print_arg = [&,this](const auto& maker, const auto& kv, bool always_print) {
147  const auto& arg_docs = maker.allowed_arg_regexes_and_documentation.at(kv.first).second;
148  if (not arg_docs.empty()) {
149  os << "# " << arg_docs.substr(0,arg_docs.find_first_of('\n')) << '\n';
150  } else if (all_mapper_maker.registered_defaults.hasKey(kv.first) && all_mapper_maker.registered_defaults.getString(kv.first) == kv.second) {
151  // skip if no docs and same value as a AllMappers default
152  if (not always_print) {
153  return;
154  }
155  }
156  os << kv.first << " =";
157  if (not kv.second.empty()) {
158  os << " " << kv.second;
159  }
160  os << '\n';
161  };
162 
163  os << "#\n";
164  os << "# Gobal settings & defaults\n";
165  os << "#\n";
166  os << "\n";
167  os << '[' << all_mapper_name() << "]\n";
168 
169  for (const auto& kv : all_mapper_maker.registered_defaults) {
170  maybe_print_arg(all_mapper_maker, kv, true);
171  }
172 
173  os << "\n";
174  os << "#\n";
175  os << "# The rest are mapper-specific & overrides\n";
176  os << "#\n";
177 
178  for (const auto& name_and_maker : m_mapper_makers) {
179  if (name_and_maker.first == all_mapper_name()) { continue; } // handled above
180  const auto& maker = name_and_maker.second;
181  os << "\n";
182  os << '[' << name_and_maker.first << "]\n";
183  for (const auto& kv : maker.registered_defaults) {
184  maybe_print_arg(maker, kv, false);
185  }
186  }
187 }
188 
189 void MapperRegistry::printHelpForMapper(const std::string& mapper_id, const ConfigStore& args, std::ostream& os) const {
190  const char* indent = " ";
191  const auto configured_args = getEntriesForPrefix(getMapperArgs(mapper_id, args), makeKeyPrefix(mapper_id));
192  const auto maker = m_mapper_makers.at(mapper_id);
193 
194  os << maker.description << "\n\nThe following argument and argument regular expressions are allowed:\n";
195  for (const auto& name_and_regex_and_desc : maker.allowed_arg_regexes_and_documentation) {
196  os << "\nArg `" << name_and_regex_and_desc.first << "': ";
197  bool last_was_newline = false;
198  for (const auto& c : name_and_regex_and_desc.second.second) {
199  if (last_was_newline) os << indent;
200  os << c;
201  last_was_newline = c == '\n';
202  }
203  os << '\n';
204  if (maker.registered_defaults.hasKey(name_and_regex_and_desc.first)) { // is it a required argument?
205  os << indent << "configured value: `" << configured_args.getStringOr(name_and_regex_and_desc.first, "!UNSET!") << "'";
206  } else {
207  bool found_match = false;
208  for (const auto& kv : configured_args) {
209  if (regex_match(kv.first, name_and_regex_and_desc.second.first)) {
210  if (not std::exchange(found_match, true)) {
211  os << indent << "matching options passed:";
212  }
213  os << " " << kv.first << "=" << kv.second;
214  }
215  }
216  if (not found_match) {
217  os << indent << "(no matching options passed)";
218  }
219  }
220  os << "\n";
221  }
222 }
223 
225  static MapperRegistry default_registry({
226  {"arch_id", "", "Possible hint to heuristics"},
227  {"seed", 0, "Seed for all preudo-random operations in a mapper"},
228  {"verbosity", 0, "Controls logging. A value of 0 requests silence."},
229  {"max_threads", 1, "Maximum number of simultaneous threads that a mapper should try to use"},
230  {"model_dump_filename", "", "Set to non-empty to enable dumping of ILP models"},
231  {"model_IIS_dump_filename", "", "Set to non-empty to enable computation and dumping of ILP irreducable inconsistent subsystems"},
232  });
233  return default_registry;
234 }
235 
237  std::string mapper_id, MapperMaker maker, bool is_composite, std::string mapper_description,
238  std::vector<ImplicitTuple<std::string, ImplicitlyToString, std::string>> required_arg_names_defaults_and_descriptions,
239  std::vector<std::pair<std::string, std::string>> optional_arg_regexes_and_descriptions
240 ) {
241  try {
243  mapper_id, std::move(maker), is_composite, std::move(mapper_description),
244  required_arg_names_defaults_and_descriptions, optional_arg_regexes_and_descriptions
245  );
246  } catch (...) {
247  // Print & continue without re-throwing
248  // This way, just registering a bad mapper doesn't bring down the entire executable/dynamic library during static init.
249  // If it's really needed, then trying to create the mapper will fail anyway.
251  std::current_exception(), "==>",
252  ("Exception thrown while registering mapper `" + mapper_id + "'. Will continue, while ignoring this mapper").c_str()
253  );
254  }
255 }
MapperRegistry::printMapperList
void printMapperList(std::ostream &os) const
Print a message with every mapper's id and description.
Definition: Mapper.cpp:130
ImplicitTuple
Definition: TupleHash.h:105
MapperRegistry::getAllRegisteredArgDefaults
ConfigStore getAllRegisteredArgDefaults() const
Retrieve all registered default values for required arguments as a ConfigStore.
Definition: Mapper.cpp:94
MapperRegistry::m_mapper_makers
std::map< std::string, MakerAndDescription > m_mapper_makers
Definition: Mapper.h:161
MapperRegistry::makeKeyPrefix
const std::string makeKeyPrefix(const std::string &mapper_id) const
Definition: Mapper.h:137
ConfigStore::setString
void setString(std::string key, std::string value)
Definition: ConfigStore.h:128
MapperRegistry
Holds instances of mapper makers and creates mappers by ID, while resolving arguments.
Definition: Mapper.h:66
ConfigStore
Definition: ConfigStore.h:76
MapperRegistry::printHelpForMapper
void printHelpForMapper(const std::string &mapper_id, const ConfigStore &args, std::ostream &os) const
Print a detailed message about a mapper and the suggested args, including all required and optional a...
Definition: Mapper.cpp:189
Mapper::~Mapper
virtual ~Mapper()
Definition: Mapper.cpp:26
ConfigStore::hasKey
bool hasKey(const std::string &key) const
Definition: ConfigStore.h:209
MapperRegistry::printDefaultsAsINI
void printDefaultsAsINI(std::ostream &os) const
Print an INI file with all registered defaults and some comments based on short descriptions.
Definition: Mapper.cpp:144
Mapper::Mapper
Mapper(std::shared_ptr< CGRA > cgra, int timelimit)
Definition: Mapper.cpp:21
filterKeys
auto filterKeys(const ConfigStore &cs, Filter &&f) -> decltype(f(std::string()), ConfigStore())
Definition: ConfigStore.h:311
addPrefix
ConfigStore addPrefix(const ConfigStore &cs, const std::string &prefix)
Definition: ConfigStore.h:298
set_all
ConfigStore & set_all(ConfigStore &into, const ConfigStore &from)
Definition: ConfigStore.h:252
with_set
ConfigStore with_set(ConfigStore into, const ConfigStore &from1, const CSes &... froms)
Definition: ConfigStore.h:279
AutoRegisterMapper::getDefaultMutableRegisty
static MapperRegistry & getDefaultMutableRegisty()
Definition: Mapper.cpp:224
MapperMaker
std::function< std::unique_ptr< Mapper >(std::shared_ptr< CGRA >, int, const ConfigStore &)> MapperMaker
Function type for registering mappers.
Definition: Mapper.h:44
Mapper.h
MapperRegistry::getMapperArgs
ConfigStore getMapperArgs(const std::string &mapper_id, const ConfigStore &args) const
Compute the arguments that would be passed when creating mapper mapper_id.
Definition: Mapper.cpp:102
AutoRegisterMapper::AutoRegisterMapper
AutoRegisterMapper(std::string mapper_id, MapperMaker maker, bool is_composite, std::string mapper_description, std::vector< ImplicitTuple< std::string, ImplicitlyToString, std::string >> required_arg_names_defaults_and_descriptions, std::vector< std::pair< std::string, std::string >> optional_arg_regexes_and_descriptions)
Register a mapper with the default registry. See MapperRegistry::registerMapper for documentation.
Definition: Mapper.cpp:236
MapperRegistry::registerMapper
void registerMapper(std::string mapper_id, MapperMaker maker, bool is_composite, std::string mapper_description, std::vector< ImplicitTuple< std::string, ImplicitlyToString, std::string >> required_arg_names_defaults_and_descriptions, std::vector< std::pair< std::string, std::string >> optional_arg_regexes_and_descriptions)
Register a new mapper under the name mapper_id.
Definition: Mapper.cpp:66
getEntriesForPrefix
ConfigStore getEntriesForPrefix(const ConfigStore &cs, const std::string &prefix)
Definition: ConfigStore.h:285
MapperRegistry::createMapper
std::unique_ptr< Mapper > createMapper(const std::string &mapper_id, std::shared_ptr< CGRA > cgra, int timelimit, const ConfigStore &args) const
Given a mapper_id, create an instance of that mapper with the given arguments.
Definition: Mapper.cpp:36
printExceptionToOutAndErr
void printExceptionToOutAndErr(std::exception_ptr eptr, const char *line_prefix, const char *message)
Definition: Exception.h:134
MapperRegistry::MakerAndDescription
Definition: Mapper.h:141
MapperRegistry::MapperRegistry
MapperRegistry(std::vector< ImplicitTuple< std::string, ImplicitlyToString, std::string >> common_defaults)
Initialize with some common defaults.
Definition: Mapper.cpp:30