CGRA-ME
PerfEngine.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/PerfEngine.h>
12 
13 PerfEngine::PerfEngine(std::string ini_path)
14 {
15  // Parse INI for each performance modelling, ignored if INI DNE
16  std::ifstream area_ini(ini_path + "/area.ini");
17  if(area_ini)
18  {
19  cgrame_msg(ini_path + "area.ini found.");
20  std::string area_ini_str(
21  (std::istreambuf_iterator<char>(area_ini)),
22  std::istreambuf_iterator<char>()
23  );
24  _parseAreaINI(area_ini_str);
25  }
26  else
27  {
28  cgrame_warn(ini_path + "area.ini not found. Skipping...");
29  }
30 
31  std::ifstream timing_ini(ini_path + "/timing.ini");
32  if(timing_ini)
33  {
34  cgrame_msg(ini_path + "timing.ini found.");
35  std::string timing_ini_str(
36  (std::istreambuf_iterator<char>(timing_ini)),
37  std::istreambuf_iterator<char>()
38  );
39  _parseTimingINI(timing_ini_str);
40  }
41  else
42  {
43  cgrame_warn(ini_path + "timing.ini not found. Skipping...");
44  }
45 
46  std::ifstream power_ini(ini_path + "/power.ini");
47  if(power_ini)
48  {
49  cgrame_msg(ini_path + "power.ini found.");
50  std::string power_ini_str(
51  (std::istreambuf_iterator<char>(power_ini)),
52  std::istreambuf_iterator<char>()
53  );
54  _parsePowerINI(power_ini_str);
55  }
56  else
57  {
58  cgrame_warn(ini_path + "power.ini not found. Skipping...");
59  }
60 }
61 
63 {
64 }
65 
66 double PerfEngine::_setModuleArea(Module* m, unsigned int level, bool last)
67 {
68  m->hierarchyLevel = level;
69  m->isLastInHierarchy = last;
70  std::string module_name = m->GenericName();
71  double module_area = 0.0;
72 
73  std::string delim = "_";
74  size_t index = module_name.find(delim);
75  std::string module_basename = module_name.substr(0, index);
76  std::string module_suffix = module_name.substr(index + 1, module_name.length());
77  std::string model_key = module_basename + "." + module_suffix;
78 
79  if (module_basename == "func")
80  {
81  // check whether it is already calculated
82  if (areaModels.count(model_key) != 0)
83  {
84  cgrame_msg("Area model of \"" + model_key + "\" found.");
85  m->area = areaModels[model_key];
86  m->submodsSet = false;
87  return areaModels[model_key];
88  }
89 
90  // return calculated func unit area
91  size_t start = 5;
92  size_t end = 0;
93  std::vector<std::string> ops;
94  do
95  {
96  end = module_name.find(delim, start);
97  std::string op = module_name.substr(start, end - start);
98  start = end + 1;
99  ops.push_back(op);
100  } while (end != std::string::npos);
101  std::string bus_width = ops[0];
102  for (int i = 1; i < ops.size(); i++)
103  {
104  std::string k = "op." + ops[i] + "_" + bus_width;
105  if (areaModels.count(k) == 0)
106  throw cgrame_error("Area model of \"" + k + "\" does not exist...");
107  cgrame_msg("Area model of \"" + k + "\" found.");
108  module_area += areaModels[k];
109  }
110 
111  // add entry to opt out re-calculation
112  cgrame_msg("Area model of \"" + model_key + "\" generated.");
113  areaModels[model_key] = module_area;
114  m->area = module_area;
115  m->submodsSet = false;
116  return module_area;
117  }
118  else
119  {
120  bool determined = false;
121  if (areaModels.count(model_key) != 0)
122  {
123  determined = true;
124  module_area = areaModels[model_key];
125  cgrame_msg("Area model of \"" + model_key + "\" found.");
126  m->area = module_area;
127  m->submodsSet = false;
128  return module_area;
129  }
130  else if (m->submodules.size() == 0) // a module without submodule must have an area entry
131  throw cgrame_error("Area model of \"" + model_key + "\" does not exist...");
132 
133  unsigned int i = 0;
134  unsigned int i_last = m->submodules.size() - 1;
135  for (const auto& sm : m->submodules)
136  {
137  std::string inst_name = sm.first;
138  Module* submodule = sm.second;
139  module_area += _setModuleArea(submodule, level + 1, i == i_last);
140  i++;
141  }
142 
143  // add entry to opt out re-calculation
144  cgrame_msg("Area model of \"" + model_key + "\" generated.");
145  areaModels[model_key] = module_area;
146  m->area = module_area;
147  m->submodsSet = true;
148  return module_area;
149  }
150 }
151 
152 void PerfEngine::reportArea(std::shared_ptr<CGRA> target)
153 {
154  cgrame_msg("Populating hierarchical module area.");
155  double total_area = _setModuleArea(&(target->getTopLevelModule()), 0, true);
156 
157  // Redirect output buffer
158  std::string filename = "/tmp/CGRAME_AreaReport.rpt";
159  std::streambuf* original_sbuf = std::cout.rdbuf();
160  std::ofstream rpt_filebuf(filename);
161  std::cout.rdbuf(rpt_filebuf.rdbuf()); // Redirects to new file
162 
163  reportLevelOrderArea(&(target->getTopLevelModule()));
164 
165  // Restore output buffer
166  std::cout.rdbuf(original_sbuf);
167  cgrame_msg("Area estimation completed. Report dumped to: `/tmp/CGRAME_AreaReport.rpt`");
168 }
169 
171 {
172  auto area = m->area;
173  auto level = m->hierarchyLevel;
174  auto last = m->isLastInHierarchy;
175  std::string treeDrawing;
176  auto n = m;
177  if (n->hierarchyLevel != 0)
178  treeDrawing = (n->isLastInHierarchy)?" └─ ":" ├─ ";
179  if (n->parent != NULL)
180  {
181  do
182  {
183  n = n->parent;
184  if (n->hierarchyLevel == 0)
185  break;
186  if (n->isLastInHierarchy)
187  treeDrawing = " " + treeDrawing;
188  else
189  treeDrawing = " │ " + treeDrawing;
190  } while(n->hierarchyLevel > 0);
191  }
192  std::cout << treeDrawing;
193  std::cout << m->getName();
194  std::cout << "(" << m->GenericName() << ") : " << std::to_string(area) << std::endl;
195  if (!m->submodsSet) // submodule should be skipped if they were opt-ed out
196  return;
197  for (const auto& sm : m->submodules)
198  {
199  auto submodule = sm.second;
200  reportLevelOrderArea(submodule);
201  }
202 }
203 
204 // Return a multimap representing the mapped MRRG, with sources as keys, destination as values
205 EdgeList PerfEngine::_genMappedMRRG(const OpGraph& og, std::map<const OpGraphNode*,std::vector<MRRG::NodeDescriptor>>& m)
206 {
207  EdgeList res;
208  std::vector<MRRG::NodeDescriptor> fu_nodes;
209 
210  // Populate fu_nodes with intermediate MRRGNodes connecting
211  for(auto & op : og.opNodes())
212  {
213  MRRG::NodeDescriptor n = m.at(op).front();
214  //n->mapped_opcode = op->opcode;
215  mapped_node2opcode[n] = op->opcode;
216  fu_nodes.push_back(n);
217  }
218 
219  // Populate res with partial MRRGs
220  for(auto & val : og.valNodes())
221  {
222  EdgeList partial;
223 
224  for(auto & node_a : m.at(val))
225  {
226  for(auto & node_b : m.at(val))
227  {
228  if (node_a == node_b) continue;
229 
230  // confirm relation to node_a
231  auto fanout = node_a->fanout;
232  if (std::find(fanout.begin(), fanout.end(), node_b) != fanout.end())
233  {
234  // node_a -> node_b (`a` drives `b`)
235  res.insert(std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor> (node_a, node_b));
236  partial.insert(std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor> (node_a, node_b));
237  }
238  }
239  }
240 
241  /*
242  // Dump MRRG dot of this op
243  std::cout << "digraph " << *val << " {" << std::endl;
244  for(auto & node : m.at(val))
245  {
246  std::cout << "\"" << *node << "\";" << std::endl;
247  }
248  for(auto it = partial.begin(); it != partial.end(); it = partial.upper_bound(it->first))
249  {
250  auto i = it;
251  while (i != partial.upper_bound(it->first))
252  {
253  auto src = i->first;
254  auto des = i->second;
255  std::cout << "\"" << *src << "\" -> \"" << *des << "\";" << std::endl;
256  i++;
257  }
258  }
259  std::cout << "}\n" << std::endl;
260  */
261  }
262 
263  std::vector<MRRG::NodeDescriptor> src_list;
264  for(auto it = res.begin(); it != res.end(); it = res.upper_bound(it->first))
265  if (std::find(src_list.begin(), src_list.end(), it->first) == src_list.end())
266  src_list.push_back(it->first);
267 
268  // Resolve disconnection in res using fu_nodes
269  for(auto i = 0; i < fu_nodes.size(); i++)
270  {
271  // connect FU MRRG nodes to inputs of partial MRRGs
272  for(auto it_i = res.begin(); it_i != res.end(); it_i = res.upper_bound(it_i->first))
273  {
274  auto node = it_i->first;
275 
276  // skip if it is a FU MRRG node
277  if (std::find(fu_nodes.begin(), fu_nodes.end(), node) != fu_nodes.end()) continue;
278 
279  bool has_no_src = true;
280  for(auto it_j = res.begin(); it_j != res.end(); it_j++)
281  {
282  auto des = it_j->second;
283  if (node == des)
284  {
285  has_no_src = false;
286  break;
287  }
288  }
289 
290  if (has_no_src)
291  {
292  // add appropriate edge if it exist: FU MRRG node -> MRRG node with no source
293  for(auto & fu_node : fu_nodes)
294  {
295  auto pos = std::find(src_list.begin(), src_list.end(), node);
296  if (std::find(node->fanin.begin(), node->fanin.end(), fu_node) != node->fanin.end())
297  {
298  res.insert(std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor> (fu_node, node));
299  if (pos != src_list.end())
300  src_list.erase(pos);
301  }
302  }
303  }
304  }
305 
306  // connect outputs of partial MRRGs to FU MRRG nodes
307  for(auto it = res.begin(); it != res.end(); it++)
308  {
309  auto node = it->second;
310 
311  // skip if it is a FU MRRG node
312  if (std::find(fu_nodes.begin(), fu_nodes.end(), node) != fu_nodes.end()) continue;
313 
314  bool has_no_des = (std::find(src_list.begin(), src_list.end(), node) == src_list.end());
315  if (has_no_des)
316  {
317  // add appropriate edge if it exist: MRRG node with no destination -> FU MRRG node
318  for(auto & fu_node : fu_nodes)
319  {
320  if (std::find(node->fanout.begin(), node->fanout.end(), fu_node) != node->fanout.end())
321  {
322  res.insert(std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor> (node, fu_node));
323  src_list.push_back(node);
324  }
325  }
326  }
327  }
328  }
329 
330  /*
331  */
332  // Dump MRRG dot of mapped result
333  std::cout << "digraph MappedMRRG {" << std::endl;
334  for(auto & op : og.opNodes())
335  {
336  std::cout << "\"" << *m.at(op).front() << "\";" << std::endl;
337  }
338  for(auto & val : og.valNodes())
339  {
340  for(auto & node : m.at(val))
341  {
342  std::cout << "\"" << *node << "\";" << std::endl;
343  }
344  }
345  for(auto it = res.begin(); it != res.end(); it = res.upper_bound(it->first))
346  {
347  auto i = it;
348  while (i != res.upper_bound(it->first))
349  {
350  auto src = i->first;
351  auto des = i->second;
352  std::cout << "\"" << *src << "\" -> \"" << *des << "\";" << std::endl;
353  i++;
354  }
355  }
356  std::cout << "}\n" << std::endl;
357  /*
358  */
359 
360  return res;
361 }
362 
363 void PerfEngine::reportTiming(std::shared_ptr<CGRA> target, const Mapping& map_res)
364 {
365  // Reconstruct MRRG graph of mapped nodes only
366  auto& opgraph = map_res.getOpGraph();
367  auto mapping = map_res.getMapping();
368  auto mapped_mrrg = _genMappedMRRG(opgraph, mapping);
369 
370  // Construct Tatum structures with delays from profile (tg, tc, dc, ta)
371  std::shared_ptr<TatumInterface> sta_interface(new TatumInterface(timingModels, this));
372  sta_interface->createTatumTimingGraph(mapped_mrrg);
373 
374  // Initialize the Tatum STA engine
375  sta_interface->initializeTatumEngine(mapped_mrrg);
376 
377  // Update user-specified wire delays
378  //TODO: implement
379 
380  // Tatum report
381  sta_interface->reportSetupAnalysis();
382 }
383 
384 void PerfEngine::reportPower(std::shared_ptr<CGRA> target)
385 {
386 }
387 
388 void PerfEngine::_parseAreaINI(std::string file_str)
389 {
390  mINI area_ini;
391  if (area_ini.parse(file_str))
392  {
393  for (const auto& entry : area_ini)
394  {
395  std::string key = entry.first;
396  double val = stod(entry.second);
397  areaModels[key] = val;
398  }
399  }
400  else
401  {
402  throw cgrame_error("Error parsing area.ini. Please verify syntax");
403  }
404 
405  // Print the read area profile
406  //for (std::map<std::string, double>::iterator i = areaModels.begin(); i != areaModels.end(); ++i)
407  //{
408  // std::string k = i->first;
409  // cgrame_msg("areaModels["+k+"] gets "+std::to_string(areaModels[k]));
410  //}
411 }
412 
413 void PerfEngine::_parseTimingINI(std::string file_str)
414 {
415  mINI timing_ini;
416  if (timing_ini.parse(file_str))
417  {
418  for (const auto& entry : timing_ini)
419  {
420  std::string key = entry.first;
421  double val = stod(entry.second);
422  timingModels[key] = val;
423  }
424  }
425  else
426  {
427  throw cgrame_error("Error parsing timing.ini. Please verify syntax");
428  }
429 
430  // Print the read timing profile
431  //for (std::map<std::string, double>::iterator i = timingModels.begin(); i != timingModels.end(); ++i)
432  //{
433  // std::string k = i->first;
434  // std::ostringstream valStream;
435  // valStream << std::scientific << std::setprecision(3) << timingModels[k];
436  // std::string valStr = valStream.str();
437  // cgrame_msg("timingModels["+k+"] gets " + valStr);
438  //}
439 }
440 
441 void PerfEngine::_parsePowerINI(std::string file_str)
442 {
443 }
444 
Module::submodules
std::map< std::string, Module * > submodules
Definition: Module.h:227
PerfEngine::_genMappedMRRG
EdgeList _genMappedMRRG(const OpGraph &og, std::map< const OpGraphNode *, std::vector< MRRG::NodeDescriptor >> &m)
Definition: PerfEngine.cpp:205
PerfEngine::_parseTimingINI
void _parseTimingINI(std::string file_str)
Definition: PerfEngine.cpp:413
PerfEngine::~PerfEngine
virtual ~PerfEngine()
Definition: PerfEngine.cpp:62
Mapping::getMapping
std::map< OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor > > & getMapping()
Definition: Mapping.h:47
PerfEngine::_parsePowerINI
void _parsePowerINI(std::string file_str)
Definition: PerfEngine.cpp:441
PerfEngine.h
Mapping::getOpGraph
OpGraph & getOpGraph()
Definition: Mapping.h:82
PerfEngine::areaModels
std::map< std::string, double > areaModels
Definition: PerfEngine.h:38
Module::parent
Module * parent
Definition: Module.h:243
OpGraph::valNodes
auto & valNodes() const
Definition: OpGraph.h:314
PerfEngine::_setModuleArea
double _setModuleArea(Module *m, unsigned int level, bool last)
Definition: PerfEngine.cpp:66
PerfEngine::mapped_node2opcode
std::map< MRRG::NodeDescriptor, OpGraphOpCode > mapped_node2opcode
Definition: PerfEngine.h:36
PerfEngine::reportArea
void reportArea(std::shared_ptr< CGRA > target)
Definition: PerfEngine.cpp:152
PerfEngine::reportLevelOrderArea
void reportLevelOrderArea(Module *m)
Definition: PerfEngine.cpp:170
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
EdgeList
std::multimap< MRRG::NodeDescriptor, MRRG::NodeDescriptor > EdgeList
Definition: PerfEngine.h:26
Mapping
Definition: Mapping.h:31
Module::GenericName
virtual std::string GenericName()
Definition: Module.cpp:260
TatumInterface
Definition: TatumInterface.h:79
OpGraph::opNodes
auto & opNodes() const
Definition: OpGraph.h:313
cgrame_msg
#define cgrame_msg(m)
Definition: Util.h:17
cgrame_warn
#define cgrame_warn(m)
Definition: Util.h:18
Module
Definition: Module.h:163
OpGraphNode
Definition: OpGraph.h:113
PerfEngine::PerfEngine
PerfEngine(std::string ini_path)
Definition: PerfEngine.cpp:13
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
MRRGNode
Definition: MRRG.h:60
PerfEngine::reportPower
void reportPower(std::shared_ptr< CGRA > target)
Definition: PerfEngine.cpp:384
Module::isLastInHierarchy
bool isLastInHierarchy
Definition: Module.h:235
Module::area
double area
Definition: Module.h:233
Module::getName
auto & getName() const
Definition: Module.h:247
PerfEngine::timingModels
std::map< std::string, double > timingModels
Definition: PerfEngine.h:39
PerfEngine::reportTiming
void reportTiming(std::shared_ptr< CGRA > target, const Mapping &mapping)
Definition: PerfEngine.cpp:363
Module::hierarchyLevel
unsigned int hierarchyLevel
Definition: Module.h:234
OpGraph
Definition: OpGraph.h:215
PerfEngine::_parseAreaINI
void _parseAreaINI(std::string file_str)
Definition: PerfEngine.cpp:388
Module::submodsSet
bool submodsSet
Definition: Module.h:237
cgrame_error
Definition: Exception.h:20