CGRA-ME
Mapping.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 <algorithm>
12 #include <vector>
13 #include <set>
14 #include <stack>
15 #include <memory>
16 #include <unordered_map>
17 #include <unordered_set>
18 #include <queue>
19 #include <deque>
20 
22 #include <CGRA/Exception.h>
23 #include <CGRA/Mapping.h>
24 #include <CGRA/Module.h>
25 #include <CGRA/MRRGProcedures.h>
27 
28 std::ostream& operator<<(std::ostream& os, MappingStatus ms) {
29  switch (ms) {
30  case MappingStatus::success: return os << "success";
31  case MappingStatus::failure: return os << "failure";
32  case MappingStatus::timeout: return os << "timeout";
33  }
34  return os << "MappingStatus{" << static_cast<int>(ms) << '}';
35 }
36 
37 Mapping::Mapping(std::shared_ptr<CGRA> cgra, int II, std::shared_ptr<OpGraph> opgraph)
38  : cgra(cgra)
39  , II(II)
40  , opgraph(opgraph)
41 {
42 }
43 
45 {
46 }
47 
49 {
50  return cgra.get();
51 }
52 
53 int Mapping::getII() const
54 {
55  return II;
56 }
57 
59 {
60  try
61  {
62  mapping[opnode].push_back(node);
63  }
64  catch(const std::exception & e)
65  {
66  throw cgrame_error(std::string("Mapping Exception Thrown by: [") + e.what() + "] at File: " + std::string(__FILE__) + " Line: " + std::to_string(__LINE__));
67  }
68 }
69 
71 {
72  try
73  {
74  auto iter = find(mapping[opnode].begin(), mapping[opnode].end(), node);
75  if(iter != mapping[opnode].end())
76  {
77  mapping[opnode].erase(iter);
78  }
79  }
80  catch(const std::exception & e)
81  {
82  throw cgrame_error(std::string("Mapping Exception Thrown by: [") + e.what() + "] at File: " + std::string(__FILE__) + " Line: " + std::to_string(__LINE__));
83  }
84 }
85 
86 void Mapping::setMapping(std::map<OpGraph::NodeDescriptor,std::vector<MRRG::NodeDescriptor>> mapping)
87 {
88  this->mapping = mapping;
89 }
90 
91 void Mapping::setNodeMapping(OpGraph::NodeDescriptor node, std::vector<MRRG::NodeDescriptor> mapping) {
92  this->mapping[node] = std::move(mapping);
93 }
94 
96  *this = Mapping(cgra, II, opgraph);
97 }
98 
99 static bool find_sink(const std::vector<MRRG::NodeDescriptor> & val_map, std::map<MRRG::NodeDescriptor,bool> & visited, MRRG::NodeDescriptor src, MRRG::NodeDescriptor sink)
100 {
101  // mark src visited
102  visited[src] = true;
103 
104  // check each fanout
105  for(auto & fo : src->fanout)
106  {
107  if(fo == sink && std::find(sink->fanin.begin(), sink->fanin.end(), src) != sink->fanin.end())
108  {
109  return true;
110  }
111 
112  if(std::find(val_map.begin(), val_map.end(), fo) != val_map.end()) // if the node in the mapping
113  if(visited.find(fo) == visited.end()) // and we haven't visited before
114  {
115  if(find_sink(val_map, visited, fo, sink))
116  return true;
117  }
118  }
119  return false;
120 }
121 
122 bool Mapping::verifyOpGraphMappingConnectivity() // Should be const member function, but the [] operator might modify the mapping
123 {
124  bool result = true;
125  // 1. check that every op has one MRRG node mapped. also check that the FU can support the OP
126  for(auto & op : opgraph->opNodes())
127  {
128  if(mapping[op].size() > 1)
129  {
130  std::cout << "Verify FAILED: Op mapped to more than FU. Op=\'" << *op << "\'" << std::endl;
131  return false;
132  }
133  else if(mapping[op].size() == 0)
134  {
135  std::cout << "Verify FAILED: Op mapped to no FU. Op=\'" << *op << "\'" << std::endl;
136  return false;
137  }
138  else
139  {
140  if(!mapping[op][0]->canMapOp(op))
141  {
142  std::cout << "Verify FAILED: Op mapped to more illegal FU. Op=\'" << *op << "\'" << std::endl;
143  return false;
144  }
145  }
146  }
147  // 2. Check that there are no shorts between values
148  for(auto & val1 : opgraph->valNodes())
149  {
150  for(auto & val2 : opgraph->valNodes())
151  {
152  if(val1 != val2)
153  {
154  for(auto & node1 : mapping[val1])
155  {
156  for(auto & node2 : mapping[val2])
157  {
158  if(node1 == node2)
159  {
160  std::cout << "Verify FAILED: Different vals mapped to same route. Val1=\'" << *val1 << "\' Val2=\'" << *val2 << "\'" << std::endl;
161  return false;
162  }
163  }
164  }
165  }
166  }
167  }
168  // 3. for every val, verify source to sink connections for each fanout
169  for(auto & val : opgraph->valNodes())
170  {
171  std::cout << "Verifying Value: " << *val << std::endl;
172  for(int i = 0; i < (std::ptrdiff_t)val->output.size(); i++)
173  {
174  MRRG::NodeDescriptor srcfu = mapping[val->input][0];
175  MRRG::NodeDescriptor sinkfu = mapping[val->output[i]][0];
176  std::cout << "Finding sink \'" << *sinkfu << "(operand=" << val->output_operand[i] << ")" << std::endl;
177  std::map<MRRG::NodeDescriptor,bool> visited;
178  if(!find_sink(mapping[val], visited, srcfu, sinkfu))
179  {
180  std::cout << "Verify FAILED: Disconnect between " << *(val->input) << "/" << *srcfu << " -> " << *(val->output[i]) << "/" << *sinkfu << "(operand=" <<val->output_operand[i] << ")" << std::endl;
181  std::cout << "Could not find sink \'" << *sinkfu << "(operand=" << val->output_operand[i] << ")" << std::endl;
182 
183  outputValMapping(val);
184  result &= false;
185  }
186  else
187  {
188  std::cout << "Found sink \'" << *sinkfu << "(operand=" << val->output_operand[i] << ")" << std::endl;
189  }
190  }
191  }
192  return result;
193 }
194 
195 namespace {
196  template<typename STREAM, typename MAPPING, typename KEY>
197  void if_found_print_single_mapping_else_print_message(STREAM& o, MAPPING&& m, KEY&& k) {
198  auto find_result = m.find(k);
199  if (find_result == end(m)) {
200  o << "__NOT_MAPPED__";
201  } else {
202  auto& mapping_list = m.at(k);
203  if (mapping_list.size() == 1) {
204  o << **begin(mapping_list);
205  } else {
206  o << "__MULTIPLE__";
207  }
208  }
209  }
210 
211  template<typename STREAM, typename MAPPING, typename KEY>
212  void if_found_print_mapping_else_print_message(STREAM& o, MAPPING&& m, KEY&& k) {
213  auto find_result = m.find(k);
214  if (find_result == end(m)) {
215  o << "__NOT_MAPPED__";
216  } else {
217  for(auto & node : m.at(k)) {
218  o << " " << *node << std::endl;
219  }
220  }
221  }
222 }
223 
224 void Mapping::outputMapping(const OpGraph& opgraph, std::ostream & o) const
225 {
226  o << "Operation Mapping Result:" << std::endl;
227  for(auto & op : opgraph.opNodes())
228  {
229  o << *op << ": ";
230  if_found_print_mapping_else_print_message(o, mapping, op);
231  o << '\n';
232  }
233  o << std::endl;
234  o << "Connection Mapping Result:" << std::endl;
235  for(auto & val : opgraph.valNodes())
236  {
237  o << *val << ":" << std::endl;
238  if_found_print_mapping_else_print_message(o, mapping, val);
239  o << std::endl;
240  }
241 }
242 
243 void Mapping::outputDetailedMapping(std::ostream & o) const
244 {
245  o << "Operation Mapping Result:" << std::endl;
246  for(auto & op : opgraph->opNodes())
247  {
248  o << *op << ": ";
249  if_found_print_mapping_else_print_message(o, mapping, op);
250  o << '\n';
251  }
252  o << std::endl;
253  // o << "Connection Mapping Result:" << std::endl;
254  // for(auto & val : opgraph->valNodes())
255  // {
256  // for(int fanout_id = 0; fanout_id < (std::ptrdiff_t)val->fanout_result.size(); ++fanout_id)
257  // {
258  // o << *val << "->" << *(val->output.at(fanout_id)) << std::endl;
259  // for(auto & node : val->fanout_result.at(fanout_id))
260  // o << " " << *node << std::endl;
261  // }
262  // o << std::endl;
263  // }
264 }
265 
266 void Mapping::outputValMapping(OpGraphVal* val, std::ostream & o) const
267 {
268 
269  o << "digraph G {\n";
270  for(auto & r : mapping.at(val))
271  {
272  for(auto & fo : r->fanout)
273  {
274  if(std::find(mapping.at(val).begin(), mapping.at(val).end(), fo) != mapping.at(val).end())
275  {
276  o << "\"" << *r << "\""<< "->" << "\""<< *fo << "\""<< "\n";
277  }
278  }
279  }
280 
281  o << "};\n";
282 }
283 
284 void Mapping::check() const
285 {
286 }
287 
289  const Mapping& src,
290  const std::unordered_map<OpGraph::NodeDescriptor, OpGraph::NodeDescriptor>& forward_mappings
291 ) {
292  Mapping result(std::shared_ptr<CGRA>(), src.getII(), std::shared_ptr<OpGraph>());
293  for (const auto& src_and_dest_og_nodes : forward_mappings) {
294  if (not src.hasMapping(src_and_dest_og_nodes.first)) { continue; }
295  for (const auto& mrrg_node : src.getMappingList(src_and_dest_og_nodes.first)) {
296  result.mapMRRGNode(src_and_dest_og_nodes.second, mrrg_node);
297  }
298  }
299  return result;
300 }
301 
302 /************** MappingGraph ************/
304  nodes.emplace(nextId, std::move(node));
305  fanout_lists.emplace(nextId, std::vector<NodeDescriptor>());
306  fanin_lists.emplace(nextId, std::vector<NodeDescriptor>());
307 
308  auto thisId = nextId;
309  nextId.id++;
310  return {thisId, true};
311 }
312 
313 std::ptrdiff_t MappingGraph::size() const {
314  return nodes.size();
315 }
316 
318  if (driver == fanout) return; // Self-linking is unneccessary
319 
320  // TODO: Perform validity check on the graph prior/after to linking.
321  // Update fanouts
322  fanout_lists[driver].emplace_back(fanout);
323 
324  fanin_lists[fanout].emplace_back(driver);
325 }
326 
328 
329  // TODO: Perform validity check on the graph prior/after to linking.
330  // Would this be a good place to do the try and catch? If the two aren't linked then throw an error?
331  // Update fanouts
332  auto findFanout = std::find(fanout_lists[driver].begin(), fanout_lists[driver].end(), fanout);
333  fanout_lists[driver].erase(findFanout);
334 
335  // Update fanins
336  auto findDriver = std::find(fanin_lists[fanout].begin(), fanin_lists[fanout].end(), driver);
337  fanin_lists[fanout].erase(findDriver);
338 }
339 
341  if (deletedIds.find(n.id) != deletedIds.end()) return;
342  // Delete links at other nodes first
343  // Nodes that n fans out from
344  for (auto & fin: reversed(fanin_lists.at(n))) {
345  unlink(fin, n);
346  }
347  fanin_lists.erase(fanin_lists.find(n));
348 
349  // Nodes that n fans into
350  for (auto & fout: reversed(fanout_lists.at(n))) {
351  unlink(n, fout);
352  }
353  fanout_lists.erase(fanout_lists.find(n));
354 
355  deletedIds.emplace(n.id);
356  nodes.erase(nodes.find(n));
357 }
358 
360  return nodes.at(ndesc);
361 }
362 
364  return nodes.at(ndesc);
365 }
366 
367 std::vector<MappingGraph::VerifyMessage> MappingGraph::verify(const MRRG& mrrg, const ToMRRGVertexMap& toMRRG) const {
373  std::vector<VerifyMessage> verifyMessages;
374  std::queue<MappingGraph::NodeDescriptor> toVisit;
375  std::unordered_set<MappingGraph::NodeDescriptor, NodeDescriptorHash> visited;
376  for (auto & node: nodes) { // Find the non-routing nodes to start search from
377  if (mrrg.getNodeRef(toMRRG.at(node.first)).type == MRRG_NODE_ROUTING ||
378  mrrg.getNodeRef(toMRRG.at(node.first)).type == MRRG_NODE_ROUTING_FUNCTION) { continue; }
379  toVisit.push(node.first);
380  }
381 
382  while (!toVisit.empty()) {
383  auto currentNode = toVisit.front();
384  if (visited.find(currentNode) != visited.end()) {
385  toVisit.pop();
386  continue;
387  }
388  visited.emplace(currentNode);
389  for (auto & fanout: fanout_lists.at(currentNode)) {
390  if (visited.find(fanout) != visited.end()) { continue; }
391  toVisit.push(fanout);
392  }
393  for (auto & fanin: fanin_lists.at(currentNode)) {
394  if (visited.find(fanin) != visited.end()) { continue; }
395  toVisit.push(fanin);
396  }
397  toVisit.pop();
398  }
399 
400  // Find the number of isolated nodes
401  int isolatedNodeNum = 0;
402  for (auto node: nodes) {
403  if (visited.find(node.first) == visited.end()) {
404  verifyMessages.emplace_back(VerifyMessage::Type::Warning, mrrg.getNodeRef(toMRRG.at(node.first)).getFullName() + "|" + node.second.op_node_desc->getName() + " is isolated.cg\n"); // Adding the nodes that are isolated to the verify message
405  isolatedNodeNum++;
406  }
407  }
408 
409  if (isolatedNodeNum > 0) {
410  verifyMessages.emplace_back(VerifyMessage::Type::Warning, "Found " + std::to_string(isolatedNodeNum) + " isolated nodes\n");
411  }
412  else {
413  verifyMessages.emplace_back(VerifyMessage::Type::Info, "No isolated found\n");
414  }
415 
416  return verifyMessages;
417 }
418 
419 void MappingGraph::printDot(std::ostream& os, const MRRG& mrrg, const OpGraph& opgraph, const ToMRRGVertexMap& toMRRG, const ConfigStore& archAttrs) const {
420  os << "digraph {\ngraph[";
421  // CGRA/Mapping attributes
422  os << "II=" << mrrg.initiationInterval() << ", ";
423  for (auto & attr : archAttrs) {
424  os << attr.first << "=\"" << attr.second << "\", ";
425  }
426  // Visual attributes
427  os << "splines=ortho, concentrate=true, landscape=false];\nnode[shape=record, fixedsize=true, height=0.8, width=2, fontsize=7, fontname=\"times bold\"];\n";
428 
429  // Nodes
430  std::unordered_map<Module*, std::vector<NodeDescriptor>> moduleToMG;
431  for (const auto& mg_ndesc_and_node : this->allNodes()) {
432  auto& mg_ndesc = mg_ndesc_and_node.first;
433  const auto& mrrg_node = mrrg.getNodeRef(toMRRG.at(mg_ndesc));
434  const auto mrrg_node_name = mrrg_node.getFullName();
435  const auto& op_name = opgraph.getNodeRef(this->getNodeRef(mg_ndesc).op_node_desc).getName();
436 
437  // "node_full_name"[name="node_name", cycle=`cycle`, maps_to="op_name", label="{node_full_name|op_name}"];
438  printDotID(os, mrrg_node_name);
439  os << "[";
440  os << "name=";
441  printDotID(os, mrrg_node.name); // Regular name without cycle
442  os << ", cycle=" << mrrg_node.cycle;
443  if (dynamic_cast<OpGraph::OpDescriptor>(this->getNodeRef(mg_ndesc).op_node_desc) != NULL) {
444  os << ", maps_to_op=";
445  }
446  else {
447  os << ", maps_to_val=";
448  }
449  printDotID(os, op_name);
450  os << ", label=\"{" << mrrg_node_name << "|" << op_name << "}\"";
451 
452  os << "];\n";
453  }
454 
455  // Edges
456  for (const auto& mg_ndesc_and_node : this->allNodes()) {
457  const auto& mg_ndesc = mg_ndesc_and_node.first;
458  const auto& mg_ndesc_fanout = this->fanout(mg_ndesc);
459 
460  for (auto fanout : this->fanout(mg_ndesc)) {
461  // "driver"->"fanout"
462  os << "\"" + mrrg.getNodeRef(toMRRG.at(mg_ndesc)).getFullName() + "\"->" << "\"" + mrrg.getNodeRef(toMRRG.at(fanout)).getFullName() + "\";\n";
463  }
464  }
465  os << "}\n";
466 }
467 
469  const auto& mapping = m.getMapping();
470  MappingGraph mg;
471  std::unordered_map<MRRG::NodeDescriptor, MappingGraph::NodeDescriptor> fromMRRG;
472  std::unordered_map<MappingGraph::NodeDescriptor, MRRG::NodeDescriptor, MappingGraph::NodeDescriptorHash> toMRRG;
473 
474  // Insert the mrrg nodes and their corresponding mapping graph nodes(opgraph nodes). Keep track of the mapping from both ways.
475  for (auto & opToMRRGNodeList : mapping) {
476  for (auto & mrrgNode : opToMRRGNodeList.second) {
477  auto mgNode = mg.insert({opToMRRGNodeList.first}).first;
478  toMRRG.emplace(mgNode, mrrgNode);
479  fromMRRG.emplace(mrrgNode, mgNode);
480  }
481  }
482 
483  // Linking the mapped MRRG nodes together
484  for (auto & opToMRRGNodeList1: mapping) {
485  for (auto & mrrgNodeA : opToMRRGNodeList1.second) {
486  for (auto & opToMRRGNodeList2: mapping) {
487  for (auto & mrrgNodeB : opToMRRGNodeList2.second) {
488  if (mrrgNodeA == mrrgNodeB) continue;
489 
490  // See if A drives B
491  const auto& nodeAfanout = mrrg.fanout(mrrgNodeA);
492  if (std::find(nodeAfanout.begin(), nodeAfanout.end(), mrrgNodeB) != nodeAfanout.end()) {
493  // If so, then link the nodes together
494  mg.link(fromMRRG.at(mrrgNodeA), fromMRRG.at(mrrgNodeB));
495  }
496  }
497  }
498  }
499  }
500 
501  return {mg, fromMRRG, toMRRG};
502 }
503 
505  MappingGraph fixedGraph(mapping);
506 
507  // Repeating the same BFS from the verify, because verify is const
508  std::queue<MappingGraph::NodeDescriptor> toVisit;
509 
510  std::unordered_set<MappingGraph::NodeDescriptor, MappingGraph::NodeDescriptorHash> visited;
511 
512 
513  for (auto & node: fixedGraph.allNodes()) { // Find the non-routing nodes to start search from
514  if (mrrg.getNodeRef(toMRRG.at(node.first)).type == MRRG_NODE_ROUTING ||
515  mrrg.getNodeRef(toMRRG.at(node.first)).type == MRRG_NODE_ROUTING_FUNCTION) { continue;}
516  toVisit.push(node.first);
517  }
518 
519  while (!toVisit.empty()) {
520  auto currentNode = toVisit.front();
521  if (visited.find(currentNode) != visited.end()) {
522  toVisit.pop();
523  continue;
524  }
525  visited.emplace(currentNode);
526  for (auto & fanout: fixedGraph.fanout(currentNode)) {
527  if (visited.find(fanout) != visited.end()) { continue; }
528  toVisit.push(fanout);
529  }
530  for (auto & fanin: fixedGraph.fanin(currentNode)) {
531  if (visited.find(fanin) != visited.end()) { continue; }
532  toVisit.push(fanin);
533  }
534  toVisit.pop();
535  }
536 
537  // Erase the unvisited nodes
538  std::vector<MappingGraph::NodeDescriptor> nodesToDelete;
539  for (auto node: fixedGraph.allNodes()) {
540  if (visited.find(node.first) == visited.end()) {
541  nodesToDelete.emplace_back(node.first);
542  }
543  }
544  for (auto node: nodesToDelete) {
545  fixedGraph.erase(node);
546  }
547 
548  return std::move(fixedGraph);
549 }
550 
551 namespace {
552 
553 // Helper functions for latencyCheck
554 bool latencyCheckBFS(
555  const MappingGraph& mapping, MappingGraphCycleAssignment& latenciesInfo,
557  std::set<MappingGraph::NodeDescriptor>& checkCycle,
558  std::set<MappingGraph::NodeDescriptor>& check0Cycle,
559  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG
560 );
561 
566 bool latencyCheckBFSCycle(
567  const MappingGraph& mapping, MappingGraph::NodeDescriptor start,
568  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG
569 );
570 
575 bool latencyCheck0Cycle(
576  const MappingGraph& mapping, MappingGraph::NodeDescriptor start,
577  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG, std::unordered_set<MappingGraph::NodeDescriptor, MappingGraph::NodeDescriptorHash> & nodesLeft
578 );
579 
580 }
581 
582 std::pair<bool, MappingGraphCycleAssignment> latencyCheck(
583  const MappingGraph& mapping, const MRRG& mrrg,
585 ) {
597  bool balanced = true;
598  MappingGraphCycleAssignment latenciesInfo; // Timing information for the nodes
599 
600  std::set<MappingGraph::NodeDescriptor> checkCycle; // Nodes to check for a cycle.
601  std::set<MappingGraph::NodeDescriptor> check0Cycle; // Nodes to check for a 0 latency cycle.
602 
603 
604  std::deque<MappingGraph::NodeDescriptor> toSearch;
605  for (auto node: mapping.allNodes()) {
606  if (mapping.fanin(node.first).empty()) {
607  toSearch.push_front(node.first);
608  }
609  else {
610  toSearch.push_back(node.first);
611  }
612  }
613 
614  // Do BFS starting from the nodes that haven't been visit. Each BFS should operate on 1 connected component of the entire graph
615  while (!toSearch.empty()) {
616  if (latenciesInfo.find(toSearch.front()) == latenciesInfo.end()) {
617  if (!latencyCheckBFS(mapping, latenciesInfo, toSearch.front(), checkCycle, check0Cycle, mrrg, toMRRG)) {
618  balanced = false;
619  }
620  }
621  toSearch.pop_front();
622  }
623 
624  for (auto node : checkCycle) {
625  if (!latencyCheckBFSCycle(mapping, node, mrrg, toMRRG)) {
626  balanced = false;
627  }
628  }
629 
630  std::unordered_set<MappingGraph::NodeDescriptor, MappingGraph::NodeDescriptorHash> check0CycleLeft;
631  for (auto node: check0Cycle) {
632  check0CycleLeft.insert(node);
633  }
634  for (auto node : check0Cycle) {
635  if (check0CycleLeft.find(node) != check0CycleLeft.end()) {
636  if (!latencyCheck0Cycle(mapping, node, mrrg, toMRRG, check0CycleLeft)) {
637  balanced = false;
638  }
639  }
640  }
641 
642  return {balanced, latenciesInfo};
643 }
644 
645 namespace {
646 
647 bool latencyCheckBFS(
648  const MappingGraph& mapping, MappingGraphCycleAssignment& latenciesInfo,
650  std::set<MappingGraph::NodeDescriptor>& checkCycle,
651  std::set<MappingGraph::NodeDescriptor>& check0Cycle,
652  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG
653 ) {
654  const auto getMRRGNode = [&](const MappingGraph::NodeDescriptor& mg_ndesc) -> auto& {
655  return mrrg.getNodeRef(toMRRG.at(mg_ndesc));
656  };
657 
658  bool balanced = true;
659  MappingGraphCycleAssignment latencies;
660 
661  using nodeLatencyPair = std::pair<MappingGraph::NodeDescriptor, int>;
662  std::queue<nodeLatencyPair> toVisit;
663  toVisit.emplace(start, 0);
664  std::queue<bool> isFanout; // Parallel queue to check if a node emplaced was from a fanout or fanin, used to avoid cycle checking on nodes that were reached by fanin
665  isFanout.emplace(true);
666 
667  const auto II = mrrg.initiationInterval();
668  int offset = 0; // Most negative offset that will have to be added onto each node for all t(n) >= 0
669 
670  while (!toVisit.empty()) {
671  auto currentNodeLatencyP = toVisit.front();
672  bool canCycleCheck = isFanout.front();
673  toVisit.pop();
674  isFanout.pop();
675  // std::cout << "Visiting " << getMRRGNode(currentNodeLatencyP.first).getFullName() << " with latency of " << currentNodeLatencyP.second << "\n";
676 
677  if (currentNodeLatencyP.second < offset) {
678  offset = currentNodeLatencyP.second;
679  }
680 
681  // Update overall latencies information
682  if (latenciesInfo.find(currentNodeLatencyP.first) != latenciesInfo.end()) {
683  if (latenciesInfo[currentNodeLatencyP.first] < currentNodeLatencyP.second) {
684  // In the case that we have multiple t(n) for a node, keep the larger value as that is likely more important, there will be a disconnect with this node's other fanins however.
685  latenciesInfo[currentNodeLatencyP.first] = currentNodeLatencyP.second;
686  }
687  }
688  else {
689  latenciesInfo.emplace(currentNodeLatencyP);
690  }
691 
692  // If the node has been visited during this search
693  if (latencies.find(currentNodeLatencyP.first) != latencies.end()) {
694  // Check that t(f) + latency(f) = t(n)
695  if (latencies.at(currentNodeLatencyP.first) == currentNodeLatencyP.second) {
696  check0Cycle.emplace(currentNodeLatencyP.first);
697  continue;
698  }
699  // Check if t(f) + latency(f) = t(n) + II
700  else if (latencies.at(currentNodeLatencyP.first) + II == currentNodeLatencyP.second) {
701  if (canCycleCheck)
702  checkCycle.emplace(currentNodeLatencyP.first); // add to set of nodes to check for a cycle
703  continue;
704  }
705  // Check if t(f) + latency(f) = t(n) - II
706  else if (latencies.at(currentNodeLatencyP.first) - II == currentNodeLatencyP.second) {
707  if (canCycleCheck)
708  checkCycle.emplace(currentNodeLatencyP.first); // add to set of nodes to check for a cycle
709  continue;
710  }
711  else {
712  // std::cout << getMRRGNode(currentNodeLatencyP.first).getFullName() << " has inbalanced latency\n";
713  balanced = false;
714  }
715  }
716  else {
717  latencies.insert(currentNodeLatencyP);
718  for (auto & fanout: mapping.fanout(currentNodeLatencyP.first)) {
719  // If this fanout has already been visited and the recorded latency matches what we've seen on it, don't need to add to queue
720  if (latencies.find(fanout) != latencies.end() && latencies.at(fanout) == currentNodeLatencyP.second + getMRRGNode(currentNodeLatencyP.first).latency) {
721  continue;
722  }
723  else {
724  // Emplace the fanin onto the queue, with latency = latencyToReachCurrentNode-latency of fanin
725  toVisit.emplace(fanout, currentNodeLatencyP.second+getMRRGNode(currentNodeLatencyP.first).latency);
726  isFanout.emplace(true);
727  }
728  }
729  for (auto & fanin: mapping.fanin(currentNodeLatencyP.first)) {
730  if (latencies.find(fanin) != latencies.end()) {
731  // Requirement to search fanin is that it must not have been visited before.
732  continue;
733  }
734  else {
735  // Emplace the fanin onto the queue, with latency = latencyToReachCurrentNode-latency of fanin
736  toVisit.emplace(fanin, currentNodeLatencyP.second - getMRRGNode(fanin).latency);
737  isFanout.emplace(false);
738  }
739  }
740  }
741  }
742 
743  // Make all the latencies >= 0
744  if (offset < 0) {
745  for (auto node: latencies) {
746  latenciesInfo[node.first] -= offset;
747  }
748  }
749 
750  return balanced;
751 }
752 
753 bool latencyCheckBFSCycle(
754  const MappingGraph& mapping, MappingGraph::NodeDescriptor start,
755  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG
756 ) {
757  using nodeLatencyPair = std::pair<MappingGraph::NodeDescriptor, int>;
758  std::queue<nodeLatencyPair> toVisit;
759  const auto II = mrrg.initiationInterval();
760  const auto getMRRGNode = [&](const MappingGraph::NodeDescriptor& mg_ndesc) -> auto& {
761  return mrrg.getNodeRef(toMRRG.at(mg_ndesc));
762  };
763 
764  // Start a BFS from this node to try to find itself. If it cannot find itself, latency is unbalanced, or if it does find itself but the delay between != II then the latency is unbalanced.
765  bool cycle = false;
766  std::unordered_map<MappingGraph::NodeDescriptor, std::unordered_set<int>, MappingGraph::NodeDescriptorHash> visited;
767  // std::cout << "Checking if " << getMRRGNode(start).getFullName() << " is part of a cycle\n";
768 
769  for (auto & fanout: mapping.fanout(start)) {
770  toVisit.emplace(fanout, getMRRGNode(start).latency);
771  }
772 
773  while (!toVisit.empty()) {
774  auto currentNodeLatencyP = toVisit.front();
775  toVisit.pop();
776  if (visited.find(currentNodeLatencyP.first) != visited.end()) {
777  if (visited[currentNodeLatencyP.first].find(currentNodeLatencyP.second) != visited[currentNodeLatencyP.first].end()) {
778  continue;
779  }
780  visited[currentNodeLatencyP.first].emplace(currentNodeLatencyP.second);
781  }
782  else {
783  visited.emplace(currentNodeLatencyP.first, std::unordered_set<int>() = {currentNodeLatencyP.second});
784  }
785 
786  if (currentNodeLatencyP.first == start) {
787  cycle = true;
788  // If we've arrived back to the original node, then make sure the delay is correct.
789  if (currentNodeLatencyP.second != II) {
790  // std::cout << getMRRGNode(currentNodeLatencyP.first).getFullName() << " has inbalanced cyclical latency\n";
791  return false;
792  }
793  }
798  else if (currentNodeLatencyP.second <= II) {
799  for (auto & fanout: mapping.fanout(currentNodeLatencyP.first)) {
800  toVisit.emplace(fanout, currentNodeLatencyP.second+getMRRGNode(currentNodeLatencyP.first).latency);
801  }
802  }
803  }
804 
805  // If we never found the orignal node from this search, then this is not a cycle and thus the latency was invalid
806  return cycle;
807 }
808 
809 bool latencyCheck0Cycle(
810  const MappingGraph& mapping, MappingGraph::NodeDescriptor start,
811  const MRRG& mrrg, const CreateMappingGraphResult::ToMRRG& toMRRG,
812  std::unordered_set<MappingGraph::NodeDescriptor, MappingGraph::NodeDescriptorHash> & nodesToCheck
813 
814 ) {
815  using nodeLatencyPair = std::pair<MappingGraph::NodeDescriptor, int>;
816  std::queue<nodeLatencyPair> toVisit;
817  const auto II = mrrg.initiationInterval();
818  const auto getMRRGNode = [&](const MappingGraph::NodeDescriptor& mg_ndesc) -> auto& {
819  return mrrg.getNodeRef(toMRRG.at(mg_ndesc));
820  };
821 
822  for (auto & fanout: mapping.fanout(start)) {
823  toVisit.emplace(fanout, getMRRGNode(start).latency);
824  }
825 
826  while (!toVisit.empty()) {
827  auto currentNodeLatencyP = toVisit.front();
828  toVisit.pop();
829  if (nodesToCheck.find(currentNodeLatencyP.first) != nodesToCheck.end()) {
830  nodesToCheck.erase(nodesToCheck.find(currentNodeLatencyP.first));
831  }
832 
833  if (currentNodeLatencyP.first == start) {
834  if (currentNodeLatencyP.second == 0) {
835  return false;
836  }
837  }
842  else if (currentNodeLatencyP.second <= II) {
843  for (auto & fanout: mapping.fanout(currentNodeLatencyP.first)) {
844  toVisit.emplace(fanout, currentNodeLatencyP.second+getMRRGNode(currentNodeLatencyP.first).latency);
845  }
846  }
847  }
848 
849  return true;
850 }
851 
852 }
Mapping::Mapping
Mapping(std::shared_ptr< CGRA > cgra, int II, std::shared_ptr< OpGraph > opgraph)
Definition: Mapping.cpp:37
removeIsolatedRoutingNodes
MappingGraph removeIsolatedRoutingNodes(const MappingGraph &mapping, const MRRG &mrrg, const MappingGraph::ToMRRGVertexMap &toMRRG)
Definition: Mapping.cpp:504
MRRGNode::getFullName
std::string getFullName() const
Definition: MRRG.cpp:569
MRRG_NODE_ROUTING_FUNCTION
@ MRRG_NODE_ROUTING_FUNCTION
Definition: MRRG.h:47
Mapping::II
int II
Definition: Mapping.h:105
ConfigGraph.h
MappingGraph::fanin
auto & fanin(const NodeDescriptor ndesc) const
Definition: Mapping.h:207
MRRG
Definition: MRRG.h:216
Mapping::check
void check() const
Definition: Mapping.cpp:284
MRRGNode::type
MRRGNode_Type type
Definition: MRRG.h:107
Mapping::getMapping
std::map< OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor > > & getMapping()
Definition: Mapping.h:47
MappingGraph::deletedIds
std::unordered_set< int > deletedIds
Definition: Mapping.h:239
OpGraph::getNodeRef
OpGraphOp & getNodeRef(OpDescriptor ndesc)
Definition: OpGraph.h:376
CreateMappingGraphResult::ToMRRG
MappingGraph::ToMRRGVertexMap ToMRRG
Definition: Mapping.h:247
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
printDotID
auto printDotID(std::ostream &os, const std::string &id) -> std::ostream &
Definition: ConfigGraph.h:26
Module.h
MappingGraph::NodeDescriptorHash
Definition: Mapping.h:140
CGRA
Definition: CGRA.h:76
Mapping::opgraph
std::shared_ptr< OpGraph > opgraph
Definition: Mapping.h:106
Mapping::getMappingList
const std::vector< MRRG::NodeDescriptor > & getMappingList(OpGraph::NodeDescriptor key) const
Definition: Mapping.h:57
Mapping::outputMapping
void outputMapping(std::ostream &o=std::cout) const
Definition: Mapping.h:72
Mapping::setMapping
void setMapping(std::map< OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor >> mapping)
Definition: Mapping.cpp:86
ConfigStore
Definition: ConfigStore.h:76
MappingGraph::printDot
void printDot(std::ostream &os, const MRRG &mrrg, const OpGraph &opgraph, const ToMRRGVertexMap &toMRRG, const ConfigStore &archAttributes) const
Definition: Mapping.cpp:419
MappingGraph::NodeDescriptor::id
std::ptrdiff_t id
Definition: Mapping.h:131
latencyCheck
std::pair< bool, MappingGraphCycleAssignment > latencyCheck(const MappingGraph &mapping, const MRRG &mrrg, const CreateMappingGraphResult::ToMRRG &toMRRG)
Definition: Mapping.cpp:582
MappingGraph::fanout_lists
std::unordered_map< NodeDescriptor, std::vector< NodeDescriptor >, NodeDescriptorHash > fanout_lists
Definition: Mapping.h:241
MappingGraph
Definition: Mapping.h:129
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
Mapping::setNodeMapping
void setNodeMapping(OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor > mapping)
Definition: Mapping.cpp:91
Mapping::mapMRRGNode
void mapMRRGNode(OpGraph::NodeDescriptor, MRRG::NodeDescriptor node)
Definition: Mapping.cpp:58
MappingGraphNode
Definition: Mapping.h:125
MappingGraph::allNodes
auto & allNodes() const
Definition: Mapping.h:234
CreateMappingGraphResult
Definition: Mapping.h:246
Mapping::hasMapping
bool hasMapping(OpGraph::NodeDescriptor key) const
Definition: Mapping.h:50
Mapping
Definition: Mapping.h:31
Exception.h
Mapping::getCGRA
CGRA * getCGRA() const
Definition: Mapping.cpp:48
MappingGraph::erase
void erase(MappingGraph::NodeDescriptor n)
Definition: Mapping.cpp:340
Mapping::outputValMapping
void outputValMapping(OpGraphVal *val, std::ostream &o=std::cout) const
Definition: Mapping.cpp:266
MappingGraph::NodeDescriptor
Definition: Mapping.h:131
MRRG::fanout
auto & fanout(NodeDescriptor ndesc) const
Definition: MRRG.h:288
Mapping::verifyOpGraphMappingConnectivity
bool verifyOpGraphMappingConnectivity()
Definition: Mapping.cpp:122
MappingStatus::timeout
@ timeout
MRRG::getNodeRef
MRRGNode & getNodeRef(NodeDescriptor ndesc)
Definition: MRRG.h:273
MappingGraph::fanin_lists
std::unordered_map< NodeDescriptor, std::vector< NodeDescriptor >, NodeDescriptorHash > fanin_lists
Definition: Mapping.h:242
operator<<
std::ostream & operator<<(std::ostream &os, MappingStatus ms)
Definition: Mapping.cpp:28
MRRGNode::fanin
std::vector< MRRGNode * > fanin
Definition: MRRG.h:114
MappingStatus::failure
@ failure
MappingGraph::VerifyMessage::Type::Info
@ Info
MappingGraph::fanout
auto & fanout(NodeDescriptor ndesc) const
Definition: Mapping.h:201
OpGraphNode
Definition: OpGraph.h:113
Mapping::cgra
std::shared_ptr< CGRA > cgra
Definition: Mapping.h:104
Mapping::getII
int getII() const
Definition: Mapping.cpp:53
find_sink
static bool find_sink(const std::vector< MRRG::NodeDescriptor > &val_map, std::map< MRRG::NodeDescriptor, bool > &visited, MRRG::NodeDescriptor src, MRRG::NodeDescriptor sink)
Definition: Mapping.cpp:99
MRRG_NODE_ROUTING
@ MRRG_NODE_ROUTING
Definition: MRRG.h:45
MappingStatus
MappingStatus
Definition: Mapping.h:26
withRemappedOps
Mapping withRemappedOps(const Mapping &src, const std::unordered_map< OpGraph::NodeDescriptor, OpGraph::NodeDescriptor > &forward_mappings)
Definition: Mapping.cpp:288
MappingGraph::ToMRRGVertexMap
std::unordered_map< NodeDescriptor, MRRG::NodeDescriptor, NodeDescriptorHash > ToMRRGVertexMap
Definition: Mapping.h:146
OpGraphVal
Definition: OpGraph.h:178
Collections.h
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
MappingGraph::VerifyMessage::Type::Warning
@ Warning
OpGraphOp
Definition: OpGraph.h:131
MRRGNode
Definition: MRRG.h:60
Mapping::mapping
std::map< OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor > > mapping
Definition: Mapping.h:102
Mapping::clear
void clear()
Definition: Mapping.cpp:95
MappingGraph::verify
std::vector< VerifyMessage > verify(const MRRG &mrrg, const ToMRRGVertexMap &toMRRG) const
Definition: Mapping.cpp:367
MappingGraph::size
std::ptrdiff_t size() const
Definition: Mapping.cpp:313
MRRGNode::fanout
std::vector< MRRGNode * > fanout
Definition: MRRG.h:113
Mapping.h
MappingGraph::link
void link(MappingGraph::NodeDescriptor driver, MappingGraph::NodeDescriptor fanout)
Definition: Mapping.cpp:317
MappingStatus::success
@ success
Mapping::outputDetailedMapping
void outputDetailedMapping(std::ostream &o=std::cout) const
Definition: Mapping.cpp:243
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
MRRGProcedures.h
MappingGraph::getNodeRef
MappingGraphNode & getNodeRef(NodeDescriptor ndesc)
Definition: Mapping.cpp:359
reversed
auto reversed(Range &r)
Definition: Collections.h:116
MappingGraph::insert
std::pair< NodeDescriptor, bool > insert(MappingGraphNode node)
Definition: Mapping.cpp:303
Mapping::~Mapping
~Mapping()
Definition: Mapping.cpp:44
createMappingGraph
CreateMappingGraphResult createMappingGraph(const MRRG &mrrg, const Mapping &m)
Definition: Mapping.cpp:468
Mapping::unmapMRRGNode
void unmapMRRGNode(OpGraph::NodeDescriptor, MRRG::NodeDescriptor node)
Definition: Mapping.cpp:70
MappingGraph::unlink
void unlink(MappingGraph::NodeDescriptor driver, MappingGraph::NodeDescriptor fanout)
Definition: Mapping.cpp:327
OpGraph
Definition: OpGraph.h:215
MappingGraph::nodes
std::unordered_map< NodeDescriptor, MappingGraphNode, NodeDescriptorHash > nodes
Definition: Mapping.h:238
cgrame_error
Definition: Exception.h:20
OpGraphNode::getName
const std::string & getName() const
Definition: OpGraph.h:121
MappingGraphCycleAssignment
std::unordered_map< MappingGraph::NodeDescriptor, int, MappingGraph::NodeDescriptorHash > MappingGraphCycleAssignment
Definition: Mapping.h:266