File indexing completed on 2025-09-17 08:54:12
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <memory>
0010
0011 #include <covfie/core/backend/primitive/array.hpp>
0012 #include <covfie/core/concepts.hpp>
0013 #include <covfie/core/qualifiers.hpp>
0014 #include <covfie/core/vector.hpp>
0015 #include <covfie/sycl/utility/memory.hpp>
0016 #include <covfie/sycl/utility/unique_ptr.hpp>
0017
0018 namespace covfie::backend {
0019 template <
0020 concepts::vector_descriptor _output_vector_t,
0021 typename _index_t = std::size_t>
0022 struct sycl_device_array {
0023 using this_t = sycl_device_array<_output_vector_t, _index_t>;
0024
0025 static constexpr bool is_initial = true;
0026
0027 using contravariant_input_t =
0028 covfie::vector::scalar_d<covfie::vector::vector_d<_index_t, 1>>;
0029 using covariant_output_t =
0030 covfie::vector::array_reference_vector_d<_output_vector_t>;
0031
0032 using output_vector_t = _output_vector_t;
0033
0034 using value_t = typename output_vector_t::type[output_vector_t::size];
0035 using vector_t = std::decay_t<typename covariant_output_t::vector_t>;
0036
0037 using configuration_t = utility::nd_size<1>;
0038
0039 static constexpr uint32_t IO_MAGIC_HEADER = 0xAB210000;
0040
0041 struct owning_data_t {
0042 using parent_t = this_t;
0043
0044 owning_data_t() = delete;
0045
0046 owning_data_t(::sycl::queue & queue)
0047 : m_size(0)
0048 , m_queue(queue)
0049 , m_ptr({})
0050 {
0051 }
0052
0053 owning_data_t(owning_data_t &&) = default;
0054 owning_data_t & operator=(owning_data_t &&) = default;
0055
0056 owning_data_t & operator=(const owning_data_t & o)
0057 {
0058 m_size = o.m_size;
0059 m_ptr.reset();
0060 m_queue = o.m_queue;
0061 m_ptr =
0062 utility::sycl::device_copy_d2d(o.m_ptr.get(), m_size, m_queue);
0063
0064 return *this;
0065 }
0066
0067 owning_data_t(const owning_data_t & o)
0068 : m_size(o.m_size)
0069 , m_queue(o.m_queue)
0070 , m_ptr(
0071 utility::sycl::device_copy_d2d(o.m_ptr.get(), m_size, m_queue)
0072 )
0073 {
0074 assert(m_size == 0 || m_ptr);
0075
0076 if (o.m_ptr && m_size > 0) {
0077 std::memcpy(
0078 m_ptr.get(), o.m_ptr.get(), m_size * sizeof(vector_t)
0079 );
0080 }
0081 }
0082
0083 explicit owning_data_t(parameter_pack<owning_data_t> && args)
0084 : owning_data_t(std::move(args.x))
0085 {
0086 }
0087
0088
0089 explicit owning_data_t(parameter_pack<configuration_t> && args)
0090 : m_size(args.x[0])
0091 , m_ptr(utility::sycl::device_allocate<vector_t[]>(m_size, m_queue))
0092 {
0093 }
0094
0095 explicit owning_data_t(
0096 std::size_t size,
0097 std::unique_ptr<vector_t[]> && ptr,
0098 ::sycl::queue & queue
0099 )
0100 : m_size(size)
0101 , m_queue(queue)
0102 , m_ptr(utility::sycl::device_copy_h2d(ptr.get(), size, m_queue))
0103 {
0104 }
0105
0106 template <typename B>
0107 requires(!std::same_as<B, owning_data_t> && concepts::array_1d_like_field_backend<typename B::parent_t>) explicit owning_data_t(
0108 const B & o, ::sycl::queue & queue
0109 )
0110 : owning_data_t(o.get_size(), o.get_host_array(), queue)
0111 {
0112 }
0113
0114 configuration_t get_configuration() const
0115 {
0116 return {m_size};
0117 }
0118
0119 static owning_data_t read_binary(std::istream & fs)
0120 {
0121 utility::read_io_header(fs, IO_MAGIC_HEADER);
0122
0123 uint32_t float_width = utility::read_binary<uint32_t>(fs);
0124
0125 if (float_width != 4 && float_width != 8) {
0126 throw std::runtime_error(
0127 "Float type is neither IEEE 754 single- nor "
0128 "double-precision, binary input is not supported."
0129 );
0130 }
0131
0132 auto size =
0133 utility::read_binary<std::decay_t<decltype(m_size)>>(fs);
0134 std::unique_ptr<vector_t[]> ptr =
0135 std::make_unique<vector_t[]>(size);
0136
0137 for (std::size_t i = 0; i < size; ++i) {
0138 for (std::size_t j = 0; j < _output_vector_t::size; ++j) {
0139 if (float_width == 4) {
0140 ptr[i][j] = utility::read_binary<float>(fs);
0141 } else if (float_width == 8) {
0142 ptr[i][j] = utility::read_binary<double>(fs);
0143 } else {
0144 throw std::logic_error("Float width is unexpected.");
0145 }
0146 }
0147 }
0148
0149 utility::read_io_footer(fs, IO_MAGIC_HEADER);
0150
0151 return owning_data_t(size, std::move(ptr));
0152 }
0153
0154 static void write_binary(std::ostream & fs, const owning_data_t & o)
0155 {
0156 utility::write_io_header(fs, IO_MAGIC_HEADER);
0157
0158 uint32_t float_width;
0159
0160 if constexpr (std::
0161 is_same_v<typename _output_vector_t::type, float>)
0162 {
0163 float_width = 4;
0164 } else if constexpr (std::is_same_v<
0165 typename _output_vector_t::type,
0166 double>)
0167 {
0168 float_width = 8;
0169 } else {
0170 throw std::logic_error(
0171 "Float type is neither IEEE 754 single- nor "
0172 "double-precision, binary output is not supported."
0173 );
0174 }
0175
0176 fs.write(
0177 reinterpret_cast<const char *>(&float_width),
0178 sizeof(std::decay_t<decltype(float_width)>)
0179 );
0180
0181 fs.write(
0182 reinterpret_cast<const char *>(&o.m_size),
0183 sizeof(std::decay_t<decltype(o.m_size)>)
0184 );
0185
0186 for (std::size_t i = 0; i < o.m_size; ++i) {
0187 for (std::size_t j = 0; j < _output_vector_t::size; ++j) {
0188 fs.write(
0189 reinterpret_cast<const char *>(&o.m_ptr[i][j]),
0190 sizeof(typename _output_vector_t::type)
0191 );
0192 }
0193 }
0194
0195 utility::write_io_footer(fs, IO_MAGIC_HEADER);
0196 }
0197
0198 std::size_t m_size;
0199 ::sycl::queue m_queue;
0200 utility::sycl::unique_device_ptr<vector_t[]> m_ptr;
0201 };
0202
0203 struct non_owning_data_t {
0204 using parent_t = this_t;
0205
0206 non_owning_data_t(const owning_data_t & o)
0207 : m_ptr(o.m_ptr.get())
0208 {
0209 }
0210
0211 COVFIE_HOST_DEVICE typename covariant_output_t::vector_t
0212 at(typename contravariant_input_t::vector_t i) const
0213 {
0214 return m_ptr[i];
0215 }
0216
0217 vector_t * m_ptr;
0218 };
0219 };
0220 }