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

IntelPython / dpnp / 24687578389

20 Apr 2026 08:03PM UTC coverage: 78.429% (-3.6%) from 82.034%
24687578389

push

github

web-flow
Migrate `dpctl.tensor` into `dpnp.tensor` (#2856)

This PR migrates the tensor implementation from `dpctl.tensor` into
`dpnp.tensor` making dpnp the primary owner of the Array API-compliant
tensor layer

Major changes:

- Move compiled C++/SYCL extensions (`_tensor_impl,
_tensor_elementwise_impl, _tensor_reductions_impl, _tensor_sorting_impl,
_tensor_accumulation_impl, tensor linalg`) into `dpnp.tensor`
- Move `usm_ndarray`, `compute-follows-data utilities` and tensor
`tests` from dpctl
- Replace all `dpctl.tensor` references with `dpnp.tensor` in
docstrings, error messages and comments
- Remove redundant dpctl.tensor C-API  interface
- Add `tensor.rst` documentation page describing the module, its
relationship to `dpnp.ndarray` and `dpctl` and linking to the `dpctl
0.21.1 API` reference

This simplifies maintenance, reduces cross-project dependencies and
enables independent development and release cycles

1573 of 2908 branches covered (54.09%)

Branch coverage included in aggregate %.

6973 of 9803 new or added lines in 203 files covered. (71.13%)

1 existing line in 1 file now uncovered.

26259 of 32579 relevant lines covered (80.6%)

7622.15 hits per line

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

82.81
/dpnp/tensor/libtensor/include/utils/sycl_alloc_utils.hpp
1
//*****************************************************************************
2
// Copyright (c) 2026, Intel Corporation
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are met:
7
// - Redistributions of source code must retain the above copyright notice,
8
//   this list of conditions and the following disclaimer.
9
// - Redistributions in binary form must reproduce the above copyright notice,
10
//   this list of conditions and the following disclaimer in the documentation
11
//   and/or other materials provided with the distribution.
12
// - Neither the name of the copyright holder nor the names of its contributors
13
//   may be used to endorse or promote products derived from this software
14
//   without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26
// THE POSSIBILITY OF SUCH DAMAGE.
27
//*****************************************************************************
28
///
29
/// \file
30
/// This file defines CIndexer_array, and CIndexer_vector classes, as well
31
/// iteration space simplifiers.
32
//===----------------------------------------------------------------------===//
33

34
#pragma once
35

36
#include <cstddef>
37
#include <exception>
38
#include <iostream>
39
#include <memory>
40
#include <stdexcept>
41
#include <type_traits>
42
#include <utility>
43
#include <vector>
44

45
#include <sycl/sycl.hpp>
46

47
namespace dpnp::tensor::alloc_utils
48
{
49
template <typename T>
50
class usm_host_allocator : public sycl::usm_allocator<T, sycl::usm::alloc::host>
51
{
52
public:
53
    using baseT = sycl::usm_allocator<T, sycl::usm::alloc::host>;
54
    using baseT::baseT;
55

56
    template <typename U>
57
    struct rebind
58
    {
59
        typedef usm_host_allocator<U> other;
60
    };
61

62
    void deallocate(T *ptr, std::size_t n)
63
    {
2,582✔
64
        try {
2,582✔
65
            baseT::deallocate(ptr, n);
2,582✔
66
        } catch (const std::exception &e) {
2,582✔
NEW
67
            std::cerr
×
NEW
68
                << "Exception caught in `usm_host_allocator::deallocate`: "
×
NEW
69
                << e.what() << std::endl;
×
NEW
70
        }
×
71
    }
2,582✔
72
};
73

74
template <typename T>
75
void sycl_free_noexcept(T *ptr, const sycl::context &ctx) noexcept
76
{
10,599✔
77
    try {
10,599✔
78
        sycl::free(ptr, ctx);
10,599✔
79
    } catch (const std::exception &e) {
10,599✔
NEW
80
        std::cerr << "Call to sycl::free caught exception: " << e.what()
×
NEW
81
                  << std::endl;
×
NEW
82
    }
×
83
}
10,599✔
84

85
template <typename T>
86
void sycl_free_noexcept(T *ptr, const sycl::queue &q) noexcept
87
{
52✔
88
    sycl_free_noexcept(ptr, q.get_context());
52✔
89
}
52✔
90

91
class USMDeleter
92
{
93
private:
94
    sycl::context ctx_;
95

96
public:
97
    USMDeleter(const sycl::queue &q) : ctx_(q.get_context()) {}
2,582✔
NEW
98
    USMDeleter(const sycl::context &ctx) : ctx_(ctx) {}
×
99

100
    template <typename T>
101
    void operator()(T *ptr) const
102
    {
2,582✔
103
        sycl_free_noexcept(ptr, ctx_);
2,582✔
104
    }
2,582✔
105
};
106

107
template <typename T>
108
std::unique_ptr<T, USMDeleter>
109
    smart_malloc(std::size_t count,
110
                 const sycl::queue &q,
111
                 sycl::usm::alloc kind,
112
                 const sycl::property_list &propList = {})
113
{
2,582✔
114
    T *ptr = sycl::malloc<T>(count, q, kind, propList);
2,582✔
115
    if (nullptr == ptr) {
2,582!
NEW
116
        throw std::runtime_error("Unable to allocate device_memory");
×
NEW
117
    }
×
118

119
    auto usm_deleter = USMDeleter(q);
2,582✔
120
    return std::unique_ptr<T, USMDeleter>(ptr, usm_deleter);
2,582✔
121
}
2,582✔
122

123
template <typename T>
124
std::unique_ptr<T, USMDeleter>
125
    smart_malloc_device(std::size_t count,
126
                        const sycl::queue &q,
127
                        const sycl::property_list &propList = {})
128
{
2,582✔
129
    return smart_malloc<T>(count, q, sycl::usm::alloc::device, propList);
2,582✔
130
}
2,582✔
131

132
template <typename T>
133
std::unique_ptr<T, USMDeleter>
134
    smart_malloc_shared(std::size_t count,
135
                        const sycl::queue &q,
136
                        const sycl::property_list &propList = {})
137
{
138
    return smart_malloc<T>(count, q, sycl::usm::alloc::shared, propList);
139
}
140

141
template <typename T>
142
std::unique_ptr<T, USMDeleter>
143
    smart_malloc_host(std::size_t count,
144
                      const sycl::queue &q,
145
                      const sycl::property_list &propList = {})
146
{
147
    return smart_malloc<T>(count, q, sycl::usm::alloc::host, propList);
148
}
149

150
namespace detail
151
{
152
template <typename T>
153
struct valid_smart_ptr : public std::false_type
154
{
155
};
156

157
template <typename ValT, typename DeleterT>
158
struct valid_smart_ptr<std::unique_ptr<ValT, DeleterT> &>
159
    : public std::is_same<DeleterT, USMDeleter>
160
{
161
};
162

163
template <typename ValT, typename DeleterT>
164
struct valid_smart_ptr<std::unique_ptr<ValT, DeleterT>>
165
    : public std::is_same<DeleterT, USMDeleter>
166
{
167
};
168

169
// base case
170
template <typename... Rest>
171
struct all_valid_smart_ptrs
172
{
173
    static constexpr bool value = true;
174
};
175

176
template <typename Arg, typename... RestArgs>
177
struct all_valid_smart_ptrs<Arg, RestArgs...>
178
{
179
    static constexpr bool value = valid_smart_ptr<Arg>::value &&
180
                                  (all_valid_smart_ptrs<RestArgs...>::value);
181
};
182
} // end of namespace detail
183

184
/*! @brief Submit host_task and transfer ownership from smart pointers to it */
185
template <typename... UniquePtrTs>
186
sycl::event async_smart_free(sycl::queue &exec_q,
187
                             const std::vector<sycl::event> &depends,
188
                             UniquePtrTs &&...unique_pointers)
189
{
2,396✔
190
    static constexpr std::size_t n = sizeof...(UniquePtrTs);
2,396✔
191
    static_assert(
2,396✔
192
        n > 0, "async_smart_free requires at least one smart pointer argument");
2,396✔
193

194
    static_assert(
2,396✔
195
        detail::all_valid_smart_ptrs<UniquePtrTs...>::value,
2,396✔
196
        "async_smart_free requires unique_ptr created with smart_malloc");
2,396✔
197

198
    std::vector<void *> ptrs;
2,396✔
199
    ptrs.reserve(n);
2,396✔
200
    (ptrs.push_back(reinterpret_cast<void *>(unique_pointers.get())), ...);
2,396✔
201

202
    std::vector<USMDeleter> dels;
2,396✔
203
    dels.reserve(n);
2,396✔
204
    (dels.emplace_back(unique_pointers.get_deleter()), ...);
2,396✔
205

206
    sycl::event ht_e = exec_q.submit([&](sycl::handler &cgh) {
2,396✔
207
        cgh.depends_on(depends);
2,396✔
208

209
        cgh.host_task([ptrs = std::move(ptrs), dels = std::move(dels)]() {
2,396✔
210
            for (std::size_t i = 0; i < ptrs.size(); ++i) {
4,978✔
211
                dels[i](ptrs[i]);
2,582✔
212
            }
2,582✔
213
        });
2,396✔
214
    });
2,396✔
215

216
    // Upon successful submission of host_task, USM allocations are owned
217
    // by the host_task. Release smart pointer ownership to avoid double
218
    // deallocation
219
    (unique_pointers.release(), ...);
2,396✔
220

221
    return ht_e;
2,396✔
222
}
2,396✔
223
} // namespace dpnp::tensor::alloc_utils
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