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

daisytuner / docc / 24474374464

15 Apr 2026 07:36PM UTC coverage: 64.633%. First build
24474374464

push

github

web-flow
Merge pull request #682 from daisytuner/read-only-offloads-reuse

Read only offloads reuse

125 of 138 new or added lines in 5 files covered. (90.58%)

30803 of 47658 relevant lines covered (64.63%)

582.23 hits per line

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

50.72
/sdfg/src/offloading/data_offloading_node.cpp
1
#include "sdfg/targets/offloading/data_offloading_node.h"
2

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

7
#include "sdfg/data_flow/data_flow_graph.h"
8
#include "sdfg/data_flow/library_node.h"
9
#include "sdfg/element.h"
10
#include "sdfg/exceptions.h"
11
#include "sdfg/graph/graph.h"
12
#include "sdfg/symbolic/symbolic.h"
13

14
namespace sdfg {
15
namespace offloading {
16

17
constexpr bool dump_offload_node_ids = false;
18

19
DataOffloadingNode::DataOffloadingNode(
20
    size_t element_id,
21
    const DebugInfo& debug_info,
22
    const graph::Vertex vertex,
23
    data_flow::DataFlowGraph& parent,
24
    const data_flow::LibraryNodeCode code,
25
    const std::vector<std::string>& outputs,
26
    const std::vector<std::string>& inputs,
27
    DataTransferDirection transfer_direction,
28
    BufferLifecycle buffer_lifecycle,
29
    symbolic::Expression size
30
)
31
    : data_flow::LibraryNode(
101✔
32
          element_id, debug_info, vertex, parent, code, outputs, inputs, true, data_flow::ImplementationType_NONE
101✔
33
      ),
101✔
34
      transfer_direction_(transfer_direction), buffer_lifecycle_(buffer_lifecycle), size_(std::move(size)) {}
101✔
35

36
DataTransferDirection DataOffloadingNode::transfer_direction() const { return this->transfer_direction_; }
298✔
37

38
BufferLifecycle DataOffloadingNode::buffer_lifecycle() const { return this->buffer_lifecycle_; }
153✔
39

40
const symbolic::Expression DataOffloadingNode::size() const { return this->size_; }
231✔
41

42
const symbolic::Expression DataOffloadingNode::alloc_size() const { return this->size(); }
×
43

44
symbolic::SymbolSet DataOffloadingNode::symbols() const {
81✔
45
    if (this->size().is_null()) {
81✔
46
        return {};
×
47
    } else {
81✔
48
        return symbolic::atoms(this->size());
81✔
49
    }
81✔
50
}
81✔
51

52
void DataOffloadingNode::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
15✔
53
    if (!this->size_.is_null()) {
15✔
54
        this->size_ = symbolic::subs(this->size_, old_expression, new_expression);
15✔
55
    }
15✔
56
}
15✔
57

58
std::string DataOffloadingNode::toStr() const {
×
59
    std::string direction, lifecycle;
×
60
    switch (this->transfer_direction()) {
×
61
        case DataTransferDirection::D2H:
×
62
            direction = " D2H";
×
63
            break;
×
64
        case DataTransferDirection::H2D:
×
65
            direction = " H2D";
×
66
            break;
×
67
        default:
×
68
            direction = " NONE";
×
69
            break;
×
70
    }
×
71
    switch (this->buffer_lifecycle()) {
×
72
        case BufferLifecycle::FREE:
×
73
            lifecycle = " FREE";
×
74
            break;
×
75
        case BufferLifecycle::ALLOC:
×
76
            lifecycle = " ALLOC";
×
77
            break;
×
78
        default:
×
79
            lifecycle = " NO_CHANGE";
×
80
            break;
×
81
    }
×
82
    std::string res = std::string(this->code_.value());
×
83
    if (dump_offload_node_ids) {
×
84
        res += " #" + std::to_string(element_id_);
×
85
    }
×
86
    res += direction + lifecycle;
×
87
    return res;
×
88
}
×
89

90
symbolic::Expression DataOffloadingNode::flop() const { return symbolic::zero(); }
×
91

92
bool DataOffloadingNode::is_compatible_with(const DataOffloadingNode& other) const {
22✔
93
    if (code() != other.code()) {
22✔
94
        return false;
×
95
    }
×
96
    if (!symbolic::null_safe_eq(size(), other.size())) {
22✔
NEW
97
        return false;
×
NEW
98
    }
×
99
    return true;
22✔
100
}
22✔
101

NEW
102
bool DataOffloadingNode::redundant_with(const DataOffloadingNode& other) const {
×
NEW
103
    if (!is_compatible_with(other)) {
×
NEW
104
        return false;
×
NEW
105
    }
×
106
    if ((static_cast<int8_t>(transfer_direction()) + static_cast<int8_t>(other.transfer_direction())) != 0) {
×
107
        return false; // not the inverse
×
108
    }
×
109
    if ((static_cast<int8_t>(buffer_lifecycle()) + static_cast<int8_t>(other.buffer_lifecycle())) != 0) {
×
110
        return false;
×
111
    }
×
112

113
    return true; // add more checks in sub-classes
×
114
}
×
115

116
bool DataOffloadingNode::equal_with(const DataOffloadingNode& other) const {
8✔
117
    if (!is_compatible_with(other)) {
8✔
118
        return false;
×
119
    }
×
120
    if (this->transfer_direction() != other.transfer_direction()) {
8✔
121
        return false;
×
122
    }
×
123
    if (this->buffer_lifecycle() != other.buffer_lifecycle()) {
8✔
124
        return false;
×
125
    }
×
126

127
    return true; // add more checks in sub-classes
8✔
128
}
8✔
129

130
bool DataOffloadingNode::is_d2h() const { return is_D2H(this->transfer_direction()); }
120✔
131

132
bool DataOffloadingNode::is_h2d() const { return is_H2D(this->transfer_direction()); }
108✔
133

134
bool DataOffloadingNode::has_transfer() const { return this->is_d2h() || this->is_h2d(); }
15✔
135

136
bool DataOffloadingNode::is_free() const { return is_FREE(this->buffer_lifecycle()); }
42✔
137

138
bool DataOffloadingNode::is_alloc() const { return is_ALLOC(this->buffer_lifecycle()); }
48✔
139

140
void DataOffloadingNode::remove_h2d() {
3✔
141
    if (this->is_h2d()) {
3✔
142
        if (!this->is_alloc()) {
3✔
143
            throw InvalidSDFGException("DataOffloadingNode: Tried removing h2d but node has no other purpose");
×
144
        }
×
145
        this->transfer_direction_ = DataTransferDirection::NONE;
3✔
146
        this->inputs_.erase(this->inputs_.begin()); // Standard nodes only have one, others need to override
3✔
147
    }
3✔
148
}
3✔
149

150
data_flow::PointerAccessType DataOffloadingNode::pointer_access_type(int input_idx) const {
2✔
151
    if (is_h2d() && input_idx == 0) {
2✔
152
        return data_flow::PointerReadOnly(size_, true);
2✔
153
    } else {
2✔
154
        return LibraryNode::pointer_access_type(input_idx);
×
155
    }
×
156
}
2✔
157

158
void DataOffloadingNode::remove_free() {
3✔
159
    if (this->is_free()) {
3✔
160
        if (!this->has_transfer()) {
3✔
161
            throw InvalidSDFGException("DataOffloadingNode: Tried removing free but no data transfer direction present"
×
162
            );
×
163
        }
×
164
        this->buffer_lifecycle_ = BufferLifecycle::NO_CHANGE;
3✔
165
    }
3✔
166
}
3✔
167

168
data_flow::EdgeRemoveOption DataOffloadingNode::
169
    can_remove_out_edge(const data_flow::DataFlowGraph& graph, const data_flow::Memlet* memlet) const {
2✔
170
    if (graph.out_edges_for_connector(*this, memlet->src_conn()).size() > 1) {
2✔
171
        return data_flow::EdgeRemoveOption::Trivially;
×
172
    } else if (transfer_direction_ != DataTransferDirection::NONE && outputs_.size() == 1 &&
2✔
173
               memlet->src_conn() == outputs_.at(0)) {
2✔
174
        // the node represents a transfer, whose output is dead.
175
        if (buffer_lifecycle_ != BufferLifecycle::NO_CHANGE) {
2✔
176
            // the node still has remaining purpose without the transfer
177
            return data_flow::EdgeRemoveOption::RequiresUpdate;
1✔
178
        } else {
1✔
179
            // the node in its entirety is dead if it the transfer is not needed
180
            return data_flow::EdgeRemoveOption::RemoveNodeAfter;
1✔
181
        }
1✔
182
    } else {
2✔
183
        return data_flow::EdgeRemoveOption::NotRemovable;
×
184
    }
×
185
}
2✔
186

187
bool DataOffloadingNode::update_edge_removed(const std::string& out_conn) {
1✔
188
    if (transfer_direction_ != DataTransferDirection::NONE && outputs_.size() == 1 && out_conn == outputs_.at(0)) {
1✔
189
        transfer_direction_ = DataTransferDirection::NONE;
1✔
190
        outputs_.erase(outputs_.begin());
1✔
191
        return true;
1✔
192
    } else {
1✔
193
        return false;
×
194
    }
×
195
}
1✔
196

197
} // namespace offloading
198
} // 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