From 60d0f8da2b754d1deb0dbb59f6e6783ba4c692c4 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Wed, 29 May 2024 21:16:06 +0200 Subject: Reworked id_map and trying to fix sycl launch --- modules/codec/c++/id_map.hpp | 164 +++++++++++++++++++++++++++++++++++++ modules/codec/tests/codec.cpp | 1 + modules/core/c++/id_map.hpp | 164 ------------------------------------- modules/core/tests/core.cpp | 27 ------ modules/io_codec/c++/rpc.hpp | 42 +++++++++- modules/remote-sycl/c++/remote.hpp | 51 +++++++++--- 6 files changed, 244 insertions(+), 205 deletions(-) create mode 100644 modules/codec/c++/id_map.hpp delete mode 100644 modules/core/c++/id_map.hpp (limited to 'modules') diff --git a/modules/codec/c++/id_map.hpp b/modules/codec/c++/id_map.hpp new file mode 100644 index 0000000..bb31846 --- /dev/null +++ b/modules/codec/c++/id_map.hpp @@ -0,0 +1,164 @@ +#pragma once + +#include +#include + +#include + +namespace saw { +/** + * Fast random access id based container. + * + * Access - O(1) + * Insert - O(1) + * Erase - O(n) ? Dunno + */ +template +class id_map final { +private: + /** + * Container which stores the primary data + */ + std::vector> data_; + /** + * Container which tracks free'd/fragmented elements within the + * main container + */ + std::deque> free_ids_; + +private: + /** + * Tries to reduce top ids + */ + void reduce_free_ids() noexcept { + for(;;){ + /** + * If we have no free ids left, we also have nothing to reduce + */ + if(free_ids_.empty()){ + break; + } + + /** + * The front contains the highest free id. + */ + if((free_ids_.front().get_value() + 1) < data_.size()){ + break; + } + + /** + * Can this throw? + */ + free_ids_.pop_front(); + } + } +public: + /** + * Default constructor + */ + id_map() = default; + + SAW_FORBID_COPY(id_map); + SAW_DEFAULT_MOVE(id_map); + + /** + * Inserts an element into the container and returns either an id on success + * or an error on failure. + */ + error_or> insert(data val) noexcept { + /// @todo Fix size_t and id base type + if(free_ids_.empty()){ + try { + size_t i = data_.size(); + data_.emplace_back(std::move(val)); + return saw::id{i}; + } catch(std::exception& e) { + return make_error(); + } + } else { + auto f_id = std::move(free_ids_.back()); + free_ids_.pop_back(); + data_.at(f_id.get_value()) = std::move(val); + return f_id; + } + + exit(-1); + // Dummy return since this is not reachable + return make_error(); + } + + /** + * Erase a value at this id. If this id isn't in the map, then it returns an error. + */ + error_or erase(const id& val) noexcept { + /** + * If id is bigger than the available vector then return an error. + */ + if(val.get_value() >= data_.size()){ + return make_error("ID is too large"); + } + + /** + * Check if it's the highest ID. Then we can just try to reduce the highest + * IDs. + */ + if((val.get_value() + 1) == data_.size()){ + data_.pop_back(); + this->reduce_free_ids(); + if(data_.size()*2 <= data_.capacity()){ + try { + data_.shrink_to_fit(); + }catch(std::exception& e){ + return make_error(); + } + } + return void_t{}; + } + + /** + * Check if ID already exists with the free IDs. + * This would mean that a double free has occured. + */ + auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); + if(find_id != free_ids_.end()){ + return make_error("ID value has already been freed"); + } + + /** + * Insert id into deque and sort it. + */ + try { + free_ids_.push_back(val); + } catch(std::exception& e){ + return make_error(); + } + std::stable_sort(free_ids_.begin(), free_ids_.end(), + [](const id& left, const id& right) -> bool { + return left.get_value() > right.get_value(); + } + ); + return void_t{}; + } + + /** + * Tries to find a value based on an id. + * Returns an error on failure and returns + * a value pointer on success. + */ + error_or*> find(const id& val){ + if(val.get_value() >= data_.size()){ + return make_error("ID is too large"); + } + + /** + * This can be removed technically if we are not in a debug state? + */ + auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); + if(find_id != free_ids_.end()){ + return make_error("ID value has already been freed"); + } + + return &data_.at(val.get_value()); + } +}; +} diff --git a/modules/codec/tests/codec.cpp b/modules/codec/tests/codec.cpp index b67d70d..e8a2fb3 100644 --- a/modules/codec/tests/codec.cpp +++ b/modules/codec/tests/codec.cpp @@ -1,5 +1,6 @@ #include #include "../c++/data.hpp" +#include "../c++/id_map.hpp" #include "../c++/simple.hpp" #include "../c++/interface.hpp" diff --git a/modules/core/c++/id_map.hpp b/modules/core/c++/id_map.hpp deleted file mode 100644 index 1df2178..0000000 --- a/modules/core/c++/id_map.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -#include "id.hpp" -#include "error.hpp" - -#include - -namespace saw { -/** - * Fast random access id based container. - * - * Access - O(1) - * Insert - O(1) - * Erase - O(n) ? Dunno - */ -template -class id_map final { -private: - /** - * Container which stores the primary data - */ - std::vector data_; - /** - * Container which tracks free'd/fragmented elements within the - * main container - */ - std::deque> free_ids_; - -private: - /** - * Tries to reduce top ids - */ - void reduce_free_ids() noexcept { - for(;;){ - /** - * If we have no free ids left, we also have nothing to reduce - */ - if(free_ids_.empty()){ - break; - } - - /** - * The front contains the highest free id. - */ - if((free_ids_.front().get_value() + 1) < data_.size()){ - break; - } - - /** - * Can this throw? - */ - free_ids_.pop_front(); - } - } -public: - /** - * Default constructor - */ - id_map() = default; - - SAW_FORBID_COPY(id_map); - SAW_DEFAULT_MOVE(id_map); - - /** - * Inserts an element into the container and returns either an id on success - * or an error on failure. - */ - error_or> insert(T val) noexcept { - /// @todo Fix size_t and id base type - if(free_ids_.empty()){ - try { - size_t i = data_.size(); - data_.emplace_back(std::move(val)); - return saw::id{i}; - } catch(std::exception& e) { - return make_error(); - } - } else { - auto f_id = std::move(free_ids_.back()); - free_ids_.pop_back(); - data_.at(f_id.get_value()) = std::move(val); - return f_id; - } - - exit(-1); - // Dummy return since this is not reachable - return make_error(); - } - - /** - * Erase a value at this id. - */ - error_or erase(const id& val) noexcept { - /** - * If id is bigger than the available vector then return an error. - */ - if(val.get_value() >= data_.size()){ - return make_error("ID is too large"); - } - - /** - * Check if it's the highest ID. Then we can just try to reduce the highest - * IDs. - */ - if((val.get_value() + 1) == data_.size()){ - data_.pop_back(); - this->reduce_free_ids(); - if(data_.size()*2 <= data_.capacity()){ - try { - data_.shrink_to_fit(); - }catch(std::exception& e){ - return make_error(); - } - } - return void_t{}; - } - - /** - * Check if ID already exists with the free IDs. - * This would mean that a double free has occured. - */ - auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); - if(find_id != free_ids_.end()){ - return make_error("ID value has already been freed"); - } - - /** - * Insert id into deque and sort it. - */ - try { - free_ids_.push_back(val); - } catch(std::exception& e){ - return make_error(); - } - std::stable_sort(free_ids_.begin(), free_ids_.end(), - [](const id& left, const id& right) -> bool { - return left.get_value() > right.get_value(); - } - ); - return void_t{}; - } - - /** - * Tries to find a value based on an id. - * Returns an error on failure and returns - * a value pointer on success. - */ - error_or find(const id& val){ - if(val.get_value() >= data_.size()){ - return make_error("ID is too large"); - } - - /** - * This can be removed technically if we are not in a debug state? - */ - auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); - if(find_id != free_ids_.end()){ - return make_error("ID value has already been freed"); - } - - return &data_.at(val.get_value()); - } -}; -} diff --git a/modules/core/tests/core.cpp b/modules/core/tests/core.cpp index 48a25ea..b1ce741 100644 --- a/modules/core/tests/core.cpp +++ b/modules/core/tests/core.cpp @@ -1,6 +1,5 @@ #include "../c++/test/suite.hpp" #include "../c++/id.hpp" -#include "../c++/id_map.hpp" #include "../c++/string_literal.hpp" namespace { @@ -38,30 +37,4 @@ SAW_TEST("String Literal Append"){ SAW_EXPECT(c == "foobar", "CT String sum is not \"foobar\""); } - -SAW_TEST("ID Map Insert"){ - using namespace saw; - - struct foo {}; - - id_map map; - { - auto eoid = map.insert(foo{}); - SAW_EXPECT(eoid.is_value(), "First insert failed"); - - auto& id = eoid.get_value(); - - auto eoid_2 = map.insert(foo{}); - SAW_EXPECT(eoid_2.is_value(), "Second Insert failed"); - auto& id_2 = eoid_2.get_value(); - - SAW_EXPECT(id != id_2, "Shouldn't be equal"); - - auto eov = map.erase(id); - SAW_EXPECT(eov.is_value(), "Erase failed"); - - auto eov_2 = map.erase(id); - SAW_EXPECT(eov_2.is_error(), "This is a double free"); - } -} } diff --git a/modules/io_codec/c++/rpc.hpp b/modules/io_codec/c++/rpc.hpp index 66b7c41..04293cd 100644 --- a/modules/io_codec/c++/rpc.hpp +++ b/modules/io_codec/c++/rpc.hpp @@ -11,27 +11,63 @@ namespace saw { /** - * + * This class acts as a helper for rpc calls and representing data on the remote. */ template class data_or_id { private: + /** + * Variant representing the either id or data class. + */ std::variant, data> doi_; public: + /** + * Constructor for instantiating. + */ data_or_id(const id& val): doi_{val} {} + /** + * Constructor for instantiating. + */ data_or_id(data val): doi_{std::move(val)} {} + /** + * Check if this class holds an id. + */ bool is_id() const { - return false; + return std::holds_alternative>(doi_); } + /** + * Check if this class holds data. + */ bool is_data() const { - return false; + return std::holds_alternative>(doi_); + } + + /** + * Returns the id. + */ + id get_id() const { + return std::get>(doi_); + } + + /** + * Return a data reference. + */ + data& get_data(){ + return std::get>(doi_); + } + + /** + * Return a data reference. + */ + const data& get_data() const { + return std::get>(doi_); } }; diff --git a/modules/remote-sycl/c++/remote.hpp b/modules/remote-sycl/c++/remote.hpp index d4b114a..003dd0e 100644 --- a/modules/remote-sycl/c++/remote.hpp +++ b/modules/remote-sycl/c++/remote.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include @@ -21,12 +21,12 @@ template class remote_data { private: id id_; - id_map* map_; + id_map* map_; public: /** * Main constructor */ - remote_data(const id& id, id_map>& map): + remote_data(const id& id, id_map& map): id_{id}, map_{&map} {} @@ -55,7 +55,7 @@ struct rpc_id_map_helper { template struct rpc_id_map_helper, Encoding> { - std::tuple>...> maps; + std::tuple...> maps; }; } /** @@ -78,7 +78,7 @@ private: interface cl_interface_; /** - * + * Basic storage for response data. */ impl::rpc_id_map_helper storage_; public: @@ -90,11 +90,11 @@ public: template remote_data request_data(id dat){ - return {dat, std::get>>(storage_.maps)}; + return {dat, std::get>(storage_.maps)}; } /** - * rpc call + * Rpc call */ template error_or< @@ -103,15 +103,44 @@ public: > > call(data_or_id::type::RequestT, Encoding> input){ - auto eod = cl_interface_.template call(std::move(input), &cmd_queue_); + /** + * 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::type::RequestT, Encoding>* > { + if(input.is_id()){ + // storage_.maps + auto& inner_map = std::get::type::RequestT, Encoding >> (storage_.maps); + auto eov = inner_map.find(input.get_id()); + if(eov.is_error()){ + return std::move(eov.get_error()); + } + return eov.get_value(); + }else { + return &input.get_data(); + } + }(); + if(eoinp.is_error()){ + return std::move(eoinp.get_error()); + } + auto& inp = *(eoinp.get_value()); + + auto eod = cl_interface_.template call(std::move(inp), &cmd_queue_); if(eod.is_error()){ return std::move(eod.get_error()); } - // using ResponseTMap = id_map> - - return id::type::ResponseT>{}; + /** + * Store returned data in rpc storage + */ + auto& val = eod.get_value(); + auto& inner_map = std::get::type::RequestT, Encoding >> (storage_.maps); + auto eoid = inner_map.insert(std::move(val)); + if(eoid.is_error()){ + return std::move(eoid.get_error()); + } + return eoid.get_value(); } }; -- cgit v1.2.3