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

daisytuner / docc / 25194337763

30 Apr 2026 11:25PM UTC coverage: 64.283% (+0.009%) from 64.274%
25194337763

push

github

web-flow
Merge pull request #693 from daisytuner/local-storage-generalization

unifies local storage api

277 of 358 new or added lines in 5 files covered. (77.37%)

16 existing lines in 6 files now uncovered.

30899 of 48067 relevant lines covered (64.28%)

684.61 hits per line

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

80.0
/opt/src/transformations/offloading/gpu_tiling.cpp
1
#include "sdfg/transformations/offloading/gpu_tiling.h"
2
#include <set>
3

4
#include "sdfg/analysis/analysis.h"
5
#include "sdfg/analysis/type_analysis.h"
6
#include "sdfg/analysis/users.h"
7
#include "sdfg/builder/structured_sdfg_builder.h"
8
#include "sdfg/data_flow/access_node.h"
9
#include "sdfg/passes/offloading/sync_condition_propagation.h"
10
#include "sdfg/structured_control_flow/for.h"
11
#include "sdfg/structured_control_flow/map.h"
12
#include "sdfg/structured_control_flow/structured_loop.h"
13
#include "sdfg/structured_control_flow/while.h"
14
#include "sdfg/transformations/loop_tiling.h"
15
#include "sdfg/transformations/offloading/kernel_local_storage.h"
16
#include "sdfg/transformations/out_local_storage.h"
17

18

19
namespace sdfg {
20
namespace transformations {
21

22
GPUTiling::GPUTiling(structured_control_flow::StructuredLoop& loop, size_t size) : loop_(loop), size_(size) {}
5✔
23

24
std::string GPUTiling::name() const { return "GPUTiling"; }
6✔
25

26
bool GPUTiling::can_be_applied(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
1✔
27
    auto sdfg = builder.subject().clone();
1✔
28
    builder::StructuredSDFGBuilder builder_local(sdfg);
1✔
29
    analysis::AnalysisManager analysis_manager_local(builder_local.subject());
1✔
30

31
    auto test_loop = builder_local.find_element_by_id(loop_.element_id());
1✔
32

33
    auto& loop_local = static_cast<structured_control_flow::StructuredLoop&>(*test_loop);
1✔
34

35
    LoopTiling tiling(loop_local, size_);
1✔
36

37
    if (!tiling.can_be_applied(builder_local, analysis_manager_local)) {
1✔
38
        return false;
×
39
    }
×
40

41
    tiling.apply(builder_local, analysis_manager_local);
1✔
42

43
    auto& users = analysis_manager_local.get<analysis::Users>();
1✔
44

45
    auto inner_loop = tiling.inner_loop();
1✔
46
    auto outer_loop = tiling.outer_loop();
1✔
47

48
    analysis::UsersView users_view(users, inner_loop->root());
1✔
49

50
    std::set<data_flow::AccessNode*> read_accesses;
1✔
51
    std::set<std::string> read_container_names;
1✔
52

53
    for (auto read : users_view.reads()) {
11✔
54
        if (!dynamic_cast<data_flow::AccessNode*>(read->element())) {
11✔
55
            continue;
8✔
56
        }
8✔
57
        if (read_container_names.find(read->container()) != read_container_names.end()) {
3✔
58
            continue;
×
59
        }
×
60
        auto access_node = dynamic_cast<data_flow::AccessNode*>(read->element());
3✔
61
        read_container_names.insert(read->container());
3✔
62
        read_accesses.insert(std::move(access_node));
3✔
63
    }
3✔
64

65
    if (read_accesses.empty()) {
1✔
66
        return false;
×
67
    }
×
68

69
    for (auto& access : read_accesses) {
3✔
70
        KernelLocalStorage kls(*inner_loop, outer_loop->indvar(), *access);
3✔
71
        if (kls.can_be_applied(builder_local, analysis_manager_local)) {
3✔
72
            target_containers_.insert(access->data());
2✔
73
        }
2✔
74
    }
3✔
75
    if (target_containers_.empty()) {
1✔
76
        return false;
×
77
    }
×
78

79
    return true;
1✔
80
}
1✔
81

82
void GPUTiling::apply(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
1✔
83
    LoopTiling tiling(loop_, size_);
1✔
84
    tiling.apply(builder, analysis_manager);
1✔
85
    auto inner_loop = tiling.inner_loop();
1✔
86
    auto outer_loop = tiling.outer_loop();
1✔
87

88
    analysis::UsersView users_view(analysis_manager.get<analysis::Users>(), inner_loop->root());
1✔
89

90
    for (const auto& container_name : target_containers_) {
2✔
91
        auto& users = analysis_manager.get<analysis::Users>();
2✔
92
        analysis::UsersView users_view(users, inner_loop->root());
2✔
93

94
        auto reads = users_view.reads(container_name);
2✔
95
        if (reads.empty()) continue;
2✔
96

97
        auto* access = dynamic_cast<data_flow::AccessNode*>(reads.front()->element());
2✔
98
        if (!access) continue;
2✔
99

100
        KernelLocalStorage kls(*inner_loop, outer_loop->indvar(), *access);
2✔
101
        if (kls.can_be_applied(builder, analysis_manager)) {
2✔
102
            kls.apply(builder, analysis_manager);
2✔
103
        }
2✔
104
    }
2✔
105

106
    passes::SyncConditionPropagation sync_condition_propagation;
1✔
107
    sync_condition_propagation.run_pass(builder, analysis_manager);
1✔
108

109
    applied_ = true;
1✔
110
    inner_loop_ = inner_loop;
1✔
111
    outer_loop_ = outer_loop;
1✔
112

113
    auto& users = analysis_manager.get<analysis::Users>();
1✔
114
    analysis::UsersView users_view_inner_loop(users, inner_loop->root());
1✔
115

116
    analysis::TypeAnalysis type_analysis(builder.subject(), inner_loop, analysis_manager);
1✔
117
    for (const auto& write : users_view_inner_loop.writes()) {
1✔
118
        if (!dynamic_cast<data_flow::AccessNode*>(write->element())) {
1✔
119
            continue;
×
120
        }
×
121
        if (type_analysis.get_outer_type(write->container())->type_id() == types::TypeID::Scalar ||
1✔
122
            type_analysis.get_outer_type(write->container())->type_id() == types::TypeID::Structure) {
1✔
123
            continue;
×
124
        }
×
125
        auto access_node = dynamic_cast<data_flow::AccessNode*>(write->element());
1✔
126
        OutLocalStorage ols(*inner_loop, *access_node);
1✔
127
        if (ols.can_be_applied(builder, analysis_manager)) {
1✔
UNCOV
128
            ols.apply(builder, analysis_manager);
×
UNCOV
129
        }
×
130
    }
1✔
131
}
1✔
132

133
void GPUTiling::to_json(nlohmann::json& j) const {
2✔
134
    j["transformation_type"] = this->name();
2✔
135

136
    // Determine loop type consistent with GNN feature extractor labelling.
137
    std::string loop_type;
2✔
138
    if (dynamic_cast<structured_control_flow::For*>(&loop_)) {
2✔
139
        loop_type = "for";
1✔
140
    } else if (dynamic_cast<structured_control_flow::While*>(&loop_)) {
1✔
141
        loop_type = "while";
×
142
    } else if (dynamic_cast<structured_control_flow::Map*>(&loop_)) {
1✔
143
        loop_type = "map";
1✔
144
    } else {
1✔
145
        loop_type = "unknown";
×
146
    }
×
147

148
    // Embedding-compatible description used by EmbeddingRecorder/EmbeddingReplayer.
149
    j["subgraph"] = {{"0", {{"element_id", this->loop_.element_id()}, {"type", loop_type}}}};
2✔
150
    j["parameters"] = {{"size", this->size_}};
2✔
151

152
    // Legacy fields for backward compatibility.
153
    j["loop_element_id"] = this->loop_.element_id();
2✔
154
    j["size"] = this->size_;
2✔
155
}
2✔
156

157
GPUTiling GPUTiling::from_json(builder::StructuredSDFGBuilder& builder, const nlohmann::json& j) {
2✔
158
    // Prefer embedding-compatible representation, but support legacy layout.
159
    size_t loop_id;
2✔
160
    if (j.contains("subgraph")) {
2✔
161
        const auto& node_desc = j.at("subgraph").at("0");
2✔
162
        loop_id = node_desc.at("element_id").get<size_t>();
2✔
163
    } else {
2✔
164
        loop_id = j.at("loop_element_id").get<size_t>();
×
165
    }
×
166

167
    auto element = builder.find_element_by_id(loop_id);
2✔
168
    if (!element) {
2✔
169
        throw InvalidTransformationDescriptionException("Element with ID " + std::to_string(loop_id) + " not found.");
×
170
    }
×
171
    auto loop = dynamic_cast<structured_control_flow::StructuredLoop*>(element);
2✔
172

173
    size_t size;
2✔
174
    if (j.contains("parameters") && j.at("parameters").contains("size")) {
2✔
175
        size = j.at("parameters").at("size").get<size_t>();
2✔
176
    } else {
2✔
177
        size = j.at("size").get<size_t>();
×
178
    }
×
179

180
    return GPUTiling(*loop, size);
2✔
181
}
2✔
182

183
structured_control_flow::StructuredLoop* GPUTiling::inner_loop() {
1✔
184
    if (!applied_) {
1✔
185
        throw InvalidSDFGException("Accessing tiled loop before their creation.");
×
186
    }
×
187

188
    return inner_loop_;
1✔
189
}
1✔
190

191
structured_control_flow::StructuredLoop* GPUTiling::outer_loop() {
1✔
192
    if (!applied_) {
1✔
193
        throw InvalidSDFGException("Accessing tiled loop before their creation.");
×
194
    }
×
195

196
    return outer_loop_;
1✔
197
}
1✔
198

199
} // namespace transformations
200
} // 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