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

IntelPython / dpctl / 42284156169

06 Nov 2026 07:57PM UTC coverage: 75.487% (+0.6%) from 74.883%
42284156169

Pull #2420

github

web-flow
Merge 08612c3d3 into 6d9edf21b
Pull Request #2420: Implement filter selector strings without the DPC++ extension

1140 of 1578 branches covered (72.24%)

Branch coverage included in aggregate %.

109 of 110 new or added lines in 1 file covered. (99.09%)

4166 of 5451 relevant lines covered (76.43%)

391.61 hits per line

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

96.17
/libsyclinterface/source/dpctl_device_selection.cpp
1
//===- dpctl_device_selection.cpp - Implementation of classes   -*-C++-*- ===//
2
// dpctl_device_selector, dpctl_default_selector, etc.
3
//
4
//                      Data Parallel Control (dpctl)
5
//
6
// Copyright 2022 Intel Corporation
7
//
8
// Licensed under the Apache License, Version 2.0 (the "License");
9
// you may not use this file except in compliance with the License.
10
// You may obtain a copy of the License at
11
//
12
//    http://www.apache.org/licenses/LICENSE-2.0
13
//
14
// Unless required by applicable law or agreed to in writing, software
15
// distributed under the License is distributed on an "AS IS" BASIS,
16
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
// See the License for the specific language governing permissions and
18
// limitations under the License.
19
//
20
//===----------------------------------------------------------------------===//
21
///
22
/// \file
23
/// This file implements device-selection classes declared in
24
/// dpctl_device_selection.hpp
25
///
26
//===----------------------------------------------------------------------===//
27

28
#include "dpctl_device_selection.hpp"
29
#include "Config/dpctl_config.h"
30
#include <charconv>
31
#include <cstddef>
32
#include <optional>
33
#include <stdexcept>
34
#include <string>
35
#include <sycl/sycl.hpp>
36
#include <utility>
37
#include <vector>
38

39
namespace
40
{
41
static_assert(__SYCL_COMPILER_VERSION >= __SYCL_COMPILER_VERSION_REQUIRED,
42
              "The compiler does not meet minimum version requirement");
43

44
/*! Splits s on delim, dropping empty tokens. */
45
std::vector<std::string> tokenize(const std::string &s, char delim)
46
{
13,398 ✔
47
    std::vector<std::string> tokens;
13,398 ✔
48
    std::size_t start = 0;
13,398 ✔
49
    while (start <= s.size()) {
32,439 ✔
50
        auto end = s.find(delim, start);
19,041 ✔
51
        if (end == std::string::npos)
19,041 ✔
52
            end = s.size();
13,398 ✔
53
        if (end > start)
19,041 ✔
54
            tokens.emplace_back(s, start, end - start);
19,027 ✔
55
        start = end + 1;
19,041 ✔
56
    }
19,041 ✔
57
    return tokens;
13,398 ✔
58
}
13,398 ✔
59

60
std::optional<sycl::backend> backend_from_token(const std::string &tok)
61
{
12,309 ✔
62
    if (tok == "opencl")
12,309 ✔
63
        return sycl::backend::opencl;
2,859 ✔
64
    if (tok == "level_zero")
9,450 ✔
65
        return sycl::backend::ext_oneapi_level_zero;
1,445 ✔
66
    if (tok == "cuda")
8,005 ✔
67
        return sycl::backend::ext_oneapi_cuda;
28 ✔
68
    if (tok == "hip")
7,977 ✔
69
        return sycl::backend::ext_oneapi_hip;
7 ✔
70
    return std::nullopt;
7,970 ✔
71
}
7,977 ✔
72

73
std::optional<sycl::info::device_type>
74
device_type_from_token(const std::string &tok)
75
{
7,975 ✔
76
    if (tok == "cpu")
7,975 ✔
77
        return sycl::info::device_type::cpu;
1,810 ✔
78
    if (tok == "gpu")
6,165 ✔
79
        return sycl::info::device_type::gpu;
3,287 ✔
80
    if (tok == "accelerator")
2,878 !
NEW
81
        return sycl::info::device_type::accelerator;
×
82
    if (tok == "custom")
2,878 ✔
83
        return sycl::info::device_type::custom;
3 ✔
84
    return std::nullopt;
2,875 ✔
85
}
2,878 ✔
86

87
/*! Parses a non-negative decimal int; nullopt on any other input. */
88
std::optional<int> device_num_from_token(const std::string &tok)
89
{
2,880 ✔
90
    for (char c : tok) {
2,910 ✔
91
        if (c < '0' || c > '9')
2,910 ✔
92
            return std::nullopt;
77 ✔
93
    }
2,910 ✔
94
    int num = 0;
2,803 ✔
95
    const char *first = tok.data();
2,803 ✔
96
    const char *last = first + tok.size();
2,803 ✔
97
    auto [ptr, ec] = std::from_chars(first, last, num);
2,803 ✔
98
    if (ec != std::errc{} || ptr != last)
2,803 !
99
        return std::nullopt;
3 ✔
100
    return num;
2,800 ✔
101
}
2,803 ✔
102

103
bool matches_backend_and_type(const std::optional<sycl::backend> &be,
104
                              const std::optional<sycl::info::device_type> &dt,
105
                              const sycl::device &d)
106
{
7,493 ✔
107
    if (be && d.get_backend() != *be)
7,493 ✔
108
        return false;
1,475 ✔
109
    if (dt && d.get_info<sycl::info::device::device_type>() != *dt)
6,018 ✔
110
        return false;
2,273 ✔
111
    return true;
3,745 ✔
112
}
6,018 ✔
113

114
[[noreturn]] void throw_invalid_filter(const std::string &fs)
115
{
90 ✔
116
    throw std::invalid_argument(
90 ✔
117
        "Invalid filter string '" + fs +
90 ✔
118
        "'. Filters are comma-separated and have the form "
90 ✔
119
        "backend:device_type:device_num, where each component is optional.");
90 ✔
120
}
90 ✔
121
} // namespace
122

123
namespace dpctl
124
{
125
namespace syclinterface
126
{
127

128
int dpctl_device_selector::operator()(const sycl::device &) const
129
{
×
130
    return REJECT_DEVICE;
×
131
}
×
132

133
int dpctl_accelerator_selector::operator()(const sycl::device &d) const
134
{
207 ✔
135
    return sycl::accelerator_selector_v(d);
207 ✔
136
}
207 ✔
137

138
int dpctl_default_selector::operator()(const sycl::device &d) const
139
{
1,002 ✔
140
    auto score = sycl::default_selector_v(d);
1,002 ✔
141
    return score;
1,002 ✔
142
}
1,002 ✔
143

144
int dpctl_gpu_selector::operator()(const sycl::device &d) const
145
{
208 ✔
146
    return sycl::gpu_selector_v(d);
208 ✔
147
}
208 ✔
148

149
int dpctl_cpu_selector::operator()(const sycl::device &d) const
150
{
209 ✔
151
    return sycl::cpu_selector_v(d);
209 ✔
152
}
209 ✔
153

154
dpctl_filter_selector::dpctl_filter_selector(const std::string &fs)
155
{
6,702 ✔
156
    std::vector<std::pair<filter, std::optional<int>>> parsed;
6,702 ✔
157
    for (const auto &filter_str : tokenize(fs, ',')) {
6,702 ✔
158
        auto tokens = tokenize(filter_str, ':');
6,696 ✔
159
        if (tokens.size() > 3)
6,696 ✔
160
            throw_invalid_filter(fs);
5 ✔
161

162
        filter f;
6,696 ✔
163
        std::optional<int> device_num;
6,696 ✔
164
        for (const auto &tok : tokens) {
12,309 ✔
165
            if (auto be = backend_from_token(tok); be && !f.backend)
12,309 ✔
166
                f.backend = be;
4,334 ✔
167
            else if (auto dt = device_type_from_token(tok);
7,975 ✔
168
                     dt && !f.device_type)
7,975 ✔
169
                f.device_type = dt;
5,095 ✔
170
            else if (auto num = device_num_from_token(tok); num && !device_num)
2,880 ✔
171
                device_num = num;
2,795 ✔
172
            else
85 ✔
173
                throw_invalid_filter(fs);
85 ✔
174
        }
12,309 ✔
175
        parsed.emplace_back(std::move(f), device_num);
6,696 ✔
176
    }
6,696 ✔
177

178
    // Resolve device numbers; a filter whose device does not exist is dropped
179
    std::vector<sycl::device> devices;
6,702 ✔
180
    bool have_devices = false;
6,702 ✔
181
    for (auto &[f, device_num] : parsed) {
6,702 ✔
182
        if (device_num) {
6,606 ✔
183
            if (!have_devices) {
2,790 !
184
                devices = sycl::device::get_devices();
2,790 ✔
185
                have_devices = true;
2,790 ✔
186
            }
2,790 ✔
187
            int idx = 0;
2,790 ✔
188
            for (const auto &d : devices) {
2,790 ✔
189
                if (!matches_backend_and_type(f.backend, f.device_type, d))
2,790 ✔
190
                    continue;
1,700 ✔
191
                if (idx++ == *device_num) {
1,090 ✔
192
                    f.device = d;
885 ✔
193
                    break;
885 ✔
194
                }
885 ✔
195
            }
1,090 ✔
196
            if (!f.device)
2,790 ✔
197
                continue;
1,905 ✔
198
        }
2,790 ✔
199
        _filters.push_back(std::move(f));
4,701 ✔
200
    }
4,701 ✔
201
}
6,702 ✔
202

203
int dpctl_filter_selector::operator()(const sycl::device &d) const
204
{
6,614 ✔
205
    for (const auto &f : _filters) {
6,614 ✔
206
        if (matches_backend_and_type(f.backend, f.device_type, d) &&
4,703 ✔
207
            (!f.device || *f.device == d))
2,655 !
208
            return sycl::default_selector_v(d);
2,655 ✔
209
    }
4,703 ✔
210
    return REJECT_DEVICE;
3,959 ✔
211
}
6,614 ✔
212

213
} // namespace syclinterface
214
} // namespace dpctl
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc