| 597 | } |
| 598 | |
| 599 | PyObject* ndarray_from_tensor(const HostTensorND& val, ShareType share_type) { |
| 600 | if (!val.layout().is_contiguous() && !val.shape().is_empty()) { |
| 601 | mgb_assert(share_type != ShareType::MUST_SHARE); |
| 602 | HostTensorND contig; |
| 603 | contig.copy_from(val); |
| 604 | return ndarray_from_tensor(contig, ShareType::TRY_SHARE); |
| 605 | } |
| 606 | PYTHON_GIL; |
| 607 | npy_intp dims[TensorLayout::MAX_NDIM]; |
| 608 | for (size_t i = 0; i < val.layout().ndim; ++i) |
| 609 | dims[i] = val.shape()[i]; |
| 610 | PyObject* ret = nullptr; |
| 611 | |
| 612 | auto alloc_new_ret = [&]() { |
| 613 | mgb_assert(!ret); |
| 614 | ret = PyArray_NewFromDescr( |
| 615 | &PyArray_Type, dtype_mgb2np_descr(val.dtype()).release(), |
| 616 | val.layout().ndim, dims, nullptr, nullptr, 0, nullptr); |
| 617 | mgb_assert(ret, "failed to allocate array"); |
| 618 | mgb_assert(PyArray_Check(ret)); |
| 619 | return PyArray_DATA(reinterpret_cast<PyArrayObject*>(ret)); |
| 620 | }; |
| 621 | if (val.dtype().is_low_bit()) { |
| 622 | mgb_assert( |
| 623 | share_type != ShareType::MUST_SHARE, |
| 624 | "can not share memory for lowbit dtype"); |
| 625 | const auto& layout = val.layout(); |
| 626 | if (layout.format.is_lowbit_aligned()) { |
| 627 | lowbit_memcpy_aligned2byte(alloc_new_ret(), val.raw_ptr(), val.layout()); |
| 628 | } else { |
| 629 | lowbit_memcpy_compact2byte( |
| 630 | val.dtype(), alloc_new_ret(), val.raw_ptr(), |
| 631 | val.layout().total_nr_elems()); |
| 632 | } |
| 633 | } else if (share_type == ShareType::MUST_UNSHARE) { |
| 634 | memcpy(alloc_new_ret(), val.raw_ptr(), val.layout().span().dist_byte()); |
| 635 | } else { |
| 636 | // share data |
| 637 | ret = PyArray_NewFromDescr( |
| 638 | &PyArray_Type, dtype_mgb2np_descr(val.dtype()).release(), |
| 639 | val.layout().ndim, dims, nullptr, const_cast<dt_byte*>(val.raw_ptr()), |
| 640 | 0, nullptr); |
| 641 | mgb_assert(ret, "failed to alloc ndarray"); |
| 642 | auto capsule = PyCapsule_New( |
| 643 | HostTensorNDRefHolder::alloc(val), "HostTensorND", |
| 644 | ndarray_shared_from_tensor_py_capsule_dtor); |
| 645 | mgb_assert(capsule, "failed to create PyCapsule"); |
| 646 | auto err = |
| 647 | PyArray_SetBaseObject(reinterpret_cast<PyArrayObject*>(ret), capsule); |
| 648 | mgb_assert(!err); |
| 649 | } |
| 650 | return ret; |
| 651 | } |
| 652 | |
| 653 | HostTensorND np2tensor(PyObject* obj, const Meth& meth, DType dtype) { |
| 654 | auto ret_full = np2tensor_try_borrow(obj, meth, dtype); |
no test coverage detected