18 #include "tensordoc.h"
20 #include <dlpack/dlpack.h>
23 #include <pybind11/pybind11.h>
24 #include <pybind11/numpy.h>
29 class __attribute__ ((visibility("hidden"))) DlpackTensorContext :
public Tensor::Context {
31 DlpackTensorContext(py::object dlm_tensor): dlm_tensor_(dlm_tensor) {}
32 virtual ~DlpackTensorContext() {}
34 py::object dlm_tensor_;
52 py::tuple
dlpack_device =
object.attr(
"__dlpack_device__")().cast<py::tuple>();
53 auto device_type =
static_cast<DLDeviceType
>(
dlpack_device[0].cast<
int>());
55 if (device_type == kDLCUDAHost || device_type == kDLCUDA || device_type == kDLCUDAManaged) {
57 cap =
object.attr(
"__dlpack__")(py::arg(
"stream") = stream_id).cast<py::capsule>();
59 cap =
object.attr(
"__dlpack__")().cast<py::capsule>();
61 if (!PyCapsule_IsValid(cap.ptr(),
"dltensor")) {
62 throw std::runtime_error(
"Invalid capsule for dltensor");
64 DLManagedTensor *dl_managed_tensor = cap.get_pointer<DLManagedTensor>();
65 const DLTensor& dl_tensor = dl_managed_tensor->dl_tensor;
66 unsigned int device_id = (
unsigned int )dl_tensor.device.device_id;
67 auto dtype_code = dl_tensor.dtype.code;
69 if (device_type == kDLCPU) {
70 device = Tensor::DeviceType::CPU;
71 }
else if (device_type == kDLCUDAHost || device_type == kDLCUDA || device_type == kDLCUDAManaged) {
72 device = Tensor::DeviceType::GPU;
74 throw std::runtime_error(
"Unsupported Tensor Device Type");
78 if (dtype_code == kDLInt) {
79 dtype = Tensor::SIGNED;
80 }
else if (dtype_code == kDLUInt || dtype_code == kDLBool) {
81 dtype = Tensor::UNSIGNED;
82 }
else if (dtype_code == kDLFloat) {
84 }
else if (dtype_code == kDLComplex) {
85 dtype = Tensor::COMPLEX;
87 std::string dtype_str = std::to_string(dtype_code);
88 throw std::runtime_error(
"Unsupported Tensor dtype: " + dtype_str);
101 new DlpackTensorContext(
object)
111 for (
size_t i = 0; i <
tensor_->rank(); i++) {
119 auto tensor_shape =
tensor_->shape();
120 py::tuple
shape(ndim);
121 for (
size_t i = 0; i < ndim; i++) {
122 shape[i] = tensor_shape[i];
130 for (
size_t d = 0; d < ndim; d++) {
142 std::string dtype_str;
143 if (
dtype == Tensor::UNSIGNED) {
145 }
else if (
dtype == Tensor::SIGNED) {
149 }
else if (
dtype == Tensor::COMPLEX) {
150 dtype_str =
"complex";
152 if (dtype_str.length()) {
153 dtype_str += std::to_string(
tensor_->bits());
154 return py::dtype(dtype_str);
160 py::capsule
dlpack(PyObject* py_object_ptr, py::object stream) {
161 unique_ptr<DLManagedTensor> dl_managed_tensor(
new DLManagedTensor);
162 dl_managed_tensor->manager_ctx = (
void*) py_object_ptr;
163 dl_managed_tensor->deleter = [](DLManagedTensor *tensor) {
164 py::gil_scoped_acquire acquire;
165 delete tensor->dl_tensor.shape;
166 delete tensor->dl_tensor.strides;
167 auto ctx =
static_cast<PyObject*
>(tensor->manager_ctx);
170 tensor->manager_ctx = NULL;
174 DLTensor &dl_tensor = dl_managed_tensor->dl_tensor;
175 dl_tensor.device.device_type =
tensor_->deviceType() == Tensor::DeviceType::GPU ? kDLCUDA : kDLCPU;
176 dl_tensor.device.device_id =
tensor_->deviceId();
177 dl_tensor.ndim =
tensor_->rank();
179 unique_ptr<int64_t[]> shape_ptr(
new int64_t[dl_tensor.ndim]);
180 copy_n(
tensor_->shape().begin(), dl_tensor.ndim, shape_ptr.get());
181 dl_tensor.shape = shape_ptr.release();
183 unique_ptr<int64_t[]> strides_ptr(
new int64_t[dl_tensor.ndim]);
184 for (
int n = 0; n < dl_tensor.ndim; n++) {
185 strides_ptr[n] =
tensor_->stride(n);
187 dl_tensor.strides = strides_ptr.release();
190 uint8_t dtype_code = 0;
191 if (
dtype == Tensor::UNSIGNED) {
192 dtype_code = kDLUInt;
193 }
else if (
dtype == Tensor::SIGNED) {
196 dtype_code = kDLFloat;
197 }
else if (
dtype == Tensor::COMPLEX) {
198 dtype_code = kDLComplex;
200 dl_tensor.dtype = {dtype_code, (uint8_t)
tensor_->bits(), 1};
202 dl_tensor.data =
tensor_->data();
203 dl_tensor.byte_offset = 0;
205 py::capsule cap(dl_managed_tensor.release(),
"dltensor", [](PyObject *ptr) {
206 if (PyCapsule_IsValid(ptr,
"dltensor")) {
207 if(auto *tensor = static_cast<DLManagedTensor *>(PyCapsule_GetPointer(ptr,
"dltensor"))) {
208 if (tensor->deleter) {
209 tensor->deleter(tensor);
219 return {kDLCUDA, tensor_->deviceId()};
244 return tensor_->size();
260 auto dtype = tensor_->deviceType();
261 if (dtype == Tensor::DeviceType::GPU)
return "GPU";
262 if (dtype == Tensor::DeviceType::CPU)
return "CPU";
268 return tensor_->data();
278 void print_nd_summary(
const void* base,
const std::vector<uint64_t>& shape,
const std::vector<int64_t>& strides,
size_t dim = 0, ssize_t offset = 0) {
279 if (dim == shape.size()) {
280 const T* ptr =
reinterpret_cast<const T*
>(
reinterpret_cast<const char*
>(base) + offset);
285 ssize_t n = shape[dim];
286 ssize_t print_head = std::min<ssize_t>(3, n);
287 ssize_t print_tail = (n > 6) ? 3 : std::max<ssize_t>(0, n - 3);
290 for (ssize_t i = 0; i < print_head; ++i) {
291 if (i > 0) std::cout <<
", ";
292 print_nd_summary<T>(base, shape, strides, dim + 1, offset + i * strides[dim]);
295 if (n > 6) std::cout <<
", ...";
297 for (ssize_t i = n - print_tail; i < n; ++i) {
298 if (i > 0) std::cout <<
", ";
299 print_nd_summary<T>(base, shape, strides, dim + 1, offset + i * strides[dim]);
316 .def(
"__dlpack__", [](py::object&
self, py::object stream){
318 Py_INCREF(
self.ptr());
319 return tensor->
dlpack(
self.ptr(), stream);
326 .def(
"__bool__", [](
TensorWrapper&
self) {
return self.hasTensor(); })
328 if (
self.hasTensor()) {
329 if (
self.deviceType() ==
"CPU") {
330 return "Tensor(shape=" + py::repr(
self.shape()).cast<std::string>() +
331 ", strides=" + py::repr(
self.strides()).cast<std::string>() +
332 ", dtype=" + py::repr(
self.dtype()).cast<std::string>() +
333 ", __dlpack_device__=" + py::repr(py::cast(
self.dlpackDevice())).cast<std::string>() +
334 ", device_type=" +
self.deviceType() +
335 ", size=" + std::to_string(
self.
size()) +
336 ", data=" + py::repr(py::array(
self.dtype(),
self.shape_vec(),
self.strides_vec(),
self.
data())).cast<std::string>() +
339 return "Tensor(shape=" + py::repr(
self.shape()).cast<std::string>() +
340 ", strides=" + py::repr(
self.strides()).cast<std::string>() +
341 ", dtype=" + py::repr(
self.dtype()).cast<std::string>() +
342 ", __dlpack_device__=" + py::repr(py::cast(
self.dlpackDevice())).cast<std::string>() +
343 ", device_type=" +
self.deviceType() +
344 ", size=" + std::to_string(
self.
size()) +
345 ", data=" + py::repr(py::cast(
self.
data())).cast<std::string>() +
348 return "Tensor(shape=" + py::repr(
self.shape()).cast<std::string>() +
349 ", strides=" + py::repr(
self.strides()).cast<std::string>() +
350 ", dtype=" + py::repr(
self.dtype()).cast<std::string>() +
351 ", __dlpack_device__=" + py::repr(py::cast(
self.dlpackDevice())).cast<std::string>() +
352 ", size=" + std::to_string(
self.
size()) +
355 m.def(
"as_tensor", [](py::object
object, std::string
format) {
356 if (hasattr(
object,
"__dlpack_device__")) {
357 return make_unique<TensorWrapper>(
object,
format);
359 return make_unique<TensorWrapper>();