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

daisytuner / sdfglib / 17300165647

28 Aug 2025 03:14PM UTC coverage: 60.049% (+0.3%) from 59.781%
17300165647

Pull #210

github

web-flow
Merge f6109d03a into 18d34db1e
Pull Request #210: New debug info

377 of 593 new or added lines in 37 files covered. (63.58%)

15 existing lines in 8 files now uncovered.

9588 of 15967 relevant lines covered (60.05%)

114.92 hits per line

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

74.14
/src/data_flow/library_nodes/math/ml/maxpool.cpp
1
#include "sdfg/data_flow/library_nodes/math/ml/maxpool.h"
2

3
#include "sdfg/analysis/analysis.h"
4
#include "sdfg/analysis/scope_analysis.h"
5
#include "sdfg/builder/structured_sdfg_builder.h"
6

7
namespace sdfg {
8
namespace math {
9
namespace ml {
10

11
/*************** Constructor ***************/
12
MaxPoolNode::MaxPoolNode(
1✔
13
    size_t element_id,
14
    const DebugInfoRegion &debug_info,
15
    const graph::Vertex vertex,
16
    data_flow::DataFlowGraph &parent,
17
    std::vector<size_t> kernel_shape,
18
    std::vector<size_t> pads,
19
    std::vector<size_t> strides
20
)
21
    : MathNode(
1✔
22
          element_id, debug_info, vertex, parent, LibraryNodeType_MaxPool, {"Y"}, {"X"}, data_flow::ImplementationType_NONE
1✔
23
      ),
24
      kernel_shape_(std::move(kernel_shape)), pads_(std::move(pads)), strides_(std::move(strides)) {}
1✔
25

26
/*************** Accessors ***************/
27
std::vector<size_t> MaxPoolNode::kernel_shape() const { return kernel_shape_; }
×
28
std::vector<size_t> MaxPoolNode::pads() const { return pads_; }
×
29
std::vector<size_t> MaxPoolNode::strides() const { return strides_; }
×
30

31
void MaxPoolNode::validate(const Function &) const { /* TODO */ }
×
32

33
/*************** Expand ***************/
34
bool MaxPoolNode::expand(builder::StructuredSDFGBuilder &builder, analysis::AnalysisManager &analysis_manager) {
1✔
35
    auto &dataflow = this->get_parent();
1✔
36
    auto &block = static_cast<structured_control_flow::Block &>(*dataflow.get_parent());
1✔
37

38
    auto &scope_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
1✔
39
    auto &parent = static_cast<structured_control_flow::Sequence &>(*scope_analysis.parent_scope(&block));
1✔
40

41
    // Locate edges
42
    const data_flow::Memlet *iedge_X = nullptr;
1✔
43
    const data_flow::Memlet *oedge_Y = nullptr;
1✔
44
    for (const auto &edge : dataflow.in_edges(*this)) {
2✔
45
        if (edge.dst_conn() == "X") {
1✔
46
            iedge_X = &edge;
1✔
47
        }
1✔
48
    }
49
    for (const auto &edge : dataflow.out_edges(*this)) {
2✔
50
        if (edge.src_conn() == "Y") {
1✔
51
            oedge_Y = &edge;
1✔
52
        }
1✔
53
    }
54
    if (!iedge_X || !oedge_Y) return false;
1✔
55

56
    std::string X_name = static_cast<const data_flow::AccessNode &>(iedge_X->src()).data();
1✔
57
    std::string Y_name = static_cast<const data_flow::AccessNode &>(oedge_Y->dst()).data();
1✔
58

59
    // Create new sequence before
60
    auto &new_sequence = builder.add_sequence_before(parent, block, block.debug_info()).first;
1✔
61
    structured_control_flow::Sequence *last_scope = &new_sequence;
1✔
62

63
    // Create maps over output subset dims (parallel dims)
64
    const auto &begin_Y = oedge_Y->begin_subset();
1✔
65
    const auto &end_Y = oedge_Y->end_subset();
1✔
66
    data_flow::Subset out_subset;
1✔
67
    std::vector<symbolic::Expression> out_syms;
1✔
68
    structured_control_flow::Map *last_map = nullptr;
1✔
69
    for (size_t d = 0; d < begin_Y.size(); ++d) {
5✔
70
        std::string indvar_str = builder.find_new_name("_i");
4✔
71
        builder.add_container(indvar_str, types::Scalar(types::PrimitiveType::UInt64));
4✔
72
        auto indvar = symbolic::symbol(indvar_str);
4✔
73
        auto init = begin_Y[d];
4✔
74
        auto update = symbolic::add(indvar, symbolic::one());
4✔
75
        auto cond = symbolic::Lt(indvar, symbolic::add(end_Y[d], symbolic::one()));
4✔
76
        last_map = &builder.add_map(
4✔
77
            *last_scope,
4✔
78
            indvar,
79
            cond,
80
            init,
81
            update,
82
            structured_control_flow::ScheduleType_Sequential,
83
            {},
4✔
84
            block.debug_info()
4✔
85
        );
86
        last_scope = &last_map->root();
4✔
87
        out_subset.push_back(indvar);
4✔
88
        out_syms.push_back(indvar);
4✔
89
    }
4✔
90

91
    // Kernel reduction loops
92
    structured_control_flow::For *last_for = nullptr;
1✔
93
    std::vector<symbolic::Expression> kernel_syms;
1✔
94
    for (size_t d = 0; d < kernel_shape_.size(); ++d) {
3✔
95
        std::string indvar_str = builder.find_new_name("_k");
2✔
96
        builder.add_container(indvar_str, types::Scalar(types::PrimitiveType::UInt64));
2✔
97
        auto indvar = symbolic::symbol(indvar_str);
2✔
98
        auto init = symbolic::integer(0);
2✔
99
        auto update = symbolic::add(indvar, symbolic::one());
2✔
100
        auto cond = symbolic::Lt(indvar, symbolic::integer(static_cast<int64_t>(kernel_shape_[d])));
2✔
101
        last_for = &builder.add_for(*last_scope, indvar, cond, init, update, {}, block.debug_info());
2✔
102
        last_scope = &last_for->root();
2✔
103
        kernel_syms.push_back(indvar);
2✔
104
    }
2✔
105

106
    // Build subsets
107
    const auto &begin_X = iedge_X->begin_subset();
1✔
108
    // infer: X dims N,C,H,W => assume same dims as Y except spatial dims with stride/pad
109

110
    auto int_expr = [](size_t v) { return symbolic::integer(static_cast<int64_t>(v)); };
5✔
111
    auto get_stride = [&](size_t idx) -> symbolic::Expression {
3✔
112
        return idx < strides_.size() ? int_expr(strides_[idx]) : symbolic::one();
2✔
113
    };
114
    auto get_pad = [&](size_t idx) -> symbolic::Expression {
3✔
115
        return idx < pads_.size() ? int_expr(pads_[idx]) : symbolic::zero();
2✔
116
    };
117

118
    // Create innermost block
119
    auto &code_block = builder.add_block(*last_scope, {}, block.debug_info());
1✔
120

121
    // Access nodes
122
    const DebugInfoRegion dbg = block.debug_info();
1✔
123
    auto &X_acc = builder.add_access(code_block, X_name, dbg);
1✔
124
    auto &Y_acc_in = builder.add_access(code_block, Y_name, dbg);
1✔
125
    auto &Y_acc_out = builder.add_access(code_block, Y_name, dbg);
1✔
126

127
    // Build X subset using output coords * stride - pad + kernel_idx
128
    data_flow::Subset subset_X;
1✔
129
    // Assume dims: N, C, spatial...
130
    subset_X.push_back(out_syms[0]); // N
1✔
131
    subset_X.push_back(out_syms[1]); // C
1✔
132
    for (size_t d = 0; d < kernel_syms.size(); ++d) {
3✔
133
        auto expr =
134
            symbolic::sub(symbolic::add(symbolic::mul(get_stride(d), out_syms[2 + d]), kernel_syms[d]), get_pad(d));
2✔
135
        subset_X.push_back(expr);
2✔
136
    }
2✔
137

138
    // Y subset is just out_subset
139
    data_flow::Subset subset_Y = out_subset;
1✔
140

141
    // Tasklet max
142
    auto &tasklet = builder.add_tasklet(code_block, data_flow::TaskletCode::max, "_out", {"_in1", "_in2"}, dbg);
1✔
143

144
    builder.add_computational_memlet(code_block, Y_acc_in, tasklet, "_in1", subset_Y, oedge_Y->base_type(), dbg);
1✔
145
    builder.add_computational_memlet(code_block, X_acc, tasklet, "_in2", subset_X, iedge_X->base_type(), dbg);
1✔
146
    builder.add_computational_memlet(code_block, tasklet, "_out", Y_acc_out, subset_Y, oedge_Y->base_type(), dbg);
1✔
147

148
    // Cleanup old block
149
    builder.remove_memlet(block, *iedge_X);
1✔
150
    builder.remove_memlet(block, *oedge_Y);
1✔
151
    builder.remove_node(block, *this);
1✔
152
    builder.remove_child(parent, block);
1✔
153

154
    return true;
1✔
155
}
1✔
156

157
/*************** Clone ***************/
158
std::unique_ptr<data_flow::DataFlowNode> MaxPoolNode::
159
    clone(size_t element_id, const graph::Vertex vertex, data_flow::DataFlowGraph &parent) const {
×
160
    return std::unique_ptr<data_flow::DataFlowNode>(new MaxPoolNode(
×
161
        element_id, this->debug_info(), vertex, parent, this->kernel_shape_, this->pads_, this->strides_
×
162
    ));
163
}
×
164

165
/*************** Serializer ***************/
166
nlohmann::json MaxPoolNodeSerializer::serialize(const data_flow::LibraryNode &library_node) {
×
167
    const MaxPoolNode &node = static_cast<const MaxPoolNode &>(library_node);
×
168
    nlohmann::json j;
×
169
    j["code"] = node.code().value();
×
170
    j["outputs"] = node.outputs();
×
171
    j["inputs"] = node.inputs();
×
172
    j["kernel_shape"] = node.kernel_shape();
×
173
    j["pads"] = node.pads();
×
174
    j["strides"] = node.strides();
×
175
    return j;
×
176
}
×
177

178
data_flow::LibraryNode &MaxPoolNodeSerializer::deserialize(
×
179
    const nlohmann::json &j, builder::StructuredSDFGBuilder &builder, structured_control_flow::Block &parent
180
) {
181
    auto code = j["code"].get<std::string>();
×
182
    if (code != LibraryNodeType_MaxPool.value()) {
×
183
        throw std::runtime_error("Invalid library node code");
×
184
    }
185
    sdfg::serializer::JSONSerializer serializer;
×
NEW
186
    DebugInfoRegion debug_info = serializer.json_to_debug_info_region(j["debug_info_region"], builder.debug_info());
×
187

188
    auto kernel_shape = j["kernel_shape"].get<std::vector<size_t>>();
×
189
    auto pads = j["pads"].get<std::vector<size_t>>();
×
190
    auto strides = j["strides"].get<std::vector<size_t>>();
×
191

192
    return builder.add_library_node<MaxPoolNode>(parent, debug_info, kernel_shape, pads, strides);
×
193
}
×
194

195
} // namespace ml
196
} // namespace math
197
} // 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