ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
44
45#include "etiss/FastString.h"
46
47#include <iomanip>
48#include <iostream>
49#include <limits>
50
51namespace etiss
52{
53namespace interfaces
54{
55
56namespace dot
57{
58
59void 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
129void 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
187void 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
282const 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}
308void 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
331ValueOperationTraceGraphStreamer::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}
362
363void 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);
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);
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
444void 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);
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/*
574static bool keepNode(ValueOperationTraceGraphStreamer::Node * n,const std::unordered_map<const void
575*,ValueOperationTraceGraphStreamer::Node*,std::hash<const void*>, std::equal_to<const
576void*>,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
602void 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
718const 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
732void 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
776void 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
840void 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
848static 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
858void 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}
883static 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}
893static std::string node_getCluster(Dot::Node *n)
894{
895 if (n == nullptr)
896 return "";
897 return graph_getCluster(n->parent_);
898}
899void 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
915void 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
934void 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
978void 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
999Dot::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}
1006Dot::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}
1014Dot::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}
1024Dot::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
1033Dot::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
1041Dot::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
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
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
std::unordered_map< const void *, Node * > currentdstnodes_
Definition Dot.h:286
void defineNode(const void *id, const std::string &name)
Definition Dot.cpp:59
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 * > 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
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.
float __ovld __cnfn dot(float p0, float p1)
Compute dot product.