diff options
author | Claudius 'keldu' Holeksa <mail@keldu.de> | 2024-08-16 16:38:09 +0200 |
---|---|---|
committer | Claudius 'keldu' Holeksa <mail@keldu.de> | 2024-08-16 16:38:09 +0200 |
commit | 4acbc19774d48b339820e91b7c9226ed2e6f12b5 (patch) | |
tree | 145ed1794f5fcac02a357e18e108b544b3747fc2 /modules | |
parent | 9f81ab07be7ee549f5f851128e4d6a03289833ea (diff) |
Separating the remote part from the rpc part
Diffstat (limited to 'modules')
-rw-r--r-- | modules/remote-sycl/c++/remote.hpp | 271 | ||||
-rw-r--r-- | modules/remote-sycl/c++/rpc.hpp | 276 |
2 files changed, 276 insertions, 271 deletions
diff --git a/modules/remote-sycl/c++/remote.hpp b/modules/remote-sycl/c++/remote.hpp index 8ec4667..fe13612 100644 --- a/modules/remote-sycl/c++/remote.hpp +++ b/modules/remote-sycl/c++/remote.hpp @@ -1,277 +1,6 @@ #pragma once -#include "common.hpp" -#include "data.hpp" -#include "device.hpp" -#include "transfer.hpp" - namespace saw { -/** - * Remote data class for the Sycl backend. - */ -template<typename T, typename Encoding, typename Storage> -class remote_data<T, Encoding, Storage, rmt::Sycl> final { -private: - /** - * An identifier to the data being held on the remote - */ - id<T> data_id_; - - /** - * The sycl queue object - */ - cl::sycl::queue* queue_; -public: - /** - * Main constructor - */ - remote_data(id<T> data_id__, cl::sycl::queue& queue__): - data_id_{data_id__}, - queue_{&queue__} - {} - - /** - * Destructor specifically designed to deallocate on the device. - */ - ~remote_data(){} - - SAW_FORBID_COPY(remote_data); - SAW_FORBID_MOVE(remote_data); - /** - remote_data(const id<T>& id, id_map<T, Encoding, rmt::Sycl>& map, cl::sycl::queue& queue__): - id_{id}, - map_{&map} - {} - */ - - /** - * Wait for the data - */ - error_or<data<T,Encoding,Storage>> wait(){ - return make_error<err::not_implemented>(); - } - - /** - * Request data asynchronously - */ - // conveyor<data<T,Encoding,Storage>> on_receive(); /// Stopped here -}; - -/** - * Meant to be a helper object which holds the allocated data on the sycl side - */ -//template<typename Schema, typename Encoding, typename Backend> -//class device_data; - -/** - * This class helps in regards to the ownership on the server side -template<typename Schema, typename Encoding> -class device_data<Schema, Encoding, rmt::Sycl> { -private: - data<Schema,Encoding,storage::Default>* device_data_; - cl::sycl::queue* queue_; -public: - device_data(data<Schema,Encoding,storage::Default>& device_data__, cl::sycl::queue& queue__): - device_data_{&device_data__}, - queue_{&queue__} - {} - - ~device_data(){ - if(device_data_){ - cl::sycl::free(device_data_,queue_); - device_data_ = nullptr; - } - } - - SAW_FORBID_COPY(device_data); - SAW_FORBID_MOVE(device_data); -}; - */ - -} -// Maybe a helper impl tmpl file? -namespace saw { - - -namespace impl { -template<typename Func> -struct rpc_func_type_helper; - -template<typename Response, typename Request> -struct rpc_func_type_helper<schema::Function<Request, Response>>{ - using type = tmpl_group<Response, Request>; -}; - -template<typename Iface> -struct rpc_iface_type_helper { - using type = tmpl_group<>; -}; - -template<typename Func, string_literal K, typename... Functions, string_literal... Keys> -struct rpc_iface_type_helper<schema::Interface<schema::Member<Func,K>,schema::Member<Functions,Keys>...>> { - using inner_type = typename rpc_func_type_helper<Func>::type; - using type = typename tmpl_concat<inner_type, typename rpc_iface_type_helper<schema::Interface<schema::Member<Functions,Keys>...>>::type>::type; -}; -} - -/** - * Rpc Client class for the Sycl backend. - */ -template<typename Iface, typename Encoding, typename Storage> -class rpc_client<Iface, Encoding, Storage, rmt::Sycl> { -public: -private: - /** - * Server this client is tied to - */ - rpc_server<Iface, Encoding, Storage, rmt::Sycl>* srv_; - - /** - * TransferClient created from the internal RPC data server - */ - data_client<typename impl::rpc_iface_type_helper<Iface>::type, Encoding, rmt::Sycl> data_client_; - - /** - * Generated some sort of id for the request. - */ -public: - rpc_client(rpc_server<Iface, Encoding, Storage, rmt::Sycl>& srv): - srv_{&srv}, - data_client_{srv_->data_server} - {} - - /** - * Rpc call - */ - template<string_literal Name> - error_or< - id< - typename schema_member_type<Name, Iface>::type::ResponseT - > - > call(const data_or_id<typename schema_member_type<Name, Iface>::type::RequestT, Encoding, Storage>& input){ - auto next_free_id = srv_->template next_free_id<typename schema_member_type<Name, Iface>::type::ResponseT>(); - return srv_->template call<Name, Storage>(input, next_free_id); - } - -}; - -/** - * Rpc Server class for the Sycl backend. - */ -template<typename Iface, typename Encoding> -class rpc_server<Iface, Encoding, storage::Default, rmt::Sycl> { -public: - using InterfaceCtxT = cl::sycl::queue*; - using InterfaceT = interface<Iface, Encoding, storage::Default, InterfaceCtxT>; - -private: - /** - * Device instance enabling the use of the remote device. - */ - our<device<rmt::Sycl>> device_; - - using DataServerT = data_server<typename impl::rpc_iface_type_helper<Iface>::type, Encoding, rmt::Sycl>; - /** - * Data server storing the relevant data - */ - DataServerT* data_server_; - - /** - * The interface including the relevant context class. - */ - interface<Iface, Encoding, storage::Default, InterfaceCtxT> cl_interface_; - -public: - - /** - * Main constructor - */ - rpc_server(our<device<rmt::Sycl>> dev__, DataServerT& data_server__, InterfaceT cl_iface): - device_{std::move(dev__)}, - data_server_{&data_server__}, - cl_interface_{std::move(cl_iface)} - {} - - /** - * Ask which id the server prefers as the next one. Only available for fast requests on no roundtrip setups. - */ - /** - template<typename T> - id<T> next_free_id() const { - return std::get<id_map<T,Encoding,rmt::Sycl>>(storage_.maps).next_free_id(); - } - */ - - /** - template<typename IdT, typename Storage> - remote_data<IdT, Encoding, Storage, rmt::Sycl> request_data(id<IdT> dat_id){ - return {dat_id, std::get<id_map<IdT,Encoding,rmt::Sycl>>(storage_.maps), device_->get_handle()}; - } - */ - - /** - * Rpc call based on the name - */ - template<string_literal Name> - error_or< - id< - typename schema_member_type<Name, Iface>::type::ResponseT - > - > call(data_or_id<typename schema_member_type<Name, Iface>::type::RequestT, Encoding, storage::Default> input, id<typename schema_member_type<Name,Iface>::type::ResponseT> rpc_id){ - using FuncT = typename schema_member_type<Name, Iface>::type; - - /** - * Object needed if and only if the provided data type is not an id - */ - own<data<typename FuncT::RequestT, Encoding, rmt::Sycl>> dev_tmp_inp = nullptr; - /** - * First check if it's data or an id. - * If it's an id, check if it's registered within the storage and retrieve it. - */ - auto eoinp = [&,this]() -> error_or<data<typename FuncT::RequestT, Encoding, rmt::Sycl>* > { - if(input.is_id()){ - // storage_.maps - auto eov = data_server_->template find<typename FuncT::RequestT>(input.get_id()); - if(eov.is_error()){ - return std::move(eov.get_error()); - } - return eov.get_value(); - } else { - auto& client_data = input.get_data(); - - auto eov = device_->template copy_to_device(client_data); - if(eov.is_error()){ - return std::move(eov.get_error()); - } - auto& val = eov.get_value(); - - dev_tmp_inp = heap<data<typename FuncT::RequestT, Encoding, rmt::Sycl>>(std::move(val)); - device_->get_handle().wait(); - return dev_tmp_inp.get(); - } - }(); - if(eoinp.is_error()){ - return std::move(eoinp.get_error()); - } - auto& inp = *(eoinp.get_value()); - - auto eod = cl_interface_.template call<Name>(inp, &(device_->get_handle())); - - if(eod.is_error()){ - return std::move(eod.get_error()); - } - - auto& val = eod.get_value(); - /** - * Store returned data in rpc storage - */ - auto eoid = data_server_->template insert<typename schema_member_type<Name, Iface>::type::RequestT>(std::move(val), rpc_id); - if(eoid.is_error()){ - return std::move(eoid.get_error()); - } - return rpc_id; - } -}; template<> struct remote_address<rmt::Sycl> { diff --git a/modules/remote-sycl/c++/rpc.hpp b/modules/remote-sycl/c++/rpc.hpp new file mode 100644 index 0000000..780f7a0 --- /dev/null +++ b/modules/remote-sycl/c++/rpc.hpp @@ -0,0 +1,276 @@ +#pragma once + +#include "common.hpp" +#include "remote.hpp" +#include "data.hpp" +#include "device.hpp" +#include "transfer.hpp" + +namespace saw { +/** + * Remote data class for the Sycl backend. + */ +template<typename T, typename Encoding, typename Storage> +class remote_data<T, Encoding, Storage, rmt::Sycl> final { +private: + /** + * An identifier to the data being held on the remote + */ + id<T> data_id_; + + /** + * The sycl queue object + */ + cl::sycl::queue* queue_; +public: + /** + * Main constructor + */ + remote_data(id<T> data_id__, cl::sycl::queue& queue__): + data_id_{data_id__}, + queue_{&queue__} + {} + + /** + * Destructor specifically designed to deallocate on the device. + */ + ~remote_data(){} + + SAW_FORBID_COPY(remote_data); + SAW_FORBID_MOVE(remote_data); + /** + remote_data(const id<T>& id, id_map<T, Encoding, rmt::Sycl>& map, cl::sycl::queue& queue__): + id_{id}, + map_{&map} + {} + */ + + /** + * Wait for the data + */ + error_or<data<T,Encoding,Storage>> wait(){ + return make_error<err::not_implemented>(); + } + + /** + * Request data asynchronously + */ + // conveyor<data<T,Encoding,Storage>> on_receive(); /// Stopped here +}; + +/** + * Meant to be a helper object which holds the allocated data on the sycl side + */ +//template<typename Schema, typename Encoding, typename Backend> +//class device_data; + +/** + * This class helps in regards to the ownership on the server side +template<typename Schema, typename Encoding> +class device_data<Schema, Encoding, rmt::Sycl> { +private: + data<Schema,Encoding,storage::Default>* device_data_; + cl::sycl::queue* queue_; +public: + device_data(data<Schema,Encoding,storage::Default>& device_data__, cl::sycl::queue& queue__): + device_data_{&device_data__}, + queue_{&queue__} + {} + + ~device_data(){ + if(device_data_){ + cl::sycl::free(device_data_,queue_); + device_data_ = nullptr; + } + } + + SAW_FORBID_COPY(device_data); + SAW_FORBID_MOVE(device_data); +}; + */ + +} +// Maybe a helper impl tmpl file? +namespace saw { + + +namespace impl { +template<typename Func> +struct rpc_func_type_helper; + +template<typename Response, typename Request> +struct rpc_func_type_helper<schema::Function<Request, Response>>{ + using type = tmpl_group<Response, Request>; +}; + +template<typename Iface> +struct rpc_iface_type_helper { + using type = tmpl_group<>; +}; + +template<typename Func, string_literal K, typename... Functions, string_literal... Keys> +struct rpc_iface_type_helper<schema::Interface<schema::Member<Func,K>,schema::Member<Functions,Keys>...>> { + using inner_type = typename rpc_func_type_helper<Func>::type; + using type = typename tmpl_concat<inner_type, typename rpc_iface_type_helper<schema::Interface<schema::Member<Functions,Keys>...>>::type>::type; +}; +} + +/** + * Rpc Client class for the Sycl backend. + */ +template<typename Iface, typename Encoding, typename Storage> +class rpc_client<Iface, Encoding, Storage, rmt::Sycl> { +public: +private: + /** + * Server this client is tied to + */ + rpc_server<Iface, Encoding, Storage, rmt::Sycl>* srv_; + + /** + * TransferClient created from the internal RPC data server + */ + data_client<typename impl::rpc_iface_type_helper<Iface>::type, Encoding, rmt::Sycl> data_client_; + + /** + * Generated some sort of id for the request. + */ +public: + rpc_client(rpc_server<Iface, Encoding, Storage, rmt::Sycl>& srv): + srv_{&srv}, + data_client_{srv_->data_server} + {} + + /** + * Rpc call + */ + template<string_literal Name> + error_or< + id< + typename schema_member_type<Name, Iface>::type::ResponseT + > + > call(const data_or_id<typename schema_member_type<Name, Iface>::type::RequestT, Encoding, Storage>& input){ + auto next_free_id = srv_->template next_free_id<typename schema_member_type<Name, Iface>::type::ResponseT>(); + return srv_->template call<Name, Storage>(input, next_free_id); + } + +}; + +/** + * Rpc Server class for the Sycl backend. + */ +template<typename Iface, typename Encoding> +class rpc_server<Iface, Encoding, storage::Default, rmt::Sycl> { +public: + using InterfaceCtxT = cl::sycl::queue*; + using InterfaceT = interface<Iface, Encoding, storage::Default, InterfaceCtxT>; + +private: + /** + * Device instance enabling the use of the remote device. + */ + our<device<rmt::Sycl>> device_; + + using DataServerT = data_server<typename impl::rpc_iface_type_helper<Iface>::type, Encoding, rmt::Sycl>; + /** + * Data server storing the relevant data + */ + DataServerT* data_server_; + + /** + * The interface including the relevant context class. + */ + interface<Iface, Encoding, storage::Default, InterfaceCtxT> cl_interface_; + +public: + + /** + * Main constructor + */ + rpc_server(our<device<rmt::Sycl>> dev__, DataServerT& data_server__, InterfaceT cl_iface): + device_{std::move(dev__)}, + data_server_{&data_server__}, + cl_interface_{std::move(cl_iface)} + {} + + /** + * Ask which id the server prefers as the next one. Only available for fast requests on no roundtrip setups. + */ + /** + template<typename T> + id<T> next_free_id() const { + return std::get<id_map<T,Encoding,rmt::Sycl>>(storage_.maps).next_free_id(); + } + */ + + /** + template<typename IdT, typename Storage> + remote_data<IdT, Encoding, Storage, rmt::Sycl> request_data(id<IdT> dat_id){ + return {dat_id, std::get<id_map<IdT,Encoding,rmt::Sycl>>(storage_.maps), device_->get_handle()}; + } + */ + + /** + * Rpc call based on the name + */ + template<string_literal Name> + error_or< + id< + typename schema_member_type<Name, Iface>::type::ResponseT + > + > call(data_or_id<typename schema_member_type<Name, Iface>::type::RequestT, Encoding, storage::Default> input, id<typename schema_member_type<Name,Iface>::type::ResponseT> rpc_id){ + using FuncT = typename schema_member_type<Name, Iface>::type; + + /** + * Object needed if and only if the provided data type is not an id + */ + own<data<typename FuncT::RequestT, Encoding, rmt::Sycl>> dev_tmp_inp = nullptr; + /** + * First check if it's data or an id. + * If it's an id, check if it's registered within the storage and retrieve it. + */ + auto eoinp = [&,this]() -> error_or<data<typename FuncT::RequestT, Encoding, rmt::Sycl>* > { + if(input.is_id()){ + // storage_.maps + auto eov = data_server_->template find<typename FuncT::RequestT>(input.get_id()); + if(eov.is_error()){ + return std::move(eov.get_error()); + } + return eov.get_value(); + } else { + auto& client_data = input.get_data(); + + auto eov = device_->template copy_to_device(client_data); + if(eov.is_error()){ + return std::move(eov.get_error()); + } + auto& val = eov.get_value(); + + dev_tmp_inp = heap<data<typename FuncT::RequestT, Encoding, rmt::Sycl>>(std::move(val)); + device_->get_handle().wait(); + return dev_tmp_inp.get(); + } + }(); + if(eoinp.is_error()){ + return std::move(eoinp.get_error()); + } + auto& inp = *(eoinp.get_value()); + + auto eod = cl_interface_.template call<Name>(inp, &(device_->get_handle())); + + if(eod.is_error()){ + return std::move(eod.get_error()); + } + + auto& val = eod.get_value(); + /** + * Store returned data in rpc storage + */ + auto eoid = data_server_->template insert<typename schema_member_type<Name, Iface>::type::RequestT>(std::move(val), rpc_id); + if(eoid.is_error()){ + return std::move(eoid.get_error()); + } + return rpc_id; + } +}; +} |