diff --git a/include/aidge/aidge.hpp b/include/aidge/aidge.hpp index cc0979b07b07c2b95515eda09fda68a9ec4ac63e..a2eed39c038e248b0c0b0d98b5ee625b304bc34a 100644 --- a/include/aidge/aidge.hpp +++ b/include/aidge/aidge.hpp @@ -15,6 +15,8 @@ #include "aidge/backend/OperatorImpl.hpp" #include "aidge/backend/TensorImpl.hpp" +#include "aidge/backend/cpu/data/TensorImpl.hpp" + #include "aidge/data/Data.hpp" #include "aidge/data/Tensor.hpp" diff --git a/include/aidge/backend/cpu/data/GetCPUPtr.h b/include/aidge/backend/cpu/data/GetCPUPtr.h new file mode 100644 index 0000000000000000000000000000000000000000..47e3b07e8fa08cdcd714745a9a49bb03e30f79f5 --- /dev/null +++ b/include/aidge/backend/cpu/data/GetCPUPtr.h @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_DATA_GETCPUPTR_H_ +#define AIDGE_CPU_DATA_GETCPUPTR_H_ + +#include "aidge/data/Tensor.hpp" + +namespace Aidge { +inline void *getCPUPtr(std::shared_ptr<Aidge::Data> const &data) { + const auto tensor = std::static_pointer_cast<Tensor>(data); + return tensor->getImpl()->hostPtr(tensor->getImplOffset()); +} +} // namespace Aidge + +#endif // AIDGE_CPU_DATA_GETCPUPTR_H_ \ No newline at end of file diff --git a/include/aidge/backend/cpu/data/TensorImpl.hpp b/include/aidge/backend/cpu/data/TensorImpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..46dfae3d53b4b201507290bd538ea13737919c3e --- /dev/null +++ b/include/aidge/backend/cpu/data/TensorImpl.hpp @@ -0,0 +1,193 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_DATA_TENSORIMPL_H_ +#define AIDGE_CPU_DATA_TENSORIMPL_H_ + +#include "aidge/backend/TensorImpl.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/data/half.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/future_std/span.hpp" + +namespace Aidge { + +template <class T> +class TensorImpl_cpu : public TensorImpl { +private: + /// Pointer to the data and its capacity + future_std::span<T> mData; + /// If this instance own the data, std::unique_ptr manages it + std::unique_ptr<T[]> mDataOwner; + +public: + static constexpr const char *Backend = "cpu"; + + TensorImpl_cpu(DeviceIdx_t device, NbElts_t length) : TensorImpl(Backend, device, length) {} + + bool operator==(const TensorImpl &otherImpl) const override final { + const auto& typedOtherImpl = reinterpret_cast<const TensorImpl_cpu<T> &>(otherImpl); + AIDGE_INTERNAL_ASSERT(typedOtherImpl.size() >= mNbElts); + + std::size_t i = 0; + for (; i < mNbElts && + *(mData.data()+i) == *static_cast<const T*>(typedOtherImpl.rawPtr(i)); + ++i) { + } + return i == mNbElts; + } + + static std::shared_ptr<TensorImpl_cpu> create(DeviceIdx_t device, NbElts_t length) { + return std::make_shared<TensorImpl_cpu<T>>(device, length); + } + + inline std::size_t scalarSize() const noexcept override final { return sizeof(T); } + + void copy(const void *src, NbElts_t length, NbElts_t offset = 0) override final { + const T* srcT = static_cast<const T *>(src); + T* dstT = static_cast<T *>(rawPtr(offset)); + + AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity"); + AIDGE_ASSERT(dstT < srcT || dstT >= srcT + length, "overlapping copy is not supported"); + std::copy(srcT, srcT + length, dstT); + } + + void copyCast(const void *src, const DataType srcDt, NbElts_t length, NbElts_t offset = 0) override final { + if (length == 0) { + return; + } + + T* dstT = static_cast<T *>(rawPtr(offset)); + AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity"); + switch (srcDt) + { + case DataType::Float64: + std::copy(static_cast<const double*>(src), static_cast<const double*>(src) + length, + dstT); + break; + case DataType::Float32: + std::copy(static_cast<const float*>(src), static_cast<const float*>(src) + length, + dstT); + break; + case DataType::Float16: + std::copy(static_cast<const half_float::half*>(src), static_cast<const half_float::half*>(src) + length, + dstT); + break; + case DataType::Int64: + std::copy(static_cast<const int64_t*>(src), static_cast<const int64_t*>(src) + length, + dstT); + break; + case DataType::UInt64: + std::copy(static_cast<const uint64_t*>(src), static_cast<const uint64_t*>(src) + length, + dstT); + break; + case DataType::Int32: + std::copy(static_cast<const int32_t*>(src), static_cast<const int32_t*>(src) + length, + dstT); + break; + case DataType::UInt32: + std::copy(static_cast<const uint32_t*>(src), static_cast<const uint32_t*>(src) + length, + dstT); + break; + case DataType::Int16: + std::copy(static_cast<const int16_t*>(src), static_cast<const int16_t*>(src) + length, + dstT); + break; + case DataType::UInt16: + std::copy(static_cast<const uint16_t*>(src), static_cast<const uint16_t*>(src) + length, + dstT); + break; + case DataType::Int8: + std::copy(static_cast<const int8_t*>(src), static_cast<const int8_t*>(src) + length, + dstT); + break; + case DataType::UInt8: + std::copy(static_cast<const uint8_t*>(src), static_cast<const uint8_t*>(src) + length, + dstT); + break; + default: + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsupported data type."); + break; + } + } + + void copyFromDevice(const void *src, const std::pair<std::string, DeviceIdx_t>& device, NbElts_t length, NbElts_t offset = 0) override final { + AIDGE_ASSERT(device.first == Backend, "backend must match"); + AIDGE_ASSERT(device.second == 0, "device cannot be != 0 for CPU backend"); + copy(src, length, offset); + } + + inline void copyFromHost(const void *src, NbElts_t length, NbElts_t offset = 0) override final { + copy(src, length, offset); + } + + void copyToHost(void *dst, NbElts_t length, NbElts_t offset = 0) const override final { + const T* src = static_cast<const T*>(rawPtr(offset)); + AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity"); + std::copy(src, src + length, static_cast<T *>(dst)); + } + + void *rawPtr(NbElts_t offset = 0) override final { + lazyInit(); + return (mData.data() + offset); + }; + + const void *rawPtr(NbElts_t offset = 0) const override final { + AIDGE_ASSERT(mData.size() >= mNbElts, "accessing uninitialized const rawPtr"); + return (mData.data() + offset); + }; + + void *hostPtr(NbElts_t offset = 0) override final { + lazyInit(); + return (mData.data() + offset); + }; + + const void *hostPtr(NbElts_t offset = 0) const override final { + AIDGE_ASSERT(mData.size() >= mNbElts, "accessing uninitialized const hostPtr"); + return (mData.data() + offset); + }; + + void setRawPtr(void *ptr, NbElts_t length) override final { + AIDGE_ASSERT(length >= mNbElts, "trying to set raw pointer of insufficient capacity"); + mData = future_std::span<T>(static_cast<T *>(ptr), length); + mDataOwner.reset(); + }; + + virtual ~TensorImpl_cpu() = default; + +private: + void lazyInit() { + if (mData.size() < mNbElts) { + // Need more data, a re-allocation will occur + AIDGE_ASSERT(mData.empty() || mDataOwner != nullptr, "trying to enlarge non-owned data"); + mDataOwner.reset(new T[mNbElts]); + mData = future_std::span<T>(mDataOwner.get(), mNbElts); + } + } +}; + +namespace { +static Registrar<Tensor> registrarTensorImpl_cpu_Float64( + {"cpu", DataType::Float64}, Aidge::TensorImpl_cpu<double>::create); +static Registrar<Tensor> registrarTensorImpl_cpu_Float32( + {"cpu", DataType::Float32}, Aidge::TensorImpl_cpu<float>::create); +static Registrar<Tensor> registrarTensorImpl_cpu_Float16( + {"cpu", DataType::Float16}, Aidge::TensorImpl_cpu<half_float::half>::create); +static Registrar<Tensor> registrarTensorImpl_cpu_Int32( + {"cpu", DataType::Int32}, Aidge::TensorImpl_cpu<int>::create); +static Registrar<Tensor> registrarTensorImpl_cpu_Int64( + {"cpu", DataType::Int64}, Aidge::TensorImpl_cpu<long>::create); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_DATA_TENSORIMPL_H_ */ diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp index be0d357b7f73e26aad44994f407696f70617ad71..e57b06cc5014e7159f5a3e5927aedfefb996cae4 100644 --- a/python_binding/pybind_core.cpp +++ b/python_binding/pybind_core.cpp @@ -11,6 +11,9 @@ #include <pybind11/pybind11.h> +#include "aidge/backend/cpu/data/TensorImpl.hpp" // This include add Tensor + + namespace py = pybind11; namespace Aidge {