• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 28177795453

25 Jun 2026 02:33PM UTC coverage: 61.743% (+0.1%) from 61.644%
28177795453

Pull #802

github

web-flow
Merge 08f22df91 into fe9abd1cb
Pull Request #802: adds reduce as new structured loop type

705 of 985 new or added lines in 34 files covered. (71.57%)

5 existing lines in 4 files now uncovered.

38837 of 62901 relevant lines covered (61.74%)

978.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.91
/sdfg/src/visualizer/dot_visualizer.cpp
1
#include "sdfg/visualizer/dot_visualizer.h"
2

3
#include <cstddef>
4
#include <string>
5
#include <utility>
6

7
#include <regex>
8
#include "sdfg/data_flow/access_node.h"
9
#include "sdfg/data_flow/memlet.h"
10
#include "sdfg/structured_control_flow/control_flow_node.h"
11
#include "sdfg/structured_control_flow/sequence.h"
12
#include "sdfg/structured_sdfg.h"
13
#include "sdfg/symbolic/symbolic.h"
14

15
namespace sdfg {
16
namespace visualizer {
17

18
static std::regex dotIdBadChars("[^a-zA-Z0-9_]+");
19

20
static std::string escapeDotId(size_t id, const std::string& prefix = "") { return prefix + std::to_string(id); }
134✔
21

22
static std::string escapeDotId(const std::string& id, const std::string& prefix = "") {
26✔
23
    return prefix + std::regex_replace(id, dotIdBadChars, "_");
26✔
24
}
26✔
25

26
void DotVisualizer::visualizeSDFG(const SDFG& sdfg) {
1✔
27
    this->stream_.clear();
1✔
28
    this->stream_ << "digraph SDFG {\n";
1✔
29
    this->stream_.setIndent(4);
1✔
30
    this->stream_ << "graph [compound=true];" << std::endl << "node [style=filled,fillcolor=white];" << std::endl;
1✔
31

32
    // State identifier in DOT
33
    std::unordered_map<size_t, std::string> node_ids;
1✔
34

35
    // States as nodes
36
    for (auto& state : sdfg.states()) {
4✔
37
        auto id = escapeDotId(state.element_id(), "state_");
4✔
38
        this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
4✔
39
        this->stream_.setIndent(this->stream_.indent() + 4);
4✔
40
        this->stream_ << "style=filled;fillcolor=white;color=black;label=\"State " << state.element_id() << "\";"
4✔
41
                      << std::endl;
4✔
42
        if (auto* return_state = dynamic_cast<const control_flow::ReturnState*>(&state)) {
4✔
43
            this->stream_ << id << " [shape=cds,label=\" return " << return_state->data() << " \"];" << std::endl;
×
44
        } else {
4✔
45
            this->stream_ << id << " [shape=point,style=invis;label=\"\"];" << std::endl;
4✔
46
            this->visualizeDataFlowGraph(id, state.dataflow());
4✔
47
        }
4✔
48
        this->stream_.setIndent(this->stream_.indent() - 4);
4✔
49
        this->stream_ << "}" << std::endl;
4✔
50
        node_ids.insert({state.element_id(), id});
4✔
51
    }
4✔
52

53
    // Edges
54
    for (auto& edge : sdfg.edges()) {
4✔
55
        auto& src_id = node_ids.at(edge.src().element_id());
4✔
56
        auto& dst_id = node_ids.at(edge.dst().element_id());
4✔
57
        this->stream_ << src_id << " -> " << dst_id << " [ltail=cluster_" << src_id << ",lhead=cluster_" << dst_id
4✔
58
                      << ",label=\"";
4✔
59

60
        // Condition
61
        bool print_condition = !symbolic::eq(edge.condition(), symbolic::__true__());
4✔
62
        if (print_condition) {
4✔
63
            this->stream_ << edge.condition()->__str__();
2✔
64
        }
2✔
65

66
        // Assignments
67
        if (!edge.assignments().empty()) {
4✔
68
            if (print_condition) {
1✔
69
                this->stream_ << ",\\n";
×
70
            }
×
71
            this->stream_ << "{";
1✔
72
            bool first = true;
1✔
73
            for (auto& [var, expr] : edge.assignments()) {
1✔
74
                if (!first) {
1✔
75
                    this->stream_ << "; ";
×
76
                }
×
77
                this->stream_ << var->get_name() << " = " << expr->__str__();
1✔
78
                first = false;
1✔
79
            }
1✔
80
            this->stream_ << "}";
1✔
81
        }
1✔
82
        this->stream_ << "\"];" << std::endl;
4✔
83
    }
4✔
84

85
    this->stream_.setIndent(0);
1✔
86
    this->stream_ << "}" << std::endl;
1✔
87
}
1✔
88

89
void DotVisualizer::visualizeStructuredSDFG(const StructuredSDFG& sdfg) {
13✔
90
    this->stream_.clear();
13✔
91
    this->stream_ << "digraph " << escapeDotId(sdfg.name()) << " {" << std::endl;
13✔
92
    this->stream_.setIndent(4);
13✔
93
    this->stream_ << "graph [compound=true];" << std::endl;
13✔
94
    this->stream_ << "subgraph cluster_" << escapeDotId(sdfg.name()) << " {" << std::endl;
13✔
95
    this->stream_.setIndent(8);
13✔
96
    this->stream_ << "node [style=filled,fillcolor=white];" << std::endl
13✔
97
                  << "style=filled;color=lightblue;label=\"\";" << std::endl;
13✔
98
    this->visualizeSequence(sdfg, sdfg.root());
13✔
99
    this->stream_.setIndent(4);
13✔
100
    this->stream_ << "}" << std::endl;
13✔
101
    this->stream_.setIndent(0);
13✔
102
    this->stream_ << "}" << std::endl;
13✔
103
}
13✔
104

105
void DotVisualizer::visualizeBlock(const StructuredSDFG& sdfg, const structured_control_flow::Block& block) {
19✔
106
    auto id = escapeDotId(block.element_id(), "block_");
19✔
107
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
19✔
108
    this->stream_.setIndent(this->stream_.indent() + 4);
19✔
109
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
19✔
110
    if (show_block_ids) {
19✔
111
        this->stream_ << "#" << block.element_id() << " ";
×
112
    }
×
113
    this->stream_ << "\";" << std::endl;
19✔
114
    this->visualizeDataFlowGraph(id, block.dataflow());
19✔
115
    this->stream_.setIndent(this->stream_.indent() - 4);
19✔
116
    this->stream_ << "}" << std::endl;
19✔
117
}
19✔
118

119
void DotVisualizer::visualizeSequence(const StructuredSDFG& sdfg, const structured_control_flow::Sequence& sequence) {
28✔
120
    std::string last_comp_name_tmp, last_comp_name_cluster_tmp;
28✔
121
    for (size_t i = 0; i < sequence.size(); ++i) {
63✔
122
        std::pair<const structured_control_flow::ControlFlowNode&, const structured_control_flow::Transition&> child =
35✔
123
            sequence.at(i);
35✔
124
        this->visualizeNode(sdfg, child.first);
35✔
125
        if ((i > 0) && !last_comp_name_tmp.empty() && !this->last_comp_name_.empty() &&
35✔
126
            last_comp_name_tmp != this->last_comp_name_) {
35✔
127
            this->stream_ << last_comp_name_tmp << " -> " << this->last_comp_name_ << " [";
7✔
128
            if (!last_comp_name_cluster_tmp.empty()) this->stream_ << "ltail=\"" << last_comp_name_cluster_tmp << "\",";
7✔
129
            if (!this->last_comp_name_cluster_.empty())
7✔
130
                this->stream_ << "lhead=\"" << this->last_comp_name_cluster_ << "\",";
4✔
131
            this->stream_ << "minlen=3";
7✔
132
            if (!sequence.at(i - 1).second.empty()) {
7✔
133
                this->stream_ << ",label=\"{";
2✔
134
                bool comma_sep = false;
2✔
135
                for (auto& [sym, expr] : sequence.at(i - 1).second.assignments()) {
2✔
136
                    if (comma_sep) {
2✔
137
                        this->stream_ << ",";
×
138
                        comma_sep = true;
×
139
                    }
×
140
                    this->stream_ << sym->get_name() << " = " << expr->__str__();
2✔
141
                }
2✔
142
                this->stream_ << "}\"";
2✔
143
            }
2✔
144
            this->stream_ << "];" << std::endl;
7✔
145
        }
7✔
146
        last_comp_name_tmp = this->last_comp_name_;
35✔
147
        last_comp_name_cluster_tmp = this->last_comp_name_cluster_;
35✔
148
    }
35✔
149
}
28✔
150

151
void DotVisualizer::visualizeIfElse(const StructuredSDFG& sdfg, const structured_control_flow::IfElse& if_else) {
3✔
152
    auto id = escapeDotId(if_else.element_id(), "if_");
3✔
153
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
3✔
154
    this->stream_.setIndent(this->stream_.indent() + 4);
3✔
155
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
3✔
156
    if (show_block_ids) {
3✔
157
        this->stream_ << "#" << if_else.element_id() << " ";
×
158
    }
×
159
    this->stream_ << "if:\";" << std::endl << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
3✔
160
    for (size_t i = 0; i < if_else.size(); ++i) {
9✔
161
        this->stream_ << "subgraph cluster_" << id << "_" << std::to_string(i) << " {" << std::endl;
6✔
162
        this->stream_.setIndent(this->stream_.indent() + 4);
6✔
163
        this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\""
6✔
164
                      << this->expression(if_else.at(i).second->__str__()) << "\";" << std::endl;
6✔
165
        this->visualizeSequence(sdfg, if_else.at(i).first);
6✔
166
        this->stream_.setIndent(this->stream_.indent() - 4);
6✔
167
        this->stream_ << "}" << std::endl;
6✔
168
    }
6✔
169
    this->stream_.setIndent(this->stream_.indent() - 4);
3✔
170
    this->stream_ << "}" << std::endl;
3✔
171
    this->last_comp_name_ = id;
3✔
172
    this->last_comp_name_cluster_ = "cluster_" + id;
3✔
173
}
3✔
174

175
void DotVisualizer::visualizeWhile(const StructuredSDFG& sdfg, const structured_control_flow::While& while_loop) {
2✔
176
    auto id = escapeDotId(while_loop.element_id(), "while_");
2✔
177
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
2✔
178
    this->stream_.setIndent(this->stream_.indent() + 4);
2✔
179
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
2✔
180
    if (show_block_ids) {
2✔
181
        this->stream_ << "#" << while_loop.element_id() << " ";
×
182
    }
×
183
    this->stream_ << "while:\";" << std::endl << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
2✔
184
    this->visualizeSequence(sdfg, while_loop.root());
2✔
185
    this->stream_.setIndent(this->stream_.indent() - 4);
2✔
186
    this->stream_ << "}" << std::endl;
2✔
187
    this->last_comp_name_ = id;
2✔
188
    this->last_comp_name_cluster_ = "cluster_" + id;
2✔
189
}
2✔
190

191
void DotVisualizer::visualizeFor(const StructuredSDFG& sdfg, const structured_control_flow::For& loop) {
6✔
192
    auto id = escapeDotId(loop.element_id(), "for_");
6✔
193
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
6✔
194
    this->stream_.setIndent(this->stream_.indent() + 4);
6✔
195
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
6✔
196
    if (show_block_ids) {
6✔
197
        this->stream_ << "#" << loop.element_id() << " ";
×
198
    }
×
199
    this->stream_ << "for: ";
6✔
200
    this->visualizeForBounds(loop.indvar(), loop.init(), loop.condition(), loop.update());
6✔
201
    this->stream_ << "\";" << std::endl << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
6✔
202
    this->visualizeSequence(sdfg, loop.root());
6✔
203
    this->stream_.setIndent(this->stream_.indent() - 4);
6✔
204
    this->stream_ << "}" << std::endl;
6✔
205
    this->last_comp_name_ = id;
6✔
206
    this->last_comp_name_cluster_ = "cluster_" + id;
6✔
207
}
6✔
208

209
void DotVisualizer::visualizeReturn(const StructuredSDFG& sdfg, const structured_control_flow::Return& return_node) {
2✔
210
    auto id = escapeDotId(return_node.element_id(), "return_");
2✔
211
    this->stream_ << id << " [shape=cds,label=\" return " << return_node.data() << "\"];" << std::endl;
2✔
212
    this->last_comp_name_ = id;
2✔
213
    this->last_comp_name_cluster_.clear();
2✔
214
}
2✔
215
void DotVisualizer::visualizeBreak(const StructuredSDFG& sdfg, const structured_control_flow::Break& break_node) {
1✔
216
    auto id = escapeDotId(break_node.element_id(), "break_");
1✔
217
    this->stream_ << id << " [shape=cds,label=\" break  \"];" << std::endl;
1✔
218
    this->last_comp_name_ = id;
1✔
219
    this->last_comp_name_cluster_.clear();
1✔
220
}
1✔
221

222
void DotVisualizer::visualizeContinue(const StructuredSDFG& sdfg, const structured_control_flow::Continue& continue_node) {
1✔
223
    auto id = escapeDotId(continue_node.element_id(), "cont_");
1✔
224
    this->stream_ << id << " [shape=cds,label=\" continue  \"];" << std::endl;
1✔
225
    this->last_comp_name_ = id;
1✔
226
    this->last_comp_name_cluster_.clear();
1✔
227
}
1✔
228

229
void DotVisualizer::visualizeMap(const StructuredSDFG& sdfg, const structured_control_flow::Map& map_node) {
×
230
    auto id = escapeDotId(map_node.element_id(), "map_");
×
231
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
×
232
    this->stream_.setIndent(this->stream_.indent() + 4);
×
233
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
×
234
    if (show_block_ids) {
×
235
        this->stream_ << "#" << map_node.element_id() << " ";
×
236
    }
×
237
    this->stream_ << "map [" << map_node.schedule_type().value() << "]: ";
×
238
    this->visualizeForBounds(map_node.indvar(), map_node.init(), map_node.condition(), map_node.update());
×
239

240
    this->stream_ << "\";" << std::endl << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
×
241
    this->visualizeSequence(sdfg, map_node.root());
×
242
    this->stream_.setIndent(this->stream_.indent() - 4);
×
243
    this->stream_ << "}" << std::endl;
×
244
    this->last_comp_name_ = id;
×
245
    this->last_comp_name_cluster_ = "cluster_" + id;
×
246
}
×
247

248
void DotVisualizer::visualizeReduce(const StructuredSDFG& sdfg, const structured_control_flow::Reduce& reduce_node) {
1✔
249
    auto id = escapeDotId(reduce_node.element_id(), "reduce_");
1✔
250
    this->stream_ << "subgraph cluster_" << id << " {" << std::endl;
1✔
251
    this->stream_.setIndent(this->stream_.indent() + 4);
1✔
252
    this->stream_ << "style=filled;shape=box;fillcolor=white;color=black;label=\"";
1✔
253
    if (show_block_ids) {
1✔
NEW
254
        this->stream_ << "#" << reduce_node.element_id() << " ";
×
NEW
255
    }
×
256
    this->stream_ << "reduce [" << reduce_node.schedule_type().value() << "]";
1✔
257
    bool comma_sep = false;
1✔
258
    this->stream_ << " {";
1✔
259
    for (auto& reduction : reduce_node.reductions()) {
1✔
260
        if (comma_sep) {
1✔
NEW
261
            this->stream_ << ", ";
×
NEW
262
        }
×
263
        comma_sep = true;
1✔
264
        this->stream_ << structured_control_flow::reduction_operation_to_string(reduction.operation) << ": "
1✔
265
                      << reduction.container;
1✔
266
    }
1✔
267
    this->stream_ << "}: ";
1✔
268
    this->visualizeForBounds(reduce_node.indvar(), reduce_node.init(), reduce_node.condition(), reduce_node.update());
1✔
269

270
    this->stream_ << "\";" << std::endl << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
1✔
271
    this->visualizeSequence(sdfg, reduce_node.root());
1✔
272
    this->stream_.setIndent(this->stream_.indent() - 4);
1✔
273
    this->stream_ << "}" << std::endl;
1✔
274
    this->last_comp_name_ = id;
1✔
275
    this->last_comp_name_cluster_ = "cluster_" + id;
1✔
276
}
1✔
277

278
void DotVisualizer::visualizeDataFlowGraph(const std::string& id, const data_flow::DataFlowGraph& dfg) {
23✔
279
    this->last_comp_name_cluster_ = "cluster_" + id;
23✔
280
    if (dfg.nodes().empty()) {
23✔
281
        this->stream_ << id << " [shape=point,style=invis,label=\"\"];" << std::endl;
5✔
282
        this->last_comp_name_ = id;
5✔
283
        return;
5✔
284
    }
5✔
285
    this->last_comp_name_.clear();
18✔
286
    std::list<const data_flow::DataFlowNode*> nodes = dfg.topological_sort();
18✔
287
    for (const data_flow::DataFlowNode* node : nodes) {
56✔
288
        std::vector<std::string> in_connectors;
56✔
289
        bool is_access_node = false;
56✔
290
        bool node_will_show_literal_connectors = false;
56✔
291
        auto nodeId = escapeDotId(node->element_id(), "id");
56✔
292
        if (this->last_comp_name_.empty()) {
56✔
293
            this->last_comp_name_ = nodeId;
18✔
294
        }
18✔
295
        if (const data_flow::Tasklet* tasklet = dynamic_cast<const data_flow::Tasklet*>(node)) {
56✔
296
            this->stream_ << nodeId << " [shape=octagon,label=\"" << tasklet->output() << " = ";
18✔
297
            this->visualizeTasklet(*tasklet);
18✔
298
            this->stream_ << "\"];" << std::endl;
18✔
299

300
            in_connectors = tasklet->inputs();
18✔
301
            node_will_show_literal_connectors = true;
18✔
302
        } else if (const data_flow::ConstantNode* constant_node = dynamic_cast<const data_flow::ConstantNode*>(node)) {
38✔
303
            this->stream_ << nodeId << " [";
3✔
304
            this->stream_ << "penwidth=3.0,";
3✔
305
            if (this->sdfg_.is_transient(constant_node->data())) this->stream_ << "style=\"dashed,filled\",";
3✔
306
            this->stream_ << "label=\"" << constant_node->data() << "\"];" << std::endl;
3✔
307
            is_access_node = true;
3✔
308
        } else if (const data_flow::AccessNode* access_node = dynamic_cast<const data_flow::AccessNode*>(node)) {
35✔
309
            this->stream_ << nodeId << " [";
34✔
310
            this->stream_ << "penwidth=3.0,";
34✔
311
            if (this->sdfg_.is_transient(access_node->data())) this->stream_ << "style=\"dashed,filled\",";
34✔
312
            this->stream_ << "label=\"" << access_node->data() << "\"];" << std::endl;
34✔
313
            is_access_node = true;
34✔
314
        } else if (const data_flow::LibraryNode* libnode = dynamic_cast<const data_flow::LibraryNode*>(node)) {
34✔
315
            this->stream_ << nodeId << " [shape=doubleoctagon,label=\"" << libnode->toStr() << "\"];" << std::endl;
1✔
316
            in_connectors = libnode->inputs();
1✔
317
        }
1✔
318

319
        std::unordered_set<std::string> unused_connectors(in_connectors.begin(), in_connectors.end());
56✔
320
        for (const data_flow::Memlet& iedge : dfg.in_edges(*node)) {
56✔
321
            auto& src = iedge.src();
39✔
322
            auto& dst_conn = iedge.dst_conn();
39✔
323
            bool nonexistent_conn = false;
39✔
324

325
            if (!is_access_node) {
39✔
326
                auto it = unused_connectors.find(dst_conn);
20✔
327
                if (it != unused_connectors.end()) {
20✔
328
                    unused_connectors.erase(it); // remove connector from in_connectors, so it is not used again
20✔
329
                } else {
20✔
330
                    nonexistent_conn = true;
×
331
                }
×
332
            }
20✔
333

334
            this->stream_ << escapeDotId(src.element_id(), "id") << " -> " << nodeId << " [label=\"   ";
39✔
335
            bool dstIsVoid = dst_conn == "void";
39✔
336
            bool dstIsRef = dst_conn == "ref";
39✔
337
            bool dstIsDeref = dst_conn == "deref";
39✔
338
            auto& src_conn = iedge.src_conn();
39✔
339
            bool srcIsVoid = src_conn == "void";
39✔
340
            bool srcIsDeref = src_conn == "deref";
39✔
341

342
            if (nonexistent_conn) {
39✔
343
                this->stream_ << "!!"; // this should not happen, but if it does, we can still visualize the memlet
×
344
            }
×
345

346
            if (dstIsVoid || dstIsRef || dstIsDeref) { // subset applies to dst
39✔
347
                auto& dstVar = dynamic_cast<data_flow::AccessNode const&>(iedge.dst()).data();
19✔
348
                bool subsetOnDst = false;
19✔
349
                if (srcIsDeref && dstIsVoid) { // Pure Store by Memlet definition (Dereference Memlet Store)
19✔
350
                    auto& subset = iedge.subset();
×
351
                    if (subset.size() == 1 && symbolic::eq(subset[0], symbolic::integer(0))) {
×
352
                        this->stream_ << "*" << dstVar; // store to pointer without further address calc
×
353
                    } else { // fallback, this should not be allowed to happen
×
354
                        this->stream_ << dstVar; // use access node name instead of connector-name
×
355
                        subsetOnDst = true;
×
356
                    }
×
357
                } else if (dstIsVoid) { // computational memlet / output from tasklet / memory store
19✔
358
                    this->stream_ << dstVar; // use access node name instead of connector-name
19✔
359
                    subsetOnDst = true;
19✔
360
                } else {
19✔
361
                    this->stream_ << dstVar; // use access node name instead of connector-name
×
362
                }
×
363
                if (subsetOnDst) {
19✔
364
                    this->visualizeSubset(iedge.subset(), &iedge.base_type());
19✔
365
                }
19✔
366
            } else { // dst is a tasklet/library node
20✔
367
                this->stream_ << dst_conn;
20✔
368
            }
20✔
369

370
            this->stream_ << " = ";
39✔
371

372
            if (srcIsVoid || srcIsDeref) { // subset applies to src, could be computational, reference or dereference
39✔
373
                                           // memlet
374
                auto& srcVar = dynamic_cast<data_flow::AccessNode const&>(src).data();
20✔
375
                bool subsetOnSrc = false;
20✔
376
                if (srcIsVoid && dstIsRef) { // reference memlet / address-of / get-element-ptr equivalent
20✔
377
                    this->stream_ << "&";
×
378
                    subsetOnSrc = true;
×
379
                } else if (srcIsVoid && dstIsDeref) { // Dereference memlet / load from address
20✔
380
                    this->stream_ << "*";
×
381
                    auto& subset = iedge.subset();
×
382
                    if (subset.size() != 1 && symbolic::eq(subset[0], symbolic::integer(0))) { // does not match memlet
×
383
                                                                                               // definition -> fallback
384
                        subsetOnSrc = true;
×
385
                    }
×
386
                } else if (srcIsVoid) {
20✔
387
                    subsetOnSrc = true;
20✔
388
                }
20✔
389
                this->stream_ << srcVar;
20✔
390
                if (subsetOnSrc) {
20✔
391
                    this->visualizeSubset(iedge.subset(), &iedge.base_type());
20✔
392
                }
20✔
393
            } else {
20✔
394
                this->stream_ << src_conn;
19✔
395
            }
19✔
396
            this->stream_ << "   \"];" << std::endl;
39✔
397
        }
39✔
398

399
        if (!node_will_show_literal_connectors) {
56✔
400
            for (uint64_t i = 0; i < in_connectors.size(); ++i) {
38✔
401
                auto& in_conn = in_connectors[i];
×
402
                auto it = unused_connectors.find(in_conn);
×
403
                if (it != unused_connectors.end()) {
×
404
                    auto literal_id = escapeDotId(node->element_id(), "id") + "_" + escapeDotId(i, "in");
×
405
                    this->stream_ << literal_id << " [style=\"invis\", label=\"\"];" << std::endl;
×
406
                    this->stream_ << literal_id << " -> " << nodeId << " [style=\"dotted\", label=\"" << i << ":"
×
407
                                  << in_conn << "\"]" << ";" << std::endl;
×
408
                }
×
409
            }
×
410
        }
38✔
411
    }
56✔
412
}
18✔
413

414
void DotVisualizer::writeToFile(const Function& sdfg, const std::filesystem::path& file) { writeToFile(sdfg, &file); }
×
415

416
void DotVisualizer::writeToFile(const Function& sdfg, const std::filesystem::path* file) {
1✔
417
    DotVisualizer viz(sdfg);
1✔
418
    viz.visualize();
1✔
419

420
    std::filesystem::path fileName = file ? *file : std::filesystem::path(sdfg.name() + ".dot");
1✔
421

422
    auto parent_path = fileName.parent_path();
1✔
423
    if (!parent_path.empty()) {
1✔
424
        std::filesystem::create_directories(fileName.parent_path());
×
425
    }
×
426

427
    std::ofstream dotOutput(fileName, std::ofstream::out);
1✔
428
    if (!dotOutput.is_open()) {
1✔
429
        std::cerr << "Could not open file " << fileName << " for writing DOT output." << std::endl;
×
430
    }
×
431

432
    dotOutput << viz.getStream().str();
1✔
433
    dotOutput.close();
1✔
434
}
1✔
435

436
} // namespace visualizer
437
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc