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

daisytuner / docc / 24348757857

13 Apr 2026 02:25PM UTC coverage: 64.469% (+0.09%) from 64.382%
24348757857

push

github

web-flow
Merge pull request #676 from daisytuner/ellide-host-mem-mgmt

Ellides H2D copies in case the host data was freshly allocated and not yet initialized before the offload transfer. In that case, offloaded Malloc is enough.

(will leave the host malloc itself in the graph, as that is a task for DDE to remove)

104 of 125 new or added lines in 5 files covered. (83.2%)

1 existing line in 1 file now uncovered.

30553 of 47392 relevant lines covered (64.47%)

584.02 hits per line

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

47.62
/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(
85✔
32
          element_id, debug_info, vertex, parent, code, outputs, inputs, true, data_flow::ImplementationType_NONE
85✔
33
      ),
85✔
34
      transfer_direction_(transfer_direction), buffer_lifecycle_(buffer_lifecycle), size_(std::move(size)) {}
85✔
35

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

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

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

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

44
symbolic::SymbolSet DataOffloadingNode::symbols() const {
32✔
45
    if (this->size().is_null()) {
32✔
46
        return {};
×
47
    } else {
32✔
48
        return symbolic::atoms(this->size());
32✔
49
    }
32✔
50
}
32✔
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::redundant_with(const DataOffloadingNode& other) const {
2✔
93
    if (code() != other.code()) {
2✔
94
        return false;
×
95
    }
×
96
    if ((static_cast<int8_t>(transfer_direction()) + static_cast<int8_t>(other.transfer_direction())) != 0) {
2✔
97
        return false; // not the inverse
×
98
    }
×
99
    if ((static_cast<int8_t>(buffer_lifecycle()) + static_cast<int8_t>(other.buffer_lifecycle())) != 0) {
2✔
100
        return false;
×
101
    }
×
102

103
    if (!symbolic::null_safe_eq(size(), other.size())) {
2✔
104
        return false;
×
105
    }
×
106

107
    return true; // add more checks in sub-classes
2✔
108
}
2✔
109

110
bool DataOffloadingNode::equal_with(const DataOffloadingNode& other) const {
8✔
111
    if (code() != other.code()) {
8✔
112
        return false;
×
113
    }
×
114
    if (this->transfer_direction() != other.transfer_direction()) {
8✔
115
        return false;
×
116
    }
×
117
    if (this->buffer_lifecycle() != other.buffer_lifecycle()) {
8✔
118
        return false;
×
119
    }
×
120

121
    if (!symbolic::null_safe_eq(size(), other.size())) {
8✔
122
        return false;
×
123
    }
×
124

125
    return true; // add more checks in sub-classes
8✔
126
}
8✔
127

128
bool DataOffloadingNode::is_d2h() const { return is_D2H(this->transfer_direction()); }
94✔
129

130
bool DataOffloadingNode::is_h2d() const { return is_H2D(this->transfer_direction()); }
83✔
131

132
bool DataOffloadingNode::has_transfer() const { return this->is_d2h() || this->is_h2d(); }
13✔
133

134
bool DataOffloadingNode::is_free() const { return is_FREE(this->buffer_lifecycle()); }
32✔
135

136
bool DataOffloadingNode::is_alloc() const { return is_ALLOC(this->buffer_lifecycle()); }
36✔
137

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

148
void DataOffloadingNode::remove_free() {
1✔
149
    if (this->is_free()) {
1✔
150
        if (!this->has_transfer()) {
1✔
151
            throw InvalidSDFGException("DataOffloadingNode: Tried removing free but no data transfer direction present"
×
152
            );
×
153
        }
×
154
        this->buffer_lifecycle_ = BufferLifecycle::NO_CHANGE;
1✔
155
    }
1✔
156
}
1✔
157

158
} // namespace offloading
159
} // 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