#include #include #include #include #include #include "docstrings.hpp" #include "utils.hpp" namespace py = pybind11; // used in Core.hpp py::object kp_trace, kp_debug, kp_info, kp_warning, kp_error; std::unique_ptr opAlgoDispatchPyInit(std::shared_ptr& algorithm, const py::array& push_consts) { const py::buffer_info info = push_consts.request(); KP_LOG_DEBUG("Kompute Python Manager creating tensor_T with push_consts " "size {} dtype {}", push_consts.size(), std::string(py::str(push_consts.dtype()))); if (push_consts.dtype().is(py::dtype::of())) { std::vector dataVec((float*)info.ptr, ((float*)info.ptr) + info.size); return std::unique_ptr{ new kp::OpAlgoDispatch( algorithm, dataVec) }; } else if (push_consts.dtype().is(py::dtype::of())) { std::vector dataVec((uint32_t*)info.ptr, ((uint32_t*)info.ptr) + info.size); return std::unique_ptr{ new kp::OpAlgoDispatch( algorithm, dataVec) }; } else if (push_consts.dtype().is(py::dtype::of())) { std::vector dataVec((int32_t*)info.ptr, ((int32_t*)info.ptr) + info.size); return std::unique_ptr{ new kp::OpAlgoDispatch( algorithm, dataVec) }; } else if (push_consts.dtype().is(py::dtype::of())) { std::vector dataVec((double*)info.ptr, ((double*)info.ptr) + info.size); return std::unique_ptr{ new kp::OpAlgoDispatch( algorithm, dataVec) }; } else { throw std::runtime_error("Kompute Python no valid dtype supported"); } } PYBIND11_MODULE(kp, m) { // The logging modules are used in the Kompute.hpp file py::module_ logging = py::module_::import("logging"); py::object kp_logger = logging.attr("getLogger")("kp"); kp_trace = kp_logger.attr( "debug"); // Same as for debug since python has no trace logging level kp_debug = kp_logger.attr("debug"); kp_info = kp_logger.attr("info"); kp_warning = kp_logger.attr("warning"); kp_error = kp_logger.attr("error"); logging.attr("basicConfig")(); py::module_ np = py::module_::import("numpy"); py::enum_(m, "TensorTypes") .value("device", kp::Tensor::TensorTypes::eDevice, DOC(kp, Tensor, TensorTypes, eDevice)) .value("host", kp::Tensor::TensorTypes::eHost, DOC(kp, Tensor, TensorTypes, eHost)) .value("storage", kp::Tensor::TensorTypes::eStorage, DOC(kp, Tensor, TensorTypes, eStorage)) .export_values(); py::class_>( m, "OpBase", DOC(kp, OpBase)); py::class_>( m, "OpTensorSyncDevice", DOC(kp, OpTensorSyncDevice)) .def(py::init>&>(), DOC(kp, OpTensorSyncDevice, OpTensorSyncDevice)); py::class_>( m, "OpTensorSyncLocal", DOC(kp, OpTensorSyncLocal)) .def(py::init>&>(), DOC(kp, OpTensorSyncLocal, OpTensorSyncLocal)); py::class_>( m, "OpTensorCopy", DOC(kp, OpTensorCopy)) .def(py::init>&>(), DOC(kp, OpTensorCopy, OpTensorCopy)); py::class_>( m, "OpAlgoDispatch", DOC(kp, OpAlgoDispatch)) .def(py::init&, const std::vector&>(), DOC(kp, OpAlgoDispatch, OpAlgoDispatch), py::arg("algorithm"), py::arg("push_consts") = std::vector()) .def(py::init(&opAlgoDispatchPyInit), DOC(kp, OpAlgoDispatch, OpAlgoDispatch), py::arg("algorithm"), py::arg("push_consts")); py::class_>( m, "OpMult", DOC(kp, OpMult)) .def(py::init>&, const std::shared_ptr&>(), DOC(kp, OpMult, OpMult)); py::class_>( m, "Algorithm", DOC(kp, Algorithm, Algorithm)) .def("get_tensors", &kp::Algorithm::getTensors, DOC(kp, Algorithm, getTensors)) .def("destroy", &kp::Algorithm::destroy, DOC(kp, Algorithm, destroy)) .def("is_init", &kp::Algorithm::isInit, DOC(kp, Algorithm, isInit)); py::class_>( m, "Tensor", DOC(kp, Tensor)) .def( "data", [](kp::Tensor& self) { // Non-owning container exposing the underlying pointer switch (self.dataType()) { case kp::Tensor::TensorDataTypes::eFloat: return py::array( self.size(), self.data(), py::cast(&self)); case kp::Tensor::TensorDataTypes::eUnsignedInt: return py::array( self.size(), self.data(), py::cast(&self)); case kp::Tensor::TensorDataTypes::eInt: return py::array( self.size(), self.data(), py::cast(&self)); case kp::Tensor::TensorDataTypes::eDouble: return py::array( self.size(), self.data(), py::cast(&self)); case kp::Tensor::TensorDataTypes::eBool: return py::array( self.size(), self.data(), py::cast(&self)); default: throw std::runtime_error( "Kompute Python data type not supported"); } }, DOC(kp, Tensor, data)) .def("size", &kp::Tensor::size, DOC(kp, Tensor, size)) .def("__len__", &kp::Tensor::size, DOC(kp, Tensor, size)) .def("tensor_type", &kp::Tensor::tensorType, DOC(kp, Tensor, tensorType)) .def("data_type", &kp::Tensor::dataType, DOC(kp, Tensor, dataType)) .def("is_init", &kp::Tensor::isInit, DOC(kp, Tensor, isInit)) .def("destroy", &kp::Tensor::destroy, DOC(kp, Tensor, destroy)); py::class_>(m, "Sequence") .def( "record", [](kp::Sequence& self, std::shared_ptr op) { return self.record(op); }, DOC(kp, Sequence, record)) .def( "eval", [](kp::Sequence& self) { return self.eval(); }, DOC(kp, Sequence, eval)) .def( "eval", [](kp::Sequence& self, std::shared_ptr op) { return self.eval(op); }, DOC(kp, Sequence, eval_2)) .def( "eval_async", [](kp::Sequence& self) { return self.eval(); }, DOC(kp, Sequence, evalAwait)) .def( "eval_async", [](kp::Sequence& self, std::shared_ptr op) { return self.evalAsync(op); }, DOC(kp, Sequence, evalAsync)) .def( "eval_await", [](kp::Sequence& self) { return self.evalAwait(); }, DOC(kp, Sequence, evalAwait)) .def( "eval_await", [](kp::Sequence& self, uint32_t wait) { return self.evalAwait(wait); }, DOC(kp, Sequence, evalAwait)) .def("is_recording", &kp::Sequence::isRecording, DOC(kp, Sequence, isRecording)) .def("is_running", &kp::Sequence::isRunning, DOC(kp, Sequence, isRunning)) .def("is_init", &kp::Sequence::isInit, DOC(kp, Sequence, isInit)) .def("clear", &kp::Sequence::clear, DOC(kp, Sequence, clear)) .def("rerecord", &kp::Sequence::rerecord, DOC(kp, Sequence, rerecord)) .def("get_timestamps", &kp::Sequence::getTimestamps, DOC(kp, Sequence, getTimestamps)) .def("destroy", &kp::Sequence::destroy, DOC(kp, Sequence, destroy)); py::class_>( m, "Manager", DOC(kp, Manager)) .def(py::init(), DOC(kp, Manager, Manager)) .def(py::init(), DOC(kp, Manager, Manager_2)) .def(py::init&, const std::vector&>(), DOC(kp, Manager, Manager_2), py::arg("device") = 0, py::arg("family_queue_indices") = std::vector(), py::arg("desired_extensions") = std::vector()) .def("destroy", &kp::Manager::destroy, DOC(kp, Manager, destroy)) .def("sequence", &kp::Manager::sequence, DOC(kp, Manager, sequence), py::arg("queue_index") = 0, py::arg("total_timestamps") = 0) .def( "tensor", [np](kp::Manager& self, const py::array_t& data, kp::Tensor::TensorTypes tensor_type) { const py::array_t& flatdata = np.attr("ravel")(data); const py::buffer_info info = flatdata.request(); KP_LOG_DEBUG("Kompute Python Manager tensor() creating tensor " "float with data size {}", flatdata.size()); return self.tensor(info.ptr, flatdata.size(), sizeof(float), kp::Tensor::TensorDataTypes::eFloat, tensor_type); }, DOC(kp, Manager, tensor), py::arg("data"), py::arg("tensor_type") = kp::Tensor::TensorTypes::eDevice) .def( "tensor_t", [np](kp::Manager& self, const py::array& data, kp::Tensor::TensorTypes tensor_type) { // TODO: Suppport strides in numpy format const py::array& flatdata = np.attr("ravel")(data); const py::buffer_info info = flatdata.request(); KP_LOG_DEBUG("Kompute Python Manager creating tensor_T with data " "size {} dtype {}", flatdata.size(), std::string(py::str(flatdata.dtype()))); if (flatdata.dtype().is(py::dtype::of())) { return self.tensor(info.ptr, flatdata.size(), sizeof(float), kp::Tensor::TensorDataTypes::eFloat, tensor_type); } else if (flatdata.dtype().is(py::dtype::of())) { return self.tensor(info.ptr, flatdata.size(), sizeof(uint32_t), kp::Tensor::TensorDataTypes::eUnsignedInt, tensor_type); } else if (flatdata.dtype().is(py::dtype::of())) { return self.tensor(info.ptr, flatdata.size(), sizeof(int32_t), kp::Tensor::TensorDataTypes::eInt, tensor_type); } else if (flatdata.dtype().is(py::dtype::of())) { return self.tensor(info.ptr, flatdata.size(), sizeof(double), kp::Tensor::TensorDataTypes::eDouble, tensor_type); } else if (flatdata.dtype().is(py::dtype::of())) { return self.tensor(info.ptr, flatdata.size(), sizeof(bool), kp::Tensor::TensorDataTypes::eBool, tensor_type); } else { throw std::runtime_error( "Kompute Python no valid dtype supported"); } }, DOC(kp, Manager, tensorT), py::arg("data"), py::arg("tensor_type") = kp::Tensor::TensorTypes::eDevice) .def( "algorithm", [](kp::Manager& self, const std::vector>& tensors, const py::bytes& spirv, const kp::Workgroup& workgroup, const std::vector& spec_consts, const std::vector& push_consts) { py::buffer_info info(py::buffer(spirv).request()); const char* data = reinterpret_cast(info.ptr); size_t length = static_cast(info.size); std::vector spirvVec((uint32_t*)data, (uint32_t*)(data + length)); return self.algorithm( tensors, spirvVec, workgroup, spec_consts, push_consts); }, DOC(kp, Manager, algorithm), py::arg("tensors"), py::arg("spirv"), py::arg("workgroup") = kp::Workgroup(), py::arg("spec_consts") = std::vector(), py::arg("push_consts") = std::vector()) .def( "algorithm", [np](kp::Manager& self, const std::vector>& tensors, const py::bytes& spirv, const kp::Workgroup& workgroup, const py::array& spec_consts, const py::array& push_consts) { py::buffer_info info(py::buffer(spirv).request()); const char* data = reinterpret_cast(info.ptr); size_t length = static_cast(info.size); std::vector spirvVec((uint32_t*)data, (uint32_t*)(data + length)); const py::buffer_info pushInfo = push_consts.request(); const py::buffer_info specInfo = spec_consts.request(); KP_LOG_DEBUG("Kompute Python Manager creating Algorithm_T with " "push consts data size {} dtype {} and spec const " "data size {} dtype {}", push_consts.size(), std::string(py::str(push_consts.dtype())), spec_consts.size(), std::string(py::str(spec_consts.dtype()))); // We have to iterate across a combination of parameters due to the // lack of support for templating if (spec_consts.dtype().is(py::dtype::of())) { std::vector specConstsVec( (float*)specInfo.ptr, ((float*)specInfo.ptr) + specInfo.size); if (spec_consts.dtype().is(py::dtype::of())) { std::vector pushConstsVec((float*)pushInfo.ptr, ((float*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specConstsVec, pushConstsVec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushConstsVec( (int32_t*)pushInfo.ptr, ((int32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specConstsVec, pushConstsVec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushConstsVec( (uint32_t*)pushInfo.ptr, ((uint32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specConstsVec, pushConstsVec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushConstsVec((double*)pushInfo.ptr, ((double*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specConstsVec, pushConstsVec); } } else if (spec_consts.dtype().is(py::dtype::of())) { std::vector specconstsvec((int32_t*)specInfo.ptr, ((int32_t*)specInfo.ptr) + specInfo.size); if (spec_consts.dtype().is(py::dtype::of())) { std::vector pushconstsvec((float*)pushInfo.ptr, ((float*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec( (int32_t*)pushInfo.ptr, ((int32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec( (uint32_t*)pushInfo.ptr, ((uint32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec((double*)pushInfo.ptr, ((double*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } } else if (spec_consts.dtype().is(py::dtype::of())) { std::vector specconstsvec((uint32_t*)specInfo.ptr, ((uint32_t*)specInfo.ptr) + specInfo.size); if (spec_consts.dtype().is(py::dtype::of())) { std::vector pushconstsvec((float*)pushInfo.ptr, ((float*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec( (int32_t*)pushInfo.ptr, ((int32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec( (uint32_t*)pushInfo.ptr, ((uint32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec((double*)pushInfo.ptr, ((double*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } } else if (spec_consts.dtype().is(py::dtype::of())) { std::vector specconstsvec((double*)specInfo.ptr, ((double*)specInfo.ptr) + specInfo.size); if (spec_consts.dtype().is(py::dtype::of())) { std::vector pushconstsvec((float*)pushInfo.ptr, ((float*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec((int32_t*)pushInfo.ptr, ((int32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec((uint32_t*)pushInfo.ptr, ((uint32_t*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } else if (spec_consts.dtype().is( py::dtype::of())) { std::vector pushconstsvec((double*)pushInfo.ptr, ((double*)pushInfo.ptr) + pushInfo.size); return self.algorithm(tensors, spirvVec, workgroup, specconstsvec, pushconstsvec); } } // If reach then no valid dtype supported throw std::runtime_error("Kompute Python no valid dtype supported"); }, DOC(kp, Manager, algorithm), py::arg("tensors"), py::arg("spirv"), py::arg("workgroup") = kp::Workgroup(), py::arg("spec_consts") = std::vector(), py::arg("push_consts") = std::vector()) .def( "list_devices", [](kp::Manager& self) { const std::vector devices = self.listDevices(); py::list list; for (const vk::PhysicalDevice& device : devices) { list.append(kp::py::vkPropertiesToDict(device.getProperties())); } return list; }, "Return a dict containing information about the device") .def( "get_device_properties", [](kp::Manager& self) { const vk::PhysicalDeviceProperties properties = self.getDeviceProperties(); return kp::py::vkPropertiesToDict(properties); }, "Return a dict containing information about the device"); auto atexit = py::module_::import("atexit"); atexit.attr("register")(py::cpp_function([]() { kp_trace = py::none(); kp_debug = py::none(); kp_info = py::none(); kp_warning = py::none(); kp_error = py::none(); })); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; #else m.attr("__version__") = "dev"; #endif }