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