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

daisytuner / sdfglib / 15852980623

24 Jun 2025 02:16PM UTC coverage: 64.412% (+0.3%) from 64.145%
15852980623

push

github

web-flow
Merge pull request #72 from daisytuner/capture-instrumentation

Capture instrumentation

363 of 446 new or added lines in 19 files covered. (81.39%)

100 existing lines in 5 files now uncovered.

8389 of 13024 relevant lines covered (64.41%)

116.79 hits per line

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

61.64
/src/codegen/code_generators/c_code_generator.cpp
1
#include "sdfg/codegen/code_generators/c_code_generator.h"
2

3
#include "sdfg/analysis/analysis.h"
4
#include "sdfg/analysis/users.h"
5
#include "sdfg/codegen/dispatchers/node_dispatcher_registry.h"
6
#include "sdfg/codegen/instrumentation/capture_var_plan.h"
7
#include "sdfg/codegen/instrumentation/instrumentation.h"
8
#include "sdfg/codegen/instrumentation/outermost_loops_instrumentation.h"
9

10
namespace sdfg {
11
namespace codegen {
12

13
CCodeGenerator::CCodeGenerator(StructuredSDFG& sdfg,
18✔
14
                               InstrumentationStrategy instrumentation_strategy, bool capture_args_results)
15
    : CodeGenerator(sdfg, instrumentation_strategy, capture_args_results) {
9✔
16
    if (sdfg.type() != FunctionType_CPU) {
9✔
17
        throw std::runtime_error("CCodeGenerator can only be used for CPU SDFGs");
×
18
    }
19
};
9✔
20

21
bool CCodeGenerator::generate() {
4✔
22
    this->dispatch_includes();
4✔
23
    this->dispatch_structures();
4✔
24
    this->dispatch_globals();
4✔
25
    this->dispatch_schedule();
4✔
26
    return true;
4✔
27
};
28

29
std::string CCodeGenerator::function_definition() {
1✔
30
    /********** Arglist **********/
31
    std::vector<std::string> args;
1✔
32
    for (auto& container : sdfg_.arguments()) {
1✔
33
        args.push_back(language_extension_.declaration(container, sdfg_.type(container)));
×
34
    }
35
    std::stringstream arglist;
1✔
36
    arglist << sdfg::helpers::join(args, ", ");
1✔
37

38
    return "extern void " + sdfg_.name() + "(" + arglist.str() + ")";
1✔
39
};
1✔
40

41
void CCodeGenerator::emit_capture_context_init(std::ostream& ofs_source) const {
1✔
42
    std::string name = sdfg_.name();
1✔
43

44
    ofs_source << "static void* __capture_ctx;" << std::endl;
1✔
45
    ofs_source << "static void __attribute__((constructor(1000))) __capture_ctx_init(void) {" << std::endl;
1✔
46
    ofs_source << "\t__capture_ctx = __daisy_capture_init(\"" << name << "\");" << std::endl;
1✔
47
    ofs_source << "}" << std::endl;
1✔
48
    ofs_source << std::endl;
1✔
49
}
1✔
50

51
void CCodeGenerator::emit_arg_captures(std::ostream& ofs_source, const std::vector<CaptureVarPlan>& plan, bool after) {
2✔
52
    std::string name = sdfg_.name();
2✔
53

54
    if (!after) {
2✔
55
        ofs_source << "const bool __daisy_cap_en = __daisy_capture_enter(__capture_ctx);" << std::endl;
1✔
56
    }
1✔
57

58
    const auto& args = sdfg_.arguments();
2✔
59
    const auto& exts = sdfg_.externals();
2✔
60

61
    ofs_source << "if (__daisy_cap_en) {" << std::endl;
2✔
62

63
    auto afterBoolStr = after ? "true" : "false";
2✔
64

65
    for (auto& varPlan : plan) {
9✔
66
        auto argIdx = varPlan.arg_idx;
7✔
67
        auto argName = varPlan.is_external ? exts[argIdx-args.size()] : args[argIdx];
7✔
68

69
        if ((!after && varPlan.capture_input) || (after && varPlan.capture_output)) {
7✔
70
            switch (varPlan.type) {
5✔
71
                case CaptureVarType::CapRaw: {
72
                    ofs_source << "\t__daisy_capture_raw(" <<
2✔
73
                        "__capture_ctx, " <<
2✔
74
                        argIdx << ", " <<
2✔
75
                        "&" << argName << ", " <<
2✔
76
                        "sizeof(" << argName << "), " <<
2✔
77
                        varPlan.inner_type << ", " <<
2✔
78
                        afterBoolStr <<
2✔
79
                        ");" << std::endl;
2✔
80
                    break;
2✔
81
                }
82
                case CaptureVarType::Cap1D: {
83
                    ofs_source << "\t__daisy_capture_1d(" <<
2✔
84
                        "__capture_ctx, " <<
1✔
85
                        argIdx << ", " <<
1✔
86
                        argName << ", " <<
1✔
87
                        "sizeof(" << language_extension_.primitive_type(varPlan.inner_type) << "), " <<
1✔
88
                        varPlan.inner_type << ", " <<
2✔
89
                        language_extension_.expression(varPlan.dim1) << ", " <<
2✔
90
                        afterBoolStr <<
1✔
91
                        ");" << std::endl;
1✔
92
                    break;
1✔
93
                }
94
                case CaptureVarType::Cap2D: {
95
                    ofs_source << "\t__daisy_capture_2d(" <<
4✔
96
                        "__capture_ctx, " <<
2✔
97
                        argIdx << ", " <<
2✔
98
                        argName << ", " <<
2✔
99
                        "sizeof(" << language_extension_.primitive_type(varPlan.inner_type) <<"), " <<
2✔
100
                        varPlan.inner_type << ", " <<
4✔
101
                        language_extension_.expression(varPlan.dim1) << ", " <<
6✔
102
                        language_extension_.expression(varPlan.dim2) << ", " <<
4✔
103
                        afterBoolStr <<
2✔
104
                        ");" << std::endl;
2✔
105
                    break;
2✔
106
                }
107
                case CaptureVarType::Cap3D: {
NEW
108
                    ofs_source << "\t__daisy_capture_3d(" <<
×
NEW
109
                        "__capture_ctx, " <<
×
NEW
110
                        argIdx << ", " <<
×
NEW
111
                        argName << ", " <<
×
NEW
112
                        "sizeof(" << language_extension_.primitive_type(varPlan.inner_type) << "), " <<
×
NEW
113
                        varPlan.inner_type << ", " <<
×
NEW
114
                        language_extension_.expression(varPlan.dim1) << ", " <<
×
NEW
115
                        language_extension_.expression(varPlan.dim2) << ", " <<
×
NEW
116
                        language_extension_.expression(varPlan.dim3) << ", " <<
×
NEW
117
                        afterBoolStr <<
×
NEW
118
                        ");" << std::endl;
×
NEW
119
                    break;
×
120
                }
121
                default:
NEW
122
                    std::cerr << "Unknown capture type " << static_cast<int>(varPlan.type) << " for arg " << argIdx << " at " << (after? "result" : "input") << " time" << std::endl;
×
NEW
123
                    break;
×
124
            }
125
        }
5✔
126
    }
7✔
127

128
    if (after) {
2✔
129
        ofs_source << "\t__daisy_capture_end(__capture_ctx);" << std::endl;
1✔
130
    }
1✔
131

132
    ofs_source << "}" << std::endl;
2✔
133
};
2✔
134

UNCOV
135
bool CCodeGenerator::as_source(const std::filesystem::path& header_path,
×
136
                               const std::filesystem::path& source_path,
137
                               const std::filesystem::path& library_path) {
138
    std::ofstream ofs_header(header_path, std::ofstream::out);
×
139
    if (!ofs_header.is_open()) {
×
140
        return false;
×
141
    }
142

143
    std::ofstream ofs_source(source_path, std::ofstream::out);
×
144
    if (!ofs_source.is_open()) {
×
145
        return false;
×
146
    }
147

148
    std::ofstream ofs_library(library_path, std::ofstream::out);
×
149
    if (!ofs_library.is_open()) {
×
150
        return false;
×
151
    }
152

153
    ofs_header << "#pragma once" << std::endl;
×
154
    ofs_header << this->includes_stream_.str() << std::endl;
×
155
    ofs_header << this->classes_stream_.str() << std::endl;
×
156
    ofs_header.close();
×
157

158
    ofs_source << "#include \"" << header_path.filename().string() << "\"" << std::endl;
×
159
    ofs_source << this->globals_stream_.str() << std::endl;
×
160

NEW
161
    std::unique_ptr<std::vector<CaptureVarPlan>> capturePlan;
×
NEW
162
    if (capture_args_results_) {
×
NEW
163
        capturePlan = create_capture_plans();
×
NEW
164
        if (capturePlan) {
×
NEW
165
            this->emit_capture_context_init(ofs_source);
×
NEW
166
        } else {
×
NEW
167
            std::cerr << "Cannot capture all args for SDFG '" << sdfg_.name() << "'. Skpping capture instrumentation!" << std::endl;
×
168
        }
NEW
169
    }
×
170

171
    ofs_source << this->function_definition() << std::endl;
×
172
    ofs_source << "{" << std::endl;
×
173

174
    if (instrumentation_strategy_ != InstrumentationStrategy::NONE) {
×
175
        ofs_source << "__daisy_instrument_init();" << std::endl;
×
176
    }
×
177

NEW
178
    if (capturePlan) {
×
NEW
179
        this->emit_arg_captures(ofs_source, *capturePlan, false);
×
NEW
180
    }
×
181

UNCOV
182
    ofs_source << this->main_stream_.str() << std::endl;
×
183

NEW
184
    if (capturePlan) {
×
NEW
185
        this->emit_arg_captures(ofs_source, *capturePlan, true);
×
NEW
186
    }
×
187

188
    if (instrumentation_strategy_ != InstrumentationStrategy::NONE) {
×
189
        ofs_source << "__daisy_instrument_finalize();" << std::endl;
×
190
    }
×
191

192
    ofs_source << "}" << std::endl;
×
193
    ofs_source.close();
×
194

195
    auto library_content = this->library_stream_.str();
×
196
    if (library_content.empty()) {
×
197
        ofs_library.close();
×
198
        return true;
×
199
    }
200

201
    ofs_library << "#include \"" << header_path.filename().string() << "\"" << std::endl;
×
202
    ofs_library << std::endl;
×
203

204
    ofs_library << library_content << std::endl;
×
205
    ofs_library.close();
×
206

207
    return true;
×
208
};
×
209

210
void CCodeGenerator::dispatch_includes() {
4✔
211
    this->includes_stream_ << "#include <math.h>" << std::endl;
4✔
212
    this->includes_stream_ << "#include <stdbool.h>" << std::endl;
4✔
213
    this->includes_stream_ << "#include <stdlib.h>" << std::endl;
4✔
214
    if (this->instrumentation_strategy_ != InstrumentationStrategy::NONE)
4✔
215
        this->includes_stream_ << "#include <daisy_rtl.h>" << std::endl;
×
216

217
    this->includes_stream_ << "#define __daisy_min(a,b) ((a)<(b)?(a):(b))" << std::endl;
4✔
218
    this->includes_stream_ << "#define __daisy_max(a,b) ((a)>(b)?(a):(b))" << std::endl;
4✔
219
    this->includes_stream_ << "#define __daisy_fma(a,b,c) a * b + c" << std::endl;
4✔
220
};
4✔
221

222
void CCodeGenerator::dispatch_structures() {
4✔
223
    // Forward declarations
224
    for (auto& structure : sdfg_.structures()) {
7✔
225
        this->classes_stream_ << "typedef struct " << structure << " " << structure << ";"
3✔
226
                              << std::endl;
3✔
227
    }
228

229
    // Generate topology-sorted structure definitions
230
    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> structures_graph;
231
    typedef boost::graph_traits<structures_graph>::vertex_descriptor Vertex;
232
    std::vector<std::string> names;
4✔
233
    for (auto& structure : sdfg_.structures()) {
7✔
234
        names.push_back(structure);
3✔
235
    }
236
    structures_graph graph(names.size());
4✔
237

238
    for (auto& structure : names) {
7✔
239
        auto& definition = sdfg_.structure(structure);
3✔
240
        for (size_t i = 0; i < definition.num_members(); i++) {
6✔
241
            auto member_type = &definition.member_type(symbolic::integer(i));
3✔
242
            while (dynamic_cast<const types::Array*>(member_type)) {
3✔
243
                auto array_type = static_cast<const types::Array*>(member_type);
×
244
                member_type = &array_type->element_type();
×
245
            }
246

247
            if (auto member_structure = dynamic_cast<const sdfg::types::Structure*>(member_type)) {
3✔
248
                boost::add_edge(
1✔
249
                    std::find(names.begin(), names.end(), member_structure->name()) - names.begin(),
1✔
250
                    std::find(names.begin(), names.end(), structure) - names.begin(), graph);
1✔
251
            }
1✔
252
        }
3✔
253
    }
254

255
    std::list<Vertex> order;
4✔
256
    std::unordered_map<Vertex, boost::default_color_type> vertex_colors;
4✔
257
    boost::topological_sort(graph, std::back_inserter(order),
8✔
258
                            boost::color_map(boost::make_assoc_property_map(vertex_colors)));
4✔
259
    order.reverse();
4✔
260

261
    for (auto& structure_index : order) {
7✔
262
        std::string structure = names.at(structure_index);
3✔
263
        auto& definition = sdfg_.structure(structure);
3✔
264
        this->classes_stream_ << "typedef struct ";
3✔
265
        if (definition.is_packed()) {
3✔
266
            this->classes_stream_ << "__attribute__((packed)) ";
×
267
        }
×
268
        this->classes_stream_ << structure << std::endl;
3✔
269
        this->classes_stream_ << "{\n";
3✔
270

271
        for (size_t i = 0; i < definition.num_members(); i++) {
6✔
272
            auto& member_type = definition.member_type(symbolic::integer(i));
3✔
273
            if (auto pointer_type = dynamic_cast<const sdfg::types::Pointer*>(&member_type)) {
3✔
274
                if (dynamic_cast<const sdfg::types::Structure*>(&pointer_type->pointee_type())) {
×
275
                    this->classes_stream_ << "struct ";
×
276
                }
×
277
            }
×
278
            this->classes_stream_ << language_extension_.declaration("member_" + std::to_string(i),
3✔
279
                                                                     member_type, false, true);
3✔
280
            this->classes_stream_ << ";" << std::endl;
3✔
281
        }
3✔
282

283
        this->classes_stream_ << "} " << structure << ";" << std::endl;
3✔
284
    }
3✔
285
};
4✔
286

287
void CCodeGenerator::dispatch_globals() {
4✔
288
    for (auto& container : sdfg_.externals()) {
5✔
289
        this->globals_stream_ << "extern "
2✔
290
                              << language_extension_.declaration(container, sdfg_.type(container))
1✔
291
                              << ";" << std::endl;
1✔
292
    }
293
};
4✔
294

295
void CCodeGenerator::dispatch_schedule() {
4✔
296
    // Map external variables to internal variables
297
    for (auto& container : sdfg_.containers()) {
5✔
298
        if (!sdfg_.is_internal(container)) {
1✔
299
            continue;
1✔
300
        }
301
        std::string external_name =
302
            container.substr(0, container.length() - external_suffix.length());
×
303
        this->main_stream_ << language_extension_.declaration(container, sdfg_.type(container));
×
304
        this->main_stream_ << " = "
×
305
                           << language_extension_.type_cast("&" + external_name,
×
306
                                                            sdfg_.type(container));
×
307
        this->main_stream_ << ";" << std::endl;
×
308
    }
×
309

310
    // Declare transient containers
311
    for (auto& container : sdfg_.containers()) {
5✔
312
        if (!sdfg_.is_transient(container)) {
1✔
313
            continue;
1✔
314
        }
315

316
        std::string val =
317
            this->language_extension_.declaration(container, sdfg_.type(container), false, true);
×
318
        if (!val.empty()) {
×
319
            this->main_stream_ << val;
×
320
            this->main_stream_ << ";" << std::endl;
×
321
        }
×
322
    }
×
323

324
    // Add instrumentation
325
    auto instrumentation = create_instrumentation(instrumentation_strategy_, sdfg_);
4✔
326

327
    auto dispatcher = create_dispatcher(language_extension_, sdfg_, sdfg_.root(), *instrumentation);
4✔
328
    dispatcher->dispatch(this->main_stream_, this->globals_stream_, this->library_stream_);
4✔
329
};
4✔
330

331
}  // namespace codegen
332
}  // 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