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

celerity / celerity-runtime / 9549024017

17 Jun 2024 01:57PM UTC coverage: 94.675%. Remained the same
9549024017

push

github

fknorr
Implement and test out_of_order_engine

The out-of-order engine keeps track of all instructions that have not yet
completed and decides which instructions to schedule onto which backend
resources at what time, and receives back information on which instructions
have already completed. This will allow us to keep the instruction executor
free of most instruction state tracking.

This new form of scheduling is based on a definition of backends which maintain
an array of in-order thread queues for host work and in-order SYCL queues for
device submissions. This allows the engine to omit host / executor loop
round-trips between consecutive GPU / CPU loads by scheduling successors onto
the same in-order queues to implicitly fulfil dependencies, and thus hide SYCL
and CUDA kernel launch latency.

In the future this could be improved further with support to submit
instructions with dependencies on multiple queues / devices earlier by waiting
on in-flight SYCL events.

3064 of 3419 branches covered (89.62%)

Branch coverage included in aggregate %.

187 of 201 new or added lines in 4 files covered. (93.03%)

20 existing lines in 4 files now uncovered.

7053 of 7267 relevant lines covered (97.06%)

216909.6 hits per line

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

83.91
/src/utils.cc
1
#include "utils.h"
2
#include "log.h"
3

4
#include <atomic>
5
#include <regex>
6
#include <stdexcept>
7

8
#if !defined(_MSC_VER)
9
// Required for kernel name demangling in Clang
10
#include <cxxabi.h>
11
#endif
12

13

14
namespace celerity::detail::utils {
15

16
std::string get_simplified_type_name_from_pointer(const std::type_info& pointer_type_info) {
1,999✔
17
#if !defined(_MSC_VER)
18
        const std::unique_ptr<char, void (*)(void*)> demangle_buffer(abi::__cxa_demangle(pointer_type_info.name(), nullptr, nullptr, nullptr), std::free);
1,999✔
19
        std::string demangled_type_name = demangle_buffer.get();
3,998✔
20
#else
21
        std::string demangled_type_name = pointer_type_info.name();
22
#endif
23

24
        // get rid of the pointer "*"
25
        if(!demangled_type_name.empty() && demangled_type_name.back() == '*') { demangled_type_name.pop_back(); }
1,999!
26

27
        if(demangled_type_name.length() < 2) return demangled_type_name;
1,999!
28
        bool templated = false;
1,999✔
29
        // there are two options:
30
        // 1. the type is templated; in this case, the last character is ">" and we go back to the matching "<"
31
        std::string::size_type last_idx = demangled_type_name.length() - 1;
1,999✔
32
        if(demangled_type_name[last_idx] == '>') {
1,999✔
33
                templated = true;
49✔
34
                int open = 0;
49✔
35
                while(last_idx > 1) {
1,106!
36
                        last_idx--;
1,106✔
37
                        if(demangled_type_name[last_idx] == '>') { open++; }
1,106✔
38
                        if(demangled_type_name[last_idx] == '<') {
1,106✔
39
                                if(open > 0) {
57✔
40
                                        open--;
8✔
41
                                } else {
42
                                        last_idx--;
49✔
43
                                        break;
49✔
44
                                }
45
                        }
46
                }
47
        }
48
        // 2. the type isn't templated (or we just removed the template); in this case, we are interested in the part from the end to the last ":" (or the start)
49
        std::string::size_type start_idx = last_idx - 1;
1,999✔
50
        while(start_idx > 0 && demangled_type_name[start_idx - 1] != ':') {
35,189✔
51
                start_idx--;
33,190✔
52
        }
53
        // if the type was templated, we add a "<...>" to indicate that
54
        return demangled_type_name.substr(start_idx, last_idx - start_idx + 1) + (templated ? "<...>" : "");
3,998✔
55
}
1,999✔
56

57
std::string escape_for_dot_label(std::string str) {
326✔
58
        str = std::regex_replace(str, std::regex("&"), "&amp;");
326✔
59
        str = std::regex_replace(str, std::regex("<"), "&lt;");
326✔
60
        str = std::regex_replace(str, std::regex(">"), "&gt;");
326✔
61
        return str;
326✔
62
}
63

NEW
64
[[noreturn]] void unreachable() {
×
NEW
65
        assert(!"executed unreachable code");
×
66
        abort();
67
}
68

69
// The panic solution defaults to `log_and_abort`, but is set to `throw_logic_error` in test binaries. Since panics are triggered from celerity library code, we
70
// manage it in a global and decide which path to take at runtime. We have also considered deciding this at link time by defining a weak symbol (GCC
71
// __attribute__((weak))) in the library which is overwritten by a strong symbol in the test library, but decided against this because there is no equivalent in
72
// MSVC and we would have to resort to even dirtier linker hacks for that target.
73
std::atomic<panic_solution> g_panic_solution = panic_solution::log_and_abort; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
74

75
void set_panic_solution(panic_solution solution) { g_panic_solution.store(solution, std::memory_order_relaxed); }
13✔
76

77
[[noreturn]] void panic(const std::string& msg) {
17✔
78
        switch(g_panic_solution.load(std::memory_order_relaxed)) {
17!
79
        case celerity::detail::utils::panic_solution::throw_logic_error: {
17✔
80
                throw std::logic_error(msg);
17✔
81
        }
UNCOV
82
        case celerity::detail::utils::panic_solution::log_and_abort:
×
83
        default: {
84
                // Print directly instead of logging: The abort message must not be hidden by log level setting, and in tests would be captured without the logging
85
                // infrastructure having a chance of dumping the logs due to the abort.
UNCOV
86
                fmt::print(stderr, "celerity-runtime panic: {}\n", msg);
×
87
                std::abort();
×
88
        }
89
        }
90
}
91

92
void report_error(const error_policy policy, const std::string& msg) {
31✔
93
        switch(policy) {
31!
UNCOV
94
        case error_policy::ignore: break;
×
95
        case error_policy::log_warning: CELERITY_WARN("{}", msg); break;
4✔
96
        case error_policy::log_error: CELERITY_ERROR("{}", msg); break;
24✔
97
        case error_policy::panic: panic(msg); break;
17✔
98
        }
99
}
14✔
100

101
std::string make_buffer_debug_label(const buffer_id bid, const std::string& name) {
273✔
102
        // if there is no name defined, the name will be the buffer id.
103
        // if there is a name we want "id name"
104
        return !name.empty() ? fmt::format("B{} \"{}\"", bid, name) : fmt::format("B{}", bid);
273✔
105
}
106

107
} // namespace celerity::detail::utils
108

109

110
// implemented here because types.h must not depend on utils.h
111
std::size_t std::hash<celerity::detail::transfer_id>::operator()(const celerity::detail::transfer_id& t) const noexcept {
9,396✔
112
        auto hash = std::hash<celerity::detail::task_id>{}(t.consumer_tid);
9,396✔
113
        celerity::detail::utils::hash_combine(hash, std::hash<celerity::detail::buffer_id>{}(t.bid));
9,396✔
114
        celerity::detail::utils::hash_combine(hash, std::hash<celerity::detail::reduction_id>{}(t.rid));
9,396✔
115
        return hash;
9,396✔
116
}
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