ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
Dot.cpp
Go to the documentation of this file.
1 /*
2 
3  @copyright
4 
5  <pre>
6 
7  Copyright 2018 Infineon Technologies AG
8 
9  This file is part of ETISS tool, see <https://github.com/tum-ei-eda/etiss>.
10 
11  The initial version of this software has been created with the funding support by the German Federal
12  Ministry of Education and Research (BMBF) in the project EffektiV under grant 01IS13022.
13 
14  Redistribution and use in source and binary forms, with or without modification, are permitted
15  provided that the following conditions are met:
16 
17  1. Redistributions of source code must retain the above copyright notice, this list of conditions and
18  the following disclaimer.
19 
20  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
21  and the following disclaimer in the documentation and/or other materials provided with the distribution.
22 
23  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
24  or promote products derived from this software without specific prior written permission.
25 
26  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
27  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
29  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  POSSIBILITY OF SUCH DAMAGE.
34 
35  </pre>
36 
37  @author Marc Greim <marc.greim@mytum.de>, Chair of Electronic Design Automation, TUM
38 
39  @version 0.1
40 
41 */
42 
43 #include "etiss/interfaces/Dot.h"
44 
45 #include "etiss/FastString.h"
46 
47 #include <iomanip>
48 #include <iostream>
49 #include <limits>
50 
51 namespace etiss
52 {
53 namespace interfaces
54 {
55 
56 namespace dot
57 {
58 
59 void ValueOperationTraceGraph::defineNode(const void *id, const std::string &name)
60 {
61  nodes_.insert(std::make_pair(id, name));
62 }
63 
65 {
66  nodes_.erase(id);
67  currentnodes_.erase(id);
68  currentdstnodes_.erase(id);
69 }
70 
72 {
73  if (src == 0 || dst == 0)
74  return 0;
75 
76  auto curme = currentnodes_.find(src); // find current src node
77  Node *idn;
78  if (curme == currentnodes_.end())
79  {
80  auto curdstme = currentdstnodes_.find(src);
81  if (curdstme != currentdstnodes_.end()) // destination node becomes source node
82  {
83  currentnodes_.insert(*curdstme);
84  currentdstnodes_.erase(curdstme->first);
85  idn = curdstme->second;
86  }
87  else
88  {
89  // create initial src node
90  idn = new Node();
91  idn->id = src;
92  // if (nodes_.find(src) != nodes_.end()) // link to start node if defined
93  {
94  Link *rl = new Link();
95  rl->dst = idn;
96  rl->color = "yellow";
97  start.links.push_back(rl);
98  }
99  currentnodes_.insert(std::make_pair(src, idn));
100  }
101  }
102  else
103  {
104  idn = curme->second;
105  }
106 
107  // new node for dst
108  Node *dstn;
109  auto curdst = currentdstnodes_.find(dst);
110  if (curdst != currentdstnodes_.end()) // use existing dst node
111  {
112  dstn = curdst->second;
113  }
114  else
115  {
116  dstn = new Node();
117  dstn->id = dst;
118  currentdstnodes_.insert(std::make_pair(dst, dstn));
119  }
120 
121  // create link
122  Link *ret = new Link();
123  ret->dst = dstn;
124  idn->links.push_back(ret);
125 
126  return ret;
127 }
128 
129 void ValueOperationTraceGraph::filterTmp(Node *start_, Node *tmp, bool hideedge, const std::string &alabels,
130  std::ofstream &out, std::unordered_set<Node *> &nnl,
131  std::unordered_set<std::pair<const void *, const void *>> &dependencies,
132  std::unordered_set<Node *> &declared)
133 {
134 
135  auto find = nodes_.find(tmp->id);
136  if (find != nodes_.end()) // terminate recursion
137  {
138 
139  bool revisit = true;
140  if (declared.find(tmp) == declared.end())
141  {
142  out << "\t" << ((size_t)tmp) << " [label=\"" << find->second << "\"];\n";
143  revisit = false;
144  declared.insert(tmp);
145  }
146 
147  if (!hideedge)
148  {
149 
150  out << "\t" << ((size_t)start_) << " -> " << ((size_t)tmp);
151 
152  {
153  std::string attr;
154 
155  attr = attr + ((attr.size() == 0) ? "" : " ") + "label=\"" + alabels + "\"";
156 
157  if (attr.size() > 0)
158  out << " [" << attr << "];\n";
159  }
160  }
161 
162  if (!revisit)
163  nnl.insert(tmp);
164 
165  if (start_->id != 0) // filter start node
166  dependencies.insert(std::make_pair(start_->id, tmp->id));
167  }
168  else
169  {
170 
171  std::list<Link *> tmplinks = tmp->links;
172  tmp->links.clear();
173 
174  for (auto iter = tmplinks.begin(); iter != tmplinks.end(); ++iter)
175  {
176 
177  std::string l = alabels + "," + (*iter)->label;
178 
179  filterTmp(start_, (*iter)->dst, hideedge, l, out, nnl, dependencies,
180  declared); // hide link if this is not a direct link between a named node and the origin
181 
182  delete *iter;
183  }
184  }
185 }
186 
187 void ValueOperationTraceGraph::flush(std::ofstream &out, const std::string &graph)
188 {
189  std::unordered_set<std::pair<const void *, const void *>> dependencies;
190 
191  out << "digraph " << graph << "{\n";
192 
193  {
194  std::unordered_set<Node *> nl;
195  nl.insert(&start);
196 
197  out << "\t" << ((size_t)&start) << " [label=\"START\"];\n";
198 
199  std::unordered_set<Node *> defined;
200 
201  while (nl.size() > 0)
202  {
203 
204  std::unordered_set<Node *> nnl;
205  for (auto iter = nl.begin(); iter != nl.end(); ++iter)
206  {
207  Node *cur = *iter;
208  if (cur)
209  {
210  for (auto iter2 = cur->links.begin(); iter2 != cur->links.end(); ++iter2)
211  {
212  Link *curl = *iter2;
213  if (curl)
214  {
215  filterTmp(cur, curl->dst,
216  ((cur == &this->start) && (nodes_.find(curl->dst->id) == nodes_.end())),
217  curl->label, out, nnl, dependencies, defined);
218  /*
219  auto find = nodes_.find(curl->dst->id);
220  if (find != nodes_.end())
221  {
222  out << "\t" << ((size_t)curl->dst) << " [label=\"" <<
223  find->second << "\"];\n";
224  }
225  else
226  {
227  out << "\t" << ((size_t)curl->dst) << " [label=\"tmp\"];\n";
228  }
229  out << "\t" << ((size_t)cur) << " -> " << ((size_t)curl->dst);
230  {
231  std::string attr;
232  if (curl->color.size() > 0)
233  attr = attr + ((attr.size()==0)?"":" ") + "color=\"" +
234  curl->color +"\""; if (curl->label.size() > 0) attr = attr +
235  ((attr.size()==0)?"":" ") + "label=\"" + curl->label +"\""; if
236  (attr.size() > 0) out << " [" << attr << "]";
237  }
238  out << ";\n";
239  nnl.push_back(curl->dst);
240  */
241  // delete curl;
242  }
243  }
244  // if (cur != &start)
245  // delete cur;
246  }
247  }
248 
249  nl = nnl;
250  }
251  }
252 
253  out << "}\n";
254 
255  out << "digraph " << graph << "_dep {\n";
256 
257  {
258  std::unordered_set<const void *> present;
259  for (auto iter = dependencies.begin(); iter != dependencies.end(); ++iter)
260  {
261  if (present.find(iter->first) == present.end())
262  {
263  present.insert(iter->first);
264  std::string name = nodes_[iter->first]; // should always succeed due to
265  // filterTmp function.
266  out << "\t" << ((size_t)iter->first) << " [label=\"" << name << "\"];\n";
267  }
268  if (present.find(iter->second) == present.end())
269  {
270  present.insert(iter->second);
271  std::string name = nodes_[iter->second]; // should always succeed due to
272  // filterTmp function.
273  out << "\t" << ((size_t)iter->second) << " [label=\"" << name << "\"];\n";
274  }
275  out << "\t" << ((size_t)iter->first) << " -> " << ((size_t)iter->second) << ";\n";
276  }
277  }
278 
279  out << "}\n";
280 }
281 
282 const double ValueOperationTraceGraphStreamer::Node::Nan = std::numeric_limits<double>::quiet_NaN();
283 
285 {
286  std::vector<std::string> al;
287  if (color && color[0])
288  ss << " color=" << color;
289  if (time == time)
290  ss << " time=" << std::setprecision(std::numeric_limits<double>::digits10 + 2) << std::fixed << time;
291  if (cluster && cluster[0])
292  ss << " cluster=\"" << cluster << "\"";
293  if (weight == weight)
294  ss << " weight=" << weight;
295  if (attrMap)
296  {
297  for (auto &attr : *attrMap)
298  {
299  ss << " " << attr.first << "=\"" << attr.second << "\"";
300  }
301  }
302 }
304 {
305  if (attrMap)
306  delete attrMap;
307 }
308 void ValueOperationTraceGraphStreamer::Node::setAttr(const std::string &name, const std::string &value)
309 {
310  if (!attrMap)
311  attrMap = new std::map<std::string, std::string>();
312  (*attrMap)[name] = value;
313 }
314 
316 {
317  // static etiss::string::form_string fs(" color=",16," label=\"",257); /// @attention testing only
318  // if (color || label[0]){
319  // fs.write(1,color?color:"white",strlen(color?color:"white"));
320  // fs.writet(1,label,strlen(label),'\"',0);
321  // ss << fs;
322  // }
323 
324  std::vector<std::string> al;
325  if (color && color[0])
326  ss << " color=" << color;
327  if (label[0])
328  ss << " label=\"" << label << "\"";
329 }
330 
331 ValueOperationTraceGraphStreamer::ValueOperationTraceGraphStreamer(const std::string &file, const std::string &depfile)
332 {
333 
335 
336  // nodeToTmpId_.rehash(1<<16);
337  // currentnodes_.rehash(1<<16);
338  // nodes_.rehash(1<<16);
339  dependencies_.rehash(1 << 16);
340 
341  out.rdbuf()->pubsetbuf(out_buf, sizeof(out_buf));
342  depout.rdbuf()->pubsetbuf(depout_buf, sizeof(depout_buf));
343 
344  out.open(file);
345  depout.open(depfile);
346 
347  closed_ = (!out.is_open()) && (!depout.is_open());
348 
349  if (closed_)
350  {
351  std::cout << "Error: Can't open either " << file << " or " << depfile << std::endl;
352  return;
353  }
354 
355  out << "digraph VOT {\n";
356  depout << "digraph VOTD {\n";
357 }
359 {
360  close();
361 }
362 
363 void ValueOperationTraceGraphStreamer::defineNode(const void *id, const std::string &name)
364 {
365  if (closed_)
366  return;
367  nodes_.insert(id, name);
368  depout << "\t" << ((size_t)id) << "[label=\"" << name << "\"];\n";
369  depout.flush();
370 }
372 {
373  if (closed_)
374  return;
375  nodes_.erase(id);
376  Node *wnode = 0;
377  // write and remove node if not linked
378  {
379  auto find = currentnodes_.find(id);
380  if (find != 0)
381  {
382  if (((*find)->links_out.size() == 0))
383  wnode = (*find);
384  currentnodes_.erase(find);
385  }
386  }
387  if (wnode)
388  traverse(wnode);
389 }
390 
392 {
393  {
394  auto find = currentnodes_.find(src);
395  if (find != 0) // node already exists
396  {
397  return *find;
398  }
399  }
400 
401  // create
403  node_alloc_.construct(ret, src);
404  currentnodes_.insert(src, ret);
405  if (setCurrentNodeAttr)
406  setCurrentNodeAttr(ret);
407  return ret;
408 }
409 
411  Node *&cleanup)
412 {
413 
414  {
415  auto find = currentnodes_.find(dst);
416  if (find != 0) // old node exists
417  {
418  if ((*find)->links_out.empty())
419  cleanup = *find;
420  currentnodes_.erase((*find));
421  }
422  }
423 
424  // create
426  node_alloc_.construct(ret, dst);
427  currentnodes_.insert(dst, ret);
428  if (setCurrentNodeAttr)
429  setCurrentNodeAttr(ret);
430  return ret;
431 }
432 
434 {
435  size_t pos = 0;
436  while ((src_[pos] != 0) && (pos < (label_size - 1)))
437  {
438  label[pos] = src_[pos];
439  ++pos;
440  }
441  label[pos] = 0;
442 }
443 
444 void ValueOperationTraceGraphStreamer::link(const void *dst, std::initializer_list<const void *> sources,
445  const char *label)
446 {
447  // check if Dot file is still open
448  if (unlikely(closed_))
449  return;
450 
451  // check if start node is valid
452  if (unlikely(dst == 0))
453  return;
454 
455  // create for all sources new Nodes
456  Node **srcns = new Node *[sources.size()];
457 
458  size_t pos = 0;
459  // get pointers for all source Nodes
460  for (auto iter = sources.begin(); likely(iter != sources.end()); ++iter)
461  {
462  const void *ptr = *iter;
463  if (likely(ptr != 0))
464  {
465  // get source node, if it doesn't exist it'll be created
466  srcns[pos++] = openSourceNode(ptr);
467  }
468  }
469 
470  // we dont have a valid source pointer
471  if (pos == 0)
472  {
473  delete[] srcns;
474  return;
475  }
476 
477  // get destination node, if it doesn't exist it'll be created. If it is a named TF, the link
478  // can get visible -> clean up gets the pointer to this TF
479  Node *cleanup = 0;
480  Node *dstn = openDestNode(dst, cleanup);
481 
482  // For all valid source nodes, insert invisible link to Link pool.
483  for (size_t i = 0; i < pos; ++i)
484  {
485  Link *l = link_alloc_.allocate(1);
486  link_alloc_.construct(l, srcns[i], dstn);
487  srcns[i]->links_out.insert(l);
488  dstn->links_in.insert(l);
489  if (label)
490  l->setLabel(label);
491  if (setCurrentLinkAttr)
492  setCurrentLinkAttr(l, dstn, srcns, pos, sources, label);
493  }
494 
495  if (cleanup)
496  {
497  traverse(cleanup);
498  }
499 
500  if (nodes_.find(dst) != 0) // write path if path can be written
501  traverse(dstn);
502 
503  delete[] srcns;
504 }
505 
507 {
508  if (path.empty())
509  return;
510 
511  auto src = path.back()->src;
512  auto dst = path.front()->dst;
513  auto sfind = nodes_.find(src->id);
514  auto dfind = nodes_.find(dst->id);
515  // stream value dependency
516  {
517  if ((dfind != 0) && (sfind != 0))
518  {
519  std::cout << "writePath" << std::endl;
520  std::pair<const void *, const void *> p = std::make_pair(src->id, dst->id);
521  if (dependencies_.find(p) == dependencies_.end())
522  {
523  depout << "\t" << ((size_t)src->id) << " -> " << ((size_t)dst->id) << ";\n";
524  // depout.flush();
525  dependencies_.insert(p);
526  }
527  }
528  }
529 
531  {
532  if ((dfind != 0) && (sfind != 0))
533  {
534  if ((!hidePath) || (!hidePath(path)))
535  {
536  out << "\tnode [shape=ellipse];\n";
537  auto sifind = nodeToTmpId_.find(src);
538  if (sifind == 0)
539  {
540  sifind = nodeToTmpId_.insert(src, nnodeid_++);
541  out << "\t" << +(*sifind) << " [label=\"" << *sfind << "\"";
542  src->attrToString(out);
543  out << "];\n";
544  }
545  auto difind = nodeToTmpId_.find(dst);
546  if (difind == 0)
547  {
548  difind = nodeToTmpId_.insert(dst, nnodeid_++);
549  out << "\t" << +(*difind) << " [label=\"" << *dfind << "\"";
550  dst->attrToString(out);
551  out << "];\n";
552  }
553  Link *tmp = link_alloc_.allocate(1);
554  link_alloc_.construct(tmp, src, dst);
555  if (setMetaLinkAttr)
556  {
557  setMetaLinkAttr(tmp, path);
558  }
559  out << "\t" << +(*sifind) << " -> " << +(*difind) << " [";
560  tmp->attrToString(out);
561  out << "];\n";
562  // out.flush();
563  link_alloc_.destroy(tmp);
564  link_alloc_.deallocate(tmp);
565  }
566  }
567  }
568 
569  if (custWritePath)
571 }
572 
573 /*
574 static bool keepNode(ValueOperationTraceGraphStreamer::Node * n,const std::unordered_map<const void
575 *,ValueOperationTraceGraphStreamer::Node*,std::hash<const void*>, std::equal_to<const
576 void*>,etiss::ObjectPool<std::pair<const void * const,ValueOperationTraceGraphStreamer::Node*> > > & current)
577 {
578  if (!n->links_out_.empty()) // check if there are links from this node
579  return true;
580 
581  auto find = current.find(n->id);
582  // check if this node is not in the set of current nodes
583  if (find == current.end())
584  return false;
585  return find->second == n;
586 }
587 */
591 {
592  if (!n->links_out_.empty()) // check if there are links from this node
593  return true;
594 
595  auto find = current.find(n->id);
596  // check if this node is not in the set of current nodes
597  if (find == 0)
598  return false;
599  return *find == n;
600 }
601 
602 void ValueOperationTraceGraphStreamer::traverse(Node *n) //,std::unordered_set<Node*> & nodes) // debug loop detection
603 {
604 
605  if (n == 0)
606  return;
607 
608  bool dellink = false; // delete the link leading from the current end node
609 
610  Node *cur = n; // use node if no path present
611  if (!path.empty())
612  {
613  cur = path.back()->src; // use node at end of path
614  if ((nodes_.find(path.back()->dst->id) != 0) ||
615  !keepNode(path.back()->dst, currentnodes_)) // check if cleanup possible // cleanup is possible if the
616  // originating node is a known ode or if keepNode is false
617  {
618  // remove link to allow further cleanup
619  cur->links_out.erase(path.back());
620  path.back()->dst->links_in.erase(path.back());
621  dellink = true;
622  }
623  }
624  /* debug loop detection
625  if (nodes.find(cur) != nodes.end())
626  {
627  std::cout << "Loop detected" << std::endl;
628  }
629  else
630  {
631  nodes.insert(cur);
632  }
633  */
634 
635  if ((cur->links_in.size() == 0)) // end of path
636  {
637  if (path.size() > 0)
638  writePath();
639  if (dellink)
640  {
641  Link *dl = path.back();
642  link_alloc_.destroy(dl);
643  link_alloc_.deallocate(dl);
644  if (!keepNode(cur, currentnodes_))
645  {
646  nodeToTmpId_.erase(cur);
647  node_alloc_.destroy(cur);
648  node_alloc_.deallocate(cur);
649  }
650  }
651  else if (cur == n)
652  {
653  if (!keepNode(cur, currentnodes_))
654  {
655  nodeToTmpId_.erase(cur);
656  node_alloc_.destroy(cur);
657  node_alloc_.deallocate(cur);
658  }
659  }
660  // nodes.erase(cur); //debug loop detection
661  return;
662  }
663 
664  // visit all links
665  {
666  std::unordered_set<Link *> &links = cur->links_in; // don't copy link list but take special care with iterator
667  for (auto iter = links.begin(); iter != links.end();)
668  {
669  path.push(*iter);
670  ++iter; // change iter here since traverse may invalidate it
671  traverse(n); //,nodes); /debug loop detection
672  path.pop();
673  }
674  }
675 
676  if (dellink)
677  {
678  Link *dl = path.back();
679  link_alloc_.destroy(dl);
680  link_alloc_.deallocate(dl);
681  if (!keepNode(cur, currentnodes_))
682  {
683  nodeToTmpId_.erase(cur);
684  node_alloc_.destroy(cur);
685  node_alloc_.deallocate(cur);
686  }
687  }
688  else if (cur == n)
689  {
690  if (!keepNode(cur, currentnodes_))
691  {
692  nodeToTmpId_.erase(cur);
693  node_alloc_.destroy(cur);
694  node_alloc_.deallocate(cur);
695  }
696  }
697 
698  // nodes.erase(cur); //debug loop detection
699 }
700 
702 {
703  if (closed_)
704  return;
705  out << "}";
706  depout << "}";
707  closed_ = true;
708  depout.close();
709  out.close();
710 }
711 
713 {
714  depout.flush();
715  out.flush();
716 }
717 
718 const std::unordered_set<std::pair<const void *, const void *>> &ValueOperationTraceGraphStreamer::staticDependencies()
719  const
720 {
721  return dependencies_;
722 }
723 
725 {
726  tmp_.rehash(1 << 13);
727  // names_.rehash(1<<13); // not many changes expected. keep map small
728  deps_.rehash(1 << 13); // expected behaviour is to grow at the beginning and then remain constant. bucket size
729  // should be medium large to prevent frequent rehashes at the beginning
730 }
731 
732 void VariableDependencyGraph::link(const void *dst, const std::initializer_list<const void *> &sources)
733 {
734  if (names_.find(dst) != names_.end())
735  {
736  for (auto iter = sources.begin(); iter != sources.end(); ++iter)
737  {
738  std::pair<const void *, const void *> tmpp(0, dst);
739  if (names_.find(*iter) != names_.end())
740  {
741  tmpp.first = *iter;
742  deps_.insert(tmpp);
743  }
744  else
745  {
746  const std::unordered_set<const void *> &srcset = tmp_[*iter];
747  for (auto iter2 = srcset.begin(); iter2 != srcset.end(); ++iter2)
748  {
749  tmpp.first = *iter2;
750  deps_.insert(tmpp);
751  }
752  }
753  }
754  }
755  else
756  {
757  std::unordered_set<const void *> &tmpset = tmp_[dst];
758  for (auto iter = sources.begin(); iter != sources.end(); ++iter)
759  {
760  if (names_.find(*iter) != names_.end())
761  {
762  tmpset.insert(*iter);
763  }
764  else
765  {
766  const std::unordered_set<const void *> &srcset = tmp_[*iter];
767  for (auto iter2 = srcset.begin(); iter2 != srcset.end(); ++iter2)
768  {
769  tmpset.insert(*iter2);
770  }
771  }
772  }
773  }
774 }
775 
776 void VariableDependencyGraph::write(std::ostream &out, const std::string &graphname,
777  std::function<bool(const void *, const void *, std::string &)> filterOutCon,
778  std::function<void(const void *, std::string & /*color*/)> nodeattr)
779 {
780 
781  bool hideDisconnected = true;
782 
783  out << "digraph " << graphname << "{\n";
784 
785  if (!hideDisconnected)
786  {
787  for (auto iter = names_.begin(); iter != names_.end(); ++iter)
788  {
789  out << "\t" << ((size_t)iter->first) << " [label=\"" << iter->second << "\"];\n";
790  }
791  }
792  else
793  {
794  std::unordered_set<const void *> cids;
795  for (auto iter = deps_.begin(); iter != deps_.end(); ++iter)
796  {
797  std::string color;
798  if ((!filterOutCon) || ((!filterOutCon(iter->first, iter->second, color))))
799  {
800  cids.insert(iter->first);
801  cids.insert(iter->second);
802  }
803  }
804  for (auto iter = cids.begin(); iter != cids.end(); ++iter)
805  {
806  std::string color;
807  nodeattr(*iter, color);
808  out << "\t" << ((size_t)*iter) << " [label=\"" << names_[*iter] << "\"";
809  if (color.size() > 0)
810  out << " color=" << color;
811  out << "];\n";
812  }
813  }
814 
815  for (auto iter = deps_.begin(); iter != deps_.end(); ++iter)
816  {
817  std::string color;
818  if ((!filterOutCon) || ((!filterOutCon(iter->first, iter->second, color))))
819  {
820  out << "\t" << ((size_t)iter->first) << " -> " << ((size_t)iter->second);
821  bool hasattr = color.size() > 0;
822  if (hasattr)
823  {
824  out << " [";
825 
826  if (color.size() > 0)
827  out << "color=" << color << " ";
828 
829  out << "]";
830  }
831  out << ";\n";
832  }
833  }
834 
835  out << "}\n";
836 }
837 
838 #ifdef TRACEABLEFIED_H_
839 
840 void VariableDependencyGraph::tf_write(const std::string & filename,
841  const std::string & graphname,
842  std::function<size_t(const std::string & ,size_t > split);
843 
844 #endif
845 
846 } // namespace dot
847 
848 static std::string depth(Dot::Node *node)
849 {
850  if (node == nullptr)
851  return "";
852  if (node->parent_ == nullptr)
853  return "";
854 
855  return depth(node->parent_) + "\t";
856 }
857 
858 void Dot::AttrList::print(std::ostream &out, const std::string &appendedattr)
859 {
860  bool none = label_.empty() && color_.empty() && appendedattr.empty();
861  bool first = true;
862  if (!none)
863  {
864  out << "[";
865  if (label_.size() > 0)
866  {
867  out << (first ? "" : " ") << "label=\"" << label_ << "\"";
868  first = false;
869  }
870  if (color_.size() > 0)
871  {
872  out << (first ? "" : " ") << " color=" << color_;
873  first = false;
874  }
875  if (!appendedattr.empty())
876  {
877  out << (first ? "" : " ") << appendedattr;
878  first = false;
879  }
880  out << "]";
881  }
882 }
883 static std::string graph_getCluster(Dot::Graph *g)
884 {
885  if (g == nullptr)
886  return "";
887  std::string ret = graph_getCluster(g->parent_);
888  if (!ret.empty())
889  ret = ret + "::";
890  ret = ret + g->label_;
891  return ret;
892 }
893 static std::string node_getCluster(Dot::Node *n)
894 {
895  if (n == nullptr)
896  return "";
897  return graph_getCluster(n->parent_);
898 }
899 void Dot::Node::print(std::ostream &out, std::unordered_set<Link *> &icl)
900 {
901  std::string aa;
902 
903  if (true) // add cluster as an attribute
904  {
905  aa = "cluster=\"";
906  aa = aa + node_getCluster(this) + "\"";
907  }
908 
909  out << depth(this) << " \"" << id_ << "\" ";
910  AttrList::print(out, aa);
911  out << ";\n";
912  icl.insert(links_.begin(), links_.end());
913 }
914 
915 void Dot::Link::print(std::ostream &out)
916 {
917  out << depth(src_ ? src_ : dst_) << "\"" << (src_ ? src_->id_ : "0") << "\" "
918  << "->" << " \"" << (dst_ ? dst_->id_ : "0") << "\" ";
919  AttrList::print(out, "");
920  out << ";\n";
921 }
922 
924 {
925  if (g == nullptr)
926  return false;
927  if (n == nullptr)
928  return false;
929  if (n->parent_ == g)
930  return true;
931  return graph_contains(g, n->parent_);
932 }
933 
934 void Dot::Graph::print(std::ostream &out, std::unordered_set<Link *> &icl)
935 {
936  out << depth(this) << (parent_ ? "subgraph \"cluster_" : "digraph \"cluster_");
937  if (!label_.empty())
938  out << label_;
939  else
940  out << id_;
941  out << "\" {\n";
942  out << depth(this) << "label=\"";
943  if (!label_.empty())
944  out << label_;
945  else
946  out << id_;
947  out << "\";\n\nnode;\n";
948 
949  std::unordered_set<Link *> links;
950  // handle nodes first
951  for (auto iter = nodes_.begin(); iter != nodes_.end(); ++iter)
952  {
953  if (!(*iter)->asGraph())
954  (*iter)->print(out, links);
955  }
956  // handle sub graphs
957  for (auto iter = nodes_.begin(); iter != nodes_.end(); ++iter)
958  {
959  if ((*iter)->asGraph())
960  (*iter)->print(out, links);
961  }
962 
963  for (auto iter = links.begin(); iter != links.end(); ++iter)
964  {
965  if (graph_contains(this, (*iter)->src_) && graph_contains(this, (*iter)->dst_))
966  {
967  (*iter)->print(out);
968  }
969  else
970  {
971  icl.insert(*iter);
972  }
973  }
974 
975  out << depth(this) << "}\n";
976 }
977 
978 void Dot::print(std::ostream &out)
979 {
980  for (auto iter = graphs_.begin(); iter != graphs_.end(); ++iter)
981  {
982  std::unordered_set<Link *> icl;
983  (*iter)->print(out, icl);
984  if (!icl.empty())
985  {
986  etiss_log(ERROR, "bug detected");
987  }
988  }
989 }
990 
992 {
993  for (auto iter = graphs_.begin(); iter != graphs_.end();)
994  {
995  delete *(iter++);
996  }
997 }
998 
999 Dot::Graph *Dot::createG(std::string name)
1000 {
1001  Graph *ret = new Graph(this, nullptr); // note: this is why a numeral id must be a valid pointer
1002  ret->label_ = name;
1003  graphs_.push_back(ret);
1004  return ret;
1005 }
1006 Dot::Graph *Dot::createG(Dot::Graph *parent, std::string name)
1007 {
1008  if (parent == nullptr)
1009  return nullptr;
1010  Graph *ret = new Graph(this, parent); // note: this is why a numeral id must be a valid pointer
1011  ret->label_ = name;
1012  return ret;
1013 }
1014 Dot::Node *Dot::createN(Dot::Graph *parent, const std::string &id, std::string name)
1015 {
1016  if (parent == nullptr)
1017  return nullptr;
1018  if ((!id.empty()) && (idmap_.find(id) != idmap_.end()))
1019  return nullptr;
1020  Node *ret = new Node(this, parent, id);
1021  ret->label_ = name;
1022  return ret;
1023 }
1024 Dot::Link *Dot::createE(Dot::Node *src, Dot::Node *dst, std::string name)
1025 {
1026  if ((dst == nullptr) || (src == nullptr))
1027  return nullptr;
1028  Link *ret = new Link(src, dst);
1029  ret->label_ = name;
1030  return ret;
1031 }
1032 
1033 Dot::Node *Dot::find(const std::string &id)
1034 {
1035  auto find = idmap_.find(id);
1036  if (find != idmap_.end())
1037  return find->second;
1038  return nullptr;
1039 }
1040 
1041 Dot::Node *Dot::lopenN(const std::list<std::string> &labelpath)
1042 {
1043  if (labelpath.size() < 2) // at least a graph + node name are needed
1044  return nullptr;
1045  auto iter = labelpath.begin();
1046  Graph *parent = 0;
1047  for (auto i = graphs_.begin(); i != graphs_.end(); ++i)
1048  {
1049  if ((*i)->label_ == *iter)
1050  {
1051  parent = *i;
1052  break;
1053  }
1054  }
1055  if (parent == nullptr)
1056  parent = createG(*iter);
1057  iter++;
1058  // travel to right sub graph
1059  auto niter = iter;
1060  niter++;
1061  while (niter != labelpath.end())
1062  {
1063  Graph *nparent = nullptr;
1064  for (auto i = parent->nodes().begin(); i != parent->nodes().end(); ++i)
1065  {
1066  if ((*i)->asGraph())
1067  {
1068  if ((*i)->label_ == *iter)
1069  {
1070  nparent = (*i)->asGraph();
1071  break;
1072  }
1073  }
1074  }
1075  if (nparent == nullptr)
1076  nparent = createG(parent, *iter);
1077  parent = nparent;
1078  iter++;
1079  niter = iter;
1080  niter++;
1081  }
1082  Node *ret = nullptr;
1083  for (auto i = parent->nodes().begin(); i != parent->nodes().end(); ++i)
1084  {
1085  if ((*i)->label_ == *iter)
1086  {
1087  ret = *i;
1088  break;
1089  }
1090  }
1091  if (ret == nullptr)
1092  ret = createN(parent, "", *iter);
1093  return ret;
1094 }
1095 
1096 } // namespace interfaces
1097 } // namespace etiss
#define etiss_log(LEVEL, MSG)
Definition: Misc.h:83
#define likely(x)
Definition: types.h:73
#define unlikely(x)
Definition: types.h:74
V * find(const K &key)
void erase(const K &key)
void print(std::ostream &out, const std::string &appendedattr)
Definition: Dot.cpp:858
Graph * asGraph() override
Definition: Dot.h:205
const std::unordered_set< Node * > & nodes()
Definition: Dot.h:211
void print(std::ostream &out, std::unordered_set< Link * > &icl) override
Definition: Dot.cpp:934
virtual void print(std::ostream &out, std::unordered_set< Link * > &icl)
Definition: Dot.cpp:899
Graph *const parent_
Definition: Dot.h:138
Node * createN(Graph *, const std::string &id, std::string name="")
Definition: Dot.cpp:1014
virtual void print(std::ostream &out)
Definition: Dot.cpp:978
Graph * createG(std::string name="")
Definition: Dot.cpp:999
Node * lopenN(const std::list< std::string > &labelpath)
travel/creates sub graphs with the given labels until i find/creates a node for the lase label.
Definition: Dot.cpp:1041
Link * createE(Node *src, Node *dst, std::string name="")
Definition: Dot.cpp:1024
Node * find(const std::string &id)
Definition: Dot.cpp:1033
const std::unordered_set< Link * > & links_out_
Definition: Dot.h:323
void setAttr(const std::string &name, const std::string &value)
Definition: Dot.cpp:308
std::map< std::string, std::string > * attrMap
Definition: Dot.h:329
const std::unordered_set< std::pair< const void *, const void * > > & staticDependencies() const
Definition: Dot.cpp:718
Node * openSourceNode(const void *const src)
Definition: Dot.cpp:391
bool enable_default_graph_streaming_
set to false to disable the streaming of variable dependencies over time.
Definition: Dot.h:366
std::function< void(Link *, const etiss::ExpandingNativeStack< Link *, 1000 > &)> setMetaLinkAttr
Definition: Dot.h:395
etiss::FixedSizeHashMap< const void *, Node *, etiss::pointerHash< const void > > currentnodes_
Definition: Dot.h:380
std::function< void(Node *)> setCurrentNodeAttr
Definition: Dot.h:391
std::function< void(const etiss::ExpandingNativeStack< Link *, 1000 > &)> custWritePath
Definition: Dot.h:396
std::unordered_set< std::pair< const void *, const void * > > dependencies_
Definition: Dot.h:385
ValueOperationTraceGraphStreamer(const std::string &file, const std::string &depfile)
Definition: Dot.cpp:331
void link(const void *dst, std::initializer_list< const void * > sources, const char *label=0)
Definition: Dot.cpp:444
etiss::ExpandingNativeStack< Link *, 1000 > path
Definition: Dot.h:373
std::function< bool(const etiss::ExpandingNativeStack< Link *, 1000 > &)> hidePath
Definition: Dot.h:397
std::function< void(Link *, Node *, Node *const *, size_t, std::initializer_list< const void * > &, const char *)> setCurrentLinkAttr
Definition: Dot.h:394
Node * openDestNode(const void *const dst, Node *&cleanup)
Definition: Dot.cpp:410
etiss::FixedSizeHashMap< Node *, uint64_t, etiss::pointerHash< const void > > nodeToTmpId_
Definition: Dot.h:379
void defineNode(const void *id, const std::string &name)
Definition: Dot.cpp:363
etiss::FixedSizeHashMap< const void *, std::string, etiss::pointerHash< const void > > nodes_
Definition: Dot.h:383
Link * link(const void *src, const void *dst)
Definition: Dot.cpp:71
void filterTmp(Node *start, Node *tmp, bool hideedge, const std::string &alabels, std::ofstream &out, std::unordered_set< Node * > &nnl, std::unordered_set< std::pair< const void *, const void * >> &dependencies, std::unordered_set< Node * > &declared)
Definition: Dot.cpp:129
std::unordered_map< const void *, Node * > currentdstnodes_
Definition: Dot.h:286
void defineNode(const void *id, const std::string &name)
Definition: Dot.cpp:59
std::unordered_map< const void *, Node * > currentnodes_
Definition: Dot.h:285
std::unordered_map< const void *, std::string > nodes_
Definition: Dot.h:287
void flush(std::ofstream &out, const std::string &graph)
Definition: Dot.cpp:187
void link(const void *dst, const std::initializer_list< const void * > &sources)
Definition: Dot.cpp:732
void write(std::ostream &out, const std::string &graphname, std::function< bool(const void *, const void *, std::string &)> filterOutCon=[](const void *, const void *, std::string &) { return false;}, std::function< void(const void *, std::string &)> nodeattr=[](const void *, std::string &) {})
Definition: Dot.cpp:776
std::set< Instruction * > Node
Holding unique instruction sets code chunks after permutation.
Definition: Instruction.h:155
static bool keepNode(ValueOperationTraceGraphStreamer::Node *n, const etiss::FixedSizeHashMap< const void *, ValueOperationTraceGraphStreamer::Node *, etiss::pointerHash< const void >> &current)
Definition: Dot.cpp:588
static std::string node_getCluster(Dot::Node *n)
Definition: Dot.cpp:893
static std::string graph_getCluster(Dot::Graph *g)
Definition: Dot.cpp:883
static std::string depth(Dot::Node *node)
Definition: Dot.cpp:848
static bool graph_contains(Dot::Graph *g, Dot::Node *n)
Definition: Dot.cpp:923
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: Benchmark.h:53
std::list< std::string > split(const std::string &str, std::function< size_t(const std::string &, size_t, size_t &)> findsplit)
Definition: Misc.cpp:91
@ ERROR
Definition: Misc.h:127
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Definition: opencl-c-base.h:40
float __ovld __cnfn dot(float p0, float p1)
Compute dot product.