#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 class remote_data final { private: /** * An identifier to the data being held on the remote */ id data_id_; /** * The sycl queue object */ cl::sycl::queue* queue_; public: /** * Main constructor */ remote_data(id 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& id, id_map& map, cl::sycl::queue& queue__): id_{id}, map_{&map} {} */ /** * Wait for the data */ error_or> wait(){ return make_error(); } /** * Request data asynchronously */ // conveyor> on_receive(); /// Stopped here }; /** * Meant to be a helper object which holds the allocated data on the sycl side */ //template //class device_data; /** * This class helps in regards to the ownership on the server side template class device_data { private: data* device_data_; cl::sycl::queue* queue_; public: device_data(data& 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 struct rpc_func_type_helper; template struct rpc_func_type_helper>{ using type = tmpl_group; }; template struct rpc_iface_type_helper { using type = tmpl_group<>; }; template struct rpc_iface_type_helper,schema::Member...>> { using inner_type = typename rpc_func_type_helper::type; using type = typename tmpl_concat...>>::type>::type; }; } /** * Rpc Client class for the Sycl backend. */ template class rpc_client { public: private: /** * Server this client is tied to */ rpc_server* srv_; /** * TransferClient created from the internal RPC data server */ data_client::type, Encoding, rmt::Hip> data_client_; /** * Generated some sort of id for the request. */ public: rpc_client(rpc_server& srv): srv_{&srv}, data_client_{srv_->data_server} {} /** * Rpc call */ template error_or< id< typename schema_member_type::type::ResponseT > > call(const data_or_id::type::RequestT, Encoding>& input){ auto next_free_id = srv_->template next_free_id::type::ResponseT>(); return srv_->template call(input, next_free_id); } }; /** * Rpc Server class for the Sycl backend. */ template class rpc_server { public: using InterfaceCtxT = cl::sycl::queue*; using InterfaceT = interface, InterfaceCtxT>; private: /** * Device instance enabling the use of the remote device. */ our> device_; using DataServerT = data_server::type, Encoding, rmt::Hip>; /** * Data server storing the relevant data */ DataServerT* data_server_; /** * The interface including the relevant context class. */ interface cl_interface_; public: /** * Main constructor */ rpc_server(our> 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 id next_free_id() const { return std::get>(storage_.maps).next_free_id(); } */ /** template remote_data request_data(id dat_id){ return {dat_id, std::get>(storage_.maps), device_->get_handle()}; } */ /** * Rpc call based on the name */ template error_or< id< typename schema_member_type::type::ResponseT > > call(data_or_id::type::RequestT, Encoding> input, id::type::ResponseT> rpc_id){ using FuncT = typename schema_member_type::type; /** * Object needed if and only if the provided data type is not an id */ own>> 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>* > { if(input.is_id()){ // storage_.maps auto eov = data_server_->template find(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>>(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(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::type::RequestT>(std::move(val), rpc_id); if(eoid.is_error()){ return std::move(eoid.get_error()); } return rpc_id; } }; }