From 687a446784da8592f8795f1068328e9de041f63b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 3 Feb 2024 17:37:08 +0100 Subject: [PATCH] used parlay epoch framework --- .../unordered/detail/foa/concurrent_table.hpp | 239 +++--------------- 1 file changed, 36 insertions(+), 203 deletions(-) diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index b73dac03..7e4b283e 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -54,6 +54,7 @@ #include #include #include +#include "utils/epoch.h" #endif std::atomic nodes_wasted=0; @@ -503,27 +504,7 @@ public: #else super{n,h_,pred_,al_} #endif - { -#if defined(BOOST_UNORDERED_LATCH_FREE) - using retired_element_allocator_type= - typename boost::allocator_rebind::type; - using retired_element_traits= - boost::allocator_traits; - - retired_element_allocator_type ral=this->al(); - for(std::size_t i=0;i::type; - using retired_element_traits= - boost::allocator_traits; - - retired_element_allocator_type ral=this->al(); - for(std::size_t i=0;isize_ctrl.size; - for(std::size_t i=0;ip.compare_exchange_strong(pv,nullptr)){ pg->reset(n); - retire_element(pv,!pg->is_not_overflowed(hash)); + auto& sc=local_size_ctrl(); + sc.size-=1; + sc.mcos+=!pg->is_not_overflowed(hash); + epoch::get_default_pool().Retire(pv); res=1; } } @@ -1071,26 +1041,22 @@ private: using exclusive_bilock_guard= reentrancy_bichecked>; -#if defined(BOOST_UNORDERED_LATCH_FREE) - using epoch_type=std::atomic; -#endif - #if defined(BOOST_UNORDERED_LATCH_FREE) struct group_shared_lock_guard { - group_shared_lock_guard(epoch_type& e_):e{e_}{} - ~group_shared_lock_guard(){e=std::size_t(-1);} + group_shared_lock_guard():id{epoch::internal::get_epoch().announce()}{} + ~group_shared_lock_guard(){epoch::internal::get_epoch().unannounce(id);} - epoch_type& e; + int id; }; struct group_exclusive_lock_guard { - group_exclusive_lock_guard( - epoch_type& e_,group_access::exclusive_lock_guard&& lck_): - e{e_},lck{std::move(lck_)}{} - ~group_exclusive_lock_guard(){e=std::size_t(-1);} + group_exclusive_lock_guard(group_access::exclusive_lock_guard&& lck_): + id{epoch::internal::get_epoch().announce()}, + lck{std::move(lck_)}{} + ~group_exclusive_lock_guard(){epoch::internal::get_epoch().unannounce(id);} - epoch_type& e; + int id; group_access::exclusive_lock_guard lck; }; #else @@ -1151,9 +1117,7 @@ private: inline group_shared_lock_guard access(group_shared,std::size_t pos)const { #if defined(BOOST_UNORDERED_LATCH_FREE) - auto& e=local_garbage_vector().epoch; - e=current_epoch.load(std::memory_order_relaxed); - return {e}; + return {}; #else return this->arrays.group_accesses()[pos].shared_access(); #endif @@ -1162,13 +1126,7 @@ private: inline group_exclusive_lock_guard access( group_exclusive,std::size_t pos)const { -#if defined(BOOST_UNORDERED_LATCH_FREE) - auto& e=local_garbage_vector().epoch; - e=current_epoch.load(std::memory_order_relaxed); - return {e,this->arrays.group_accesses()[pos].exclusive_access()}; -#else return this->arrays.group_accesses()[pos].exclusive_access(); -#endif } inline group_insert_counter_type& insert_counter(std::size_t pos)const @@ -1670,10 +1628,8 @@ private: } { assign_insert_counter_on_exit a{insert_counter(pos0),counter+2}; - auto p=this->arrays.elements()+pos*N+n; - auto pv=new_element(); - new (pv) value_type(std::forward(args)...); - p->p=pv; + auto p=this->arrays.elements()+pos*N+n; + this->construct_element(p,std::forward(args)...); pg->set(n,hash); for(prober pb2(pos0);pb2.get()!=pos; pb2.next(this->arrays.groups_size_mask)){ @@ -1681,9 +1637,9 @@ private: } } rslot.commit(); - auto& v=local_garbage_vector(); - ++v.size; - v.mcos-=!pg->is_not_overflowed(hash); + auto& sc=local_size_ctrl(); + sc.size+=1; + sc.mcos-=!pg->is_not_overflowed(hash); return 1; } if(!pbn--)return -1; @@ -1744,7 +1700,6 @@ private: if(p.first>=p.second){ // NB >= auto lck=exclusive_access(); update_size_ctrl(); - garbage_collect(); ++rehashes; this->unchecked_rehash_for_growth(); max_probe=default_max_probe; @@ -2000,118 +1955,22 @@ private: mutable multimutex_type mutexes; #if defined(BOOST_UNORDERED_LATCH_FREE) - struct retired_element{ - static constexpr std::size_t available_=std::size_t(-1), - reserved_=std::size_t(-2); - retired_element()=default; - retired_element(const retired_element&){} - - std::atomic epoch=available_; - std::atomic p={}; - }; - struct alignas(64) garbage_vector + struct alignas(64) local_size_ctrl_type { - static constexpr std::size_t N=256*16; - static constexpr std::size_t min_for_epoch_bump=16; - static constexpr std::size_t min_for_garbage_collection=64; - using ssize_t=std::make_signed::type; - epoch_type epoch=std::size_t(-1); - std::atomic epoch_bump=0; - retired_element* retired_elements; - std::atomic wpos=0; - std::atomic rpos=0; - //std::atomic apos=0; std::atomic size=0; std::atomic mcos=0; }; static constexpr std::size_t default_max_probe=3; - mutable std::array garbage_vectors; - epoch_type current_epoch=1; - unsigned char pad_[cacheline_size-sizeof(epoch_type)]; - std::atomic max_probe=default_max_probe; - std::size_t rehashes=0; + mutable std::array local_size_ctrls; + std::atomic max_probe=default_max_probe; + std::size_t rehashes=0; - garbage_vector& local_garbage_vector()const + local_size_ctrl_type& local_size_ctrl()const { - return garbage_vectors[thread_id()%garbage_vectors.size()]; - } - - std::size_t max_safe_epoch() - { - std::size_t e=retired_element::reserved_; - for(std::size_t i=0;idestroy_element(&x); - // ++v.apos; - //} - e.epoch=v.epoch.load(); - if(++v.wpos%garbage_vector::min_for_garbage_collection==0){ - garbage_collect(v,max_safe_epoch()); - } - return; - } - if(expected==retired_element::reserved_){ /* other thread wrote */ - } - else{ /* vector full */ - v.epoch=current_epoch.load(); - garbage_collect(v,max_safe_epoch()); - } - } - } - - BOOST_FORCEINLINE value_type* new_element() - { - //auto& v=local_garbage_vector(); - //for(;;){ - // std::size_t apos=v.apos; - // if(apos>=v.rpos)break; /*`no available elements*/ - // auto pv=v.retired_elements[apos%v.garbage_vector::N].p.load(); - // if(v.apos.compare_exchange_weak(apos,apos+1)){ - // v.retired_elements[apos%v.garbage_vector::N].p=nullptr; - // return pv; - // } - //} - - /* allocate */ - return boost::allocator_allocate(this->al(),1); + return local_size_ctrls[thread_id()%local_size_ctrls.size()]; } std::pair calculate_size_ctrl() @@ -2119,10 +1978,9 @@ private: using ssize_t=std::make_signed::type; ssize_t ssize=0,smcos=0; - for(std::size_t i=0;isize_ctrl.size.load(std::memory_order_relaxed), ml_=this->size_ctrl.ml.load(std::memory_order_relaxed); @@ -2139,10 +1997,9 @@ private: using ssize_t=std::make_signed::type; ssize_t ssize=0,smcos=0; - for(std::size_t i=0;isize_ctrl.size+=ssize; if(ssize_t(this->size_ctrl.ml)>=smcos)this->size_ctrl.ml-=smcos; @@ -2150,30 +2007,6 @@ private: auto max_ml=super::initial_max_load(); if(this->size_ctrl.ml>max_ml)this->size_ctrl.ml=max_ml; } - - void garbage_collect(garbage_vector& v,std::size_t max_epoch) - { - if(v.rpos==v.wpos)return; - - std::size_t rpos=v.rpos; - for(;;){ - auto& e=v.retired_elements[rpos%v.garbage_vector::N]; - if(e.epoch>max_epoch)break; - element_type x{e.p}; - this->destroy_element(&x); - e.epoch=retired_element::available_; - ++rpos; - } - v.rpos=rpos; - } - - BOOST_NOINLINE void garbage_collect() - { - auto max_epoch=max_safe_epoch(); - for(std::size_t i=0;i