diff --git a/BUILD b/BUILD index d5b39ba8..b0cb564d 100644 --- a/BUILD +++ b/BUILD @@ -75,11 +75,21 @@ alias( actual = '//src/babylon/concurrent:counter', ) +alias( + name = 'concurrent_epoch', + actual = '//src/babylon/concurrent:epoch', +) + alias( name = 'concurrent_execution_queue', actual = '//src/babylon/concurrent:execution_queue', ) +alias( + name = 'concurrent_garbage_collector', + actual = '//src/babylon/concurrent:garbage_collector', +) + alias( name = 'concurrent_id_allocator', actual = '//src/babylon/concurrent:id_allocator', diff --git a/copts.bzl b/copts.bzl index 8187e5f1..ecb4b94c 100644 --- a/copts.bzl +++ b/copts.bzl @@ -18,9 +18,10 @@ BABYLON_CLANG_COPTS = ['-faligned-new', '-Weverything', '-Wno-unknown-warning-op '-Wno-gnu-zero-variadic-macro-arguments', # 零长度数组用来做可变长结构是一种常用手段 '-Wno-zero-length-array', + # BABYLON_SERIALIZABLE宏内部定义的一些辅助成员在继承场景下会发生同名隐藏 + # 但是这个场景下的隐藏本身是无害的,目前也还没有很好的方法做命名区分 + '-Wno-shadow-field', # TODO(lijiang01): 逐步梳理清除 - '-Wno-old-style-cast', '-Wno-shadow-field', - '-Wno-exit-time-destructors', '-Wno-sign-conversion', '-Wno-shadow-field-in-constructor', '-Wno-gnu-anonymous-struct', '-Wno-nested-anon-types', '-Wno-shadow-uncaptured-local', '-Wno-weak-vtables', '-Wno-float-conversion', '-Wno-switch-enum', '-Wno-shadow', '-Wno-array-bounds-pointer-arithmetic', '-Wno-cast-align', '-Wno-vla-extension', @@ -34,3 +35,9 @@ BABYLON_COPTS = select({ '//:enable_werror': ['-Werror', '-DBABYLON_INCLUDE_EXTERNAL_AS_SYSTEM=1'], '//conditions:default': [], }) + +BABYLON_TEST_COPTS = BABYLON_COPTS + select({ + '//:compiler_gcc': [], + '//:compiler_clang': ['-Wno-exit-time-destructors', '-Wno-sign-conversion'], + '//conditions:default': [], +}) diff --git a/src/babylon/BUILD b/src/babylon/BUILD index 346a25ee..40fa8d53 100644 --- a/src/babylon/BUILD +++ b/src/babylon/BUILD @@ -103,6 +103,19 @@ cc_library( ], ) +cc_library( + name = 'garbage_collector', + srcs = ['garbage_collector.cpp'], + hdrs = ['garbage_collector.h'], + copts = BABYLON_COPTS, + includes = ['//src'], + strip_include_prefix = '//src', + deps = [ + '//src/babylon/concurrent:bounded_queue', + '//src/babylon/concurrent:id_allocator', + ], +) + cc_library( name = 'mlock', srcs = ['mlock.cpp'], diff --git a/src/babylon/any.hpp b/src/babylon/any.hpp index 5dba8bf2..d7508dbb 100644 --- a/src/babylon/any.hpp +++ b/src/babylon/any.hpp @@ -334,28 +334,21 @@ inline bool Any::is_reference() const noexcept { template inline T Any::as() const noexcept { switch (_meta.m.type) { - case Type::INT64: - return *reinterpret_cast(const_raw_pointer()); - case Type::INT32: - return *reinterpret_cast(const_raw_pointer()); - case Type::INT16: - return *reinterpret_cast(const_raw_pointer()); - case Type::INT8: - return *reinterpret_cast(const_raw_pointer()); - case Type::BOOLEAN: - return *reinterpret_cast(const_raw_pointer()); - case Type::UINT64: - return *reinterpret_cast(const_raw_pointer()); - case Type::UINT32: - return *reinterpret_cast(const_raw_pointer()); - case Type::UINT16: - return *reinterpret_cast(const_raw_pointer()); - case Type::UINT8: - return *reinterpret_cast(const_raw_pointer()); - case Type::DOUBLE: - return *reinterpret_cast(const_raw_pointer()); - case Type::FLOAT: - return *reinterpret_cast(const_raw_pointer()); +#define __BABYLON_TMP_GEN(etype, ctype) \ + case Type::etype: \ + return static_cast(*reinterpret_cast(const_raw_pointer())); + __BABYLON_TMP_GEN(INT64, int64_t) + __BABYLON_TMP_GEN(INT32, int32_t) + __BABYLON_TMP_GEN(INT16, int16_t) + __BABYLON_TMP_GEN(INT8, int8_t) + __BABYLON_TMP_GEN(BOOLEAN, bool) + __BABYLON_TMP_GEN(UINT64, uint64_t) + __BABYLON_TMP_GEN(UINT32, uint32_t) + __BABYLON_TMP_GEN(UINT16, uint16_t) + __BABYLON_TMP_GEN(UINT8, uint8_t) + __BABYLON_TMP_GEN(DOUBLE, double) + __BABYLON_TMP_GEN(FLOAT, float) +#undef __BABYLON_TMP_GEN default: return 0; } diff --git a/src/babylon/anyflow/builder.cpp b/src/babylon/anyflow/builder.cpp index 5c4e7180..1ba74f1c 100644 --- a/src/babylon/anyflow/builder.cpp +++ b/src/babylon/anyflow/builder.cpp @@ -148,7 +148,7 @@ ssize_t GraphVertexBuilder::index_for_named_dependency( if (ABSL_PREDICT_FALSE(iter == _dependency_index_by_name.end())) { return -1; } - return iter->second; + return static_cast(iter->second); } ssize_t GraphVertexBuilder::index_for_named_emit( @@ -157,7 +157,7 @@ ssize_t GraphVertexBuilder::index_for_named_emit( if (ABSL_PREDICT_FALSE(iter == _emit_index_by_name.end())) { return -1; } - return iter->second; + return static_cast(iter->second); } void GraphVertexBuilder::set_graph(GraphBuilder& graph) noexcept { diff --git a/src/babylon/anyflow/builder.hpp b/src/babylon/anyflow/builder.hpp index a6c8368b..78f7b79f 100644 --- a/src/babylon/anyflow/builder.hpp +++ b/src/babylon/anyflow/builder.hpp @@ -78,10 +78,10 @@ template inline void GraphVertexBuilder::for_each_dependency( C&& callback) const noexcept { for (auto& dependency : _named_dependencies) { - callback(static_cast(*dependency)); + callback(const_cast(*dependency)); } for (auto& dependency : _anonymous_dependencies) { - callback(static_cast(*dependency)); + callback(const_cast(*dependency)); } } @@ -98,10 +98,10 @@ inline void GraphVertexBuilder::for_each_emit(C&& callback) noexcept { template inline void GraphVertexBuilder::for_each_emit(C&& callback) const noexcept { for (auto& emit : _named_emits) { - callback(static_cast(*emit)); + callback(const_cast(*emit)); } for (auto& emit : _anonymous_emits) { - callback(static_cast(*emit)); + callback(const_cast(*emit)); } } diff --git a/src/babylon/anyflow/builtin/expression.cpp b/src/babylon/anyflow/builtin/expression.cpp index ab879b50..cc04c92b 100644 --- a/src/babylon/anyflow/builtin/expression.cpp +++ b/src/babylon/anyflow/builtin/expression.cpp @@ -122,10 +122,15 @@ class UnaryOperator : public Operator { size_t _operand_index; GetOperandFunction _get_operand; }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" ::std::unordered_map<::std::string, ::std::function<::std::unique_ptr( const Operator::ValueIndex&, const Operator::ValueIndex&)>> UnaryOperator::_s_registry; +#pragma GCC diagnostic pop // 二元运算符基类,自带注册表 class BinaryOperator : public Operator { @@ -225,6 +230,10 @@ class BinaryOperator : public Operator { size_t _roperand_index; GetOperandFunction _get_roperand; }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" ::std::vector<::std::tuple> BinaryOperator::TYPE_LEVEL = BinaryOperator::generate_type_level(); ::std::unordered_map< @@ -232,6 +241,7 @@ ::std::unordered_map< const Operator::ValueIndex&, const Operator::ValueIndex&, const Operator::ValueIndex&)>> BinaryOperator::_s_registry; +#pragma GCC diagnostic pop // 定义并注册一个一元运算符 #define __BABYLON_DEFINE_UNARY_OPERATOR(name, op) \ @@ -284,7 +294,7 @@ ::std::unordered_map< if (ABSL_PREDICT_TRUE(value != nullptr)) { \ result = op !value->empty(); \ } else { \ - result = op(bool) operand; \ + result = op static_cast(operand); \ } \ break; \ } \ @@ -363,6 +373,10 @@ ::std::unordered_map< BinaryOperator::Register \ name_prefix##Operator::_s_register(#op); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" // 定义这些运算符 __BABYLON_DEFINE_UNARY_OPERATOR(Not, !); __BABYLON_DEFINE_UNARY_OPERATOR(Neg, -); @@ -381,6 +395,7 @@ __BABYLON_DEFINE_BINARY_OPERATOR(Ne, !=, 1); #pragma GCC diagnostic pop __BABYLON_DEFINE_BINARY_OPERATOR(And, &&, 0); __BABYLON_DEFINE_BINARY_OPERATOR(Or, ||, 0); +#pragma GCC diagnostic pop #undef __BABYLON_DEFINE_UNARY_OPERATOR #undef __BABYLON_DEFINE_BINARY_OPERATOR @@ -410,6 +425,10 @@ struct Option { ::std::vector<::std::unique_ptr> operators; }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static struct QuotedString : public grammar { QuotedString() noexcept : base_type(start, "quoted_string") { start = '"' >> *(escaped_slash | escaped_quote | common_char) >> '"'; @@ -423,6 +442,7 @@ static struct QuotedString : public grammar { rule escaped_quote; rule common_char; } quoted_string; +#pragma GCC diagnostic pop struct Variable : public grammar { Variable() noexcept : base_type(start, "variable") { @@ -850,8 +870,13 @@ int32_t ExpressionProcessor::expend_conditional_expression( unsolved_expressions, const ::std::string& result_name, const ::std::string& expression_string) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static expression::ConditionalExpression conditional_expression; static expression::Expression expression; +#pragma GCC diagnostic pop ::std::tuple<::std::string, ::std::string, ::std::string> result; auto begin = expression_string.c_str(); @@ -868,7 +893,8 @@ int32_t ExpressionProcessor::expend_conditional_expression( ::boost::spirit::qi::space); // 也不是一般表达式则报错 if (!ret || begin < end) { - ::std::string pointer(begin - expression_string.c_str(), ' '); + ::std::string pointer( + static_cast(begin - expression_string.c_str()), ' '); pointer += '^'; BABYLON_LOG(WARNING) << "error exp = " << expression_string; BABYLON_LOG(WARNING) << " " << pointer; @@ -923,7 +949,8 @@ int32_t ExpressionProcessor::expend_non_conditional_expression( // 完整解析才算成功 if (!ret || begin < end) { - ::std::string pointer(begin - expression_string.c_str(), ' '); + ::std::string pointer( + static_cast(begin - expression_string.c_str()), ' '); pointer += '^'; BABYLON_LOG(WARNING) << "error exp = " << expression_string; BABYLON_LOG(WARNING) << " " << pointer; diff --git a/src/babylon/anyflow/executor.cpp b/src/babylon/anyflow/executor.cpp index 38122178..cbdb7dc5 100644 --- a/src/babylon/anyflow/executor.cpp +++ b/src/babylon/anyflow/executor.cpp @@ -25,7 +25,12 @@ int InplaceGraphExecutor::run(ClosureContext* closure, } InplaceGraphExecutor& InplaceGraphExecutor::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static InplaceGraphExecutor instance; +#pragma GCC diagnostic pop return instance; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/babylon/anyflow/vertex.cpp b/src/babylon/anyflow/vertex.cpp index db376870..a892b3ec 100644 --- a/src/babylon/anyflow/vertex.cpp +++ b/src/babylon/anyflow/vertex.cpp @@ -177,12 +177,13 @@ int GraphVertex::activate(DataStack& activating_data, _closure = closure; // 无依赖直接记入可执行列表 - int64_t waiting_num = _dependencies.size(); + auto waiting_num = _dependencies.size(); if (waiting_num == 0) { runnable_vertexes.emplace_back(this); return 0; } - _waiting_num.store(waiting_num, ::std::memory_order_relaxed); + _waiting_num.store(static_cast(waiting_num), + ::std::memory_order_relaxed); if (0 != _processor->on_activate()) { return -1; @@ -200,9 +201,9 @@ int GraphVertex::activate(DataStack& activating_data, // 去掉已经就绪的数目,如果全部就绪,节点加入待运行集合 if (finished > 0) { - waiting_num = + waiting_num = static_cast( _waiting_num.fetch_sub(finished, ::std::memory_order_acq_rel) - - finished; + finished); if (waiting_num == 0) { runnable_vertexes.emplace_back(this); return 0; @@ -242,7 +243,5 @@ void GraphVertex::invoke(VertexStack& runnable_vertexes) noexcept { } } -GraphProcessor GraphVertex::DEFAULT_EMPTY_PROCESSOR; - } // namespace anyflow BABYLON_NAMESPACE_END diff --git a/src/babylon/anyflow/vertex.h b/src/babylon/anyflow/vertex.h index f93cf3cb..9f15c09a 100644 --- a/src/babylon/anyflow/vertex.h +++ b/src/babylon/anyflow/vertex.h @@ -211,8 +211,6 @@ class GraphVertex { inline VertexStack* runnable_vertexes() noexcept; private: - static GraphProcessor DEFAULT_EMPTY_PROCESSOR; - const GraphVertexBuilder* _builder {nullptr}; Graph* _graph {nullptr}; @@ -299,34 +297,34 @@ BABYLON_NAMESPACE_END BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_ELEM(0, args), 0), \ __ANYFLOW_DECLARE_DEPEND args, __ANYFLOW_DECLARE_EMIT args) -#define __ANYFLOW_DECLARE_DEPEND(r, type, name, is_channel, is_mutable, \ - essential_level, is_va_args, ...) \ - { \ - BOOST_PP_IF( \ - BOOST_PP_EQUAL(is_va_args, 0), \ - auto index = vertex().index_for_named_dependency(#name); \ - if (index < 0 && essential_level > 0) { \ - BABYLON_LOG(WARNING) \ - << "no depend bind to " #name " for " << vertex(); \ - return -1; \ - } if (index >= 0) { \ - auto depend = vertex().named_dependency(index); \ - if (is_mutable) { \ - depend->declare_mutable(); \ - } \ - depend->declare_essential(essential_level == 1); \ - BOOST_PP_IF( \ - is_channel, \ - depend->declare_channel<__ANYFLOW_TYPE_FOR_NAME(name)>(); \ - , depend->declare_type<__ANYFLOW_TYPE_FOR_NAME(name)>();) \ - } __anyflow_index_for_##name = index; \ - , \ - size_t anonymous_depends_size = vertex().anonymous_dependency_size(); \ - name.resize(anonymous_depends_size); \ - for (size_t index = 0; index < anonymous_depends_size; index++) { \ - auto depend = vertex().anonymous_dependency(index); \ - depend->declare_type<__ANYFLOW_TYPE_FOR_NAME(name)>(); \ - }) \ +#define __ANYFLOW_DECLARE_DEPEND(r, type, name, is_channel, is_mutable, \ + essential_level, is_va_args, ...) \ + { \ + BOOST_PP_IF( \ + BOOST_PP_EQUAL(is_va_args, 0), \ + auto index = vertex().index_for_named_dependency(#name); \ + if (index < 0 && essential_level > 0) { \ + BABYLON_LOG(WARNING) \ + << "no depend bind to " #name " for " << vertex(); \ + return -1; \ + } if (index >= 0) { \ + auto depend = vertex().named_dependency(static_cast(index)); \ + if (is_mutable) { \ + depend->declare_mutable(); \ + } \ + depend->declare_essential(essential_level == 1); \ + BOOST_PP_IF( \ + is_channel, \ + depend->declare_channel<__ANYFLOW_TYPE_FOR_NAME(name)>(); \ + , depend->declare_type<__ANYFLOW_TYPE_FOR_NAME(name)>();) \ + } __anyflow_index_for_##name = index; \ + , \ + size_t anonymous_depends_size = vertex().anonymous_dependency_size(); \ + name.resize(anonymous_depends_size); \ + for (size_t index = 0; index < anonymous_depends_size; index++) { \ + auto depend = vertex().anonymous_dependency(index); \ + depend->declare_type<__ANYFLOW_TYPE_FOR_NAME(name)>(); \ + }) \ } #define __ANYFLOW_DECLARE_EMIT(r, type, name, is_channel, is_mutable, \ diff --git a/src/babylon/application_context.cpp b/src/babylon/application_context.cpp index ed7129ae..c3ddc0fe 100644 --- a/src/babylon/application_context.cpp +++ b/src/babylon/application_context.cpp @@ -18,7 +18,12 @@ void ApplicationContext::OffsetDeleter::operator()(void* ptr) noexcept { //////////////////////////////////////////////////////////////////////////////// // ApplicationContext begin ApplicationContext& ApplicationContext::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static ApplicationContext singleton; +#pragma GCC diagnostic pop return singleton; } @@ -173,8 +178,13 @@ void ApplicationContext::ComponentHolder::create_singleton( } } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" ApplicationContext::EmptyComponentHolder ApplicationContext::EMPTY_COMPONENT_HOLDER; +#pragma GCC diagnostic pop //////////////////////////////////////////////////////////////////////////////// // ApplicationContext::EmptyComponentHolder begin diff --git a/src/babylon/application_context.h b/src/babylon/application_context.h index 0f578dc6..0d8d9789 100644 --- a/src/babylon/application_context.h +++ b/src/babylon/application_context.h @@ -489,7 +489,12 @@ ApplicationContext::component_accessor() noexcept { template ABSL_ATTRIBUTE_NOINLINE ApplicationContext::ComponentAccessor ApplicationContext::component_accessor(StringView name) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static thread_local ::std::tuple key; +#pragma GCC diagnostic pop ::std::get<0>(key) = &TypeId().ID; ::std::get<1>(key) = name; auto it = _holder_by_type_and_name.find(key); diff --git a/src/babylon/concurrent/BUILD b/src/babylon/concurrent/BUILD index a3200cf0..0091895f 100644 --- a/src/babylon/concurrent/BUILD +++ b/src/babylon/concurrent/BUILD @@ -8,9 +8,9 @@ load('//:copts.bzl', 'BABYLON_COPTS') cc_library( name = 'concurrent', deps = [ - ':bounded_queue', ':counter', ':execution_queue', - ':id_allocator', ':object_pool', ':sched_interface', - ':thread_local', ':transient_hash_table', + ':bounded_queue', ':counter', ':epoch', ':execution_queue', + ':garbage_collector', ':id_allocator', ':object_pool', + ':sched_interface', ':thread_local', ':transient_hash_table', ':transient_topic', ':vector', ] ) @@ -42,6 +42,17 @@ cc_library( ], ) +cc_library( + name = 'epoch', + hdrs = ['epoch.h'], + copts = BABYLON_COPTS, + includes = ['//src'], + strip_include_prefix = '//src', + deps = [ + ':id_allocator', + ], +) + cc_library( name = 'execution_queue', hdrs = ['execution_queue.h'], @@ -55,6 +66,18 @@ cc_library( ], ) +cc_library( + name = 'garbage_collector', + hdrs = ['garbage_collector.h'], + copts = BABYLON_COPTS, + includes = ['//src'], + strip_include_prefix = '//src', + deps = [ + ':bounded_queue', + ':epoch', + ], +) + cc_library( name = 'id_allocator', hdrs = ['id_allocator.h', 'id_allocator.hpp'], diff --git a/src/babylon/concurrent/bounded_queue.hpp b/src/babylon/concurrent/bounded_queue.hpp index 6c686e6f..6c9e77d0 100644 --- a/src/babylon/concurrent/bounded_queue.hpp +++ b/src/babylon/concurrent/bounded_queue.hpp @@ -406,7 +406,7 @@ template size_t ConcurrentBoundedQueue::reserve_and_clear(size_t min_capacity) { auto new_capacity = ::absl::bit_ceil(min_capacity); if (new_capacity != capacity()) { - _slot_bits = __builtin_ctzll(new_capacity); + _slot_bits = static_cast(__builtin_ctzll(new_capacity)); _slot_mask = new_capacity - 1; _slots.resize(new_capacity); _next_push_index.store(0, ::std::memory_order_relaxed); diff --git a/src/babylon/concurrent/counter.h b/src/babylon/concurrent/counter.h index 6351aebf..5f166617 100644 --- a/src/babylon/concurrent/counter.h +++ b/src/babylon/concurrent/counter.h @@ -31,7 +31,8 @@ class ConcurrentAdder { ~ConcurrentAdder() noexcept = default; // 分散计数接口 - inline ConcurrentAdder& operator<<(ssize_t value) noexcept; + template + inline ConcurrentAdder& operator<<(const T& value) noexcept; // 汇聚读取接口 ssize_t value() const noexcept; @@ -40,6 +41,8 @@ class ConcurrentAdder { void reset() noexcept; private: + inline void count(ssize_t value) noexcept; + CompactEnumerableThreadLocal _storage; }; @@ -203,13 +206,19 @@ class ConcurrentSampler { ::std::atomic _version {0}; }; +template inline ABSL_ATTRIBUTE_ALWAYS_INLINE ConcurrentAdder& -ConcurrentAdder::operator<<(ssize_t value) noexcept { +ConcurrentAdder::operator<<(const T& value) noexcept { + count(static_cast(value)); + return *this; +} + +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void ConcurrentAdder::count( + ssize_t value) noexcept { auto& local = _storage.local(); // local的唯一修改者是自己,所以这里不需要使用原子加法 // 正确对齐的数值类型赋值本身是原子发生的 local = local + value; - return *this; } inline ABSL_ATTRIBUTE_ALWAYS_INLINE ConcurrentMaxer& @@ -276,7 +285,7 @@ ConcurrentSampler::bucket_index(uint32_t value) noexcept { if (ABSL_PREDICT_FALSE(value == 0)) { return 0; } else { - return 32 - __builtin_clz(value); + return 32 - static_cast(__builtin_clz(value)); } } diff --git a/src/babylon/concurrent/epoch.h b/src/babylon/concurrent/epoch.h new file mode 100644 index 00000000..53fbbafc --- /dev/null +++ b/src/babylon/concurrent/epoch.h @@ -0,0 +1,235 @@ +#pragma once + +#include "babylon/concurrent/id_allocator.h" +#include "babylon/concurrent/vector.h" + +#pragma GCC diagnostic push +#if GCC_VERSION >= 120000 +#pragma GCC diagnostic ignored "-Wtsan" +#endif // GCC_VERSION >= 120000 + +BABYLON_NAMESPACE_BEGIN + +// Standalone epoch implementation as a part of EBR (Epoch-Based Reclamation) +// which described in https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf +// +// With modifications below: +// - Spilt global epoch advance and local epoch check out of critical region +// - Support non-thread-local and long-term critical region +// +// This makes read-only access faster and decouple with reclaim operation. +// Also, this makes it possible to amortize overhead of read / modify / reclaim +// operation, like NEBR mentioned in +// https://sysweb.cs.toronto.edu/publication_files/0000/0159/jpdc07.pdf +class Epoch { + public: + // Accessor is an explicit handle for construct critical region. + // An Accessor join epoch calculation just a thread in standard algorithm. + // + // Cannot mix usage of Accessor and implicit thread local style. + class Accessor; + inline Accessor create_accessor() noexcept; + + // Total num of Accessor created. + // Contain released accessors, which may be reused in subsequent + // create_accessor + inline size_t accessor_number() const noexcept; + + // Standard thread local style to construct critical region. + // Satisfy STL BasicLockable requirement. + // + // Cannot mix usage of Accessor and implicit thread local style. + inline void lock() noexcept; + inline void unlock() noexcept; + + // Advance global epoch and get epoch after increase. + // This epoch value is used to check whether previous retired objects can be + // safely reclaimed, if that value <= low_water_mark. + inline uint64_t tick() noexcept; + + // Collect observations of all thread local or Accessor, calculate low water + // mark + inline uint64_t low_water_mark() const noexcept; + + private: + class alignas(BABYLON_CACHELINE_SIZE) Slot { + public: + Slot() noexcept = default; + Slot(Slot&&) = delete; + Slot(const Slot&) = delete; + Slot& operator=(Slot&&) = delete; + Slot& operator=(const Slot&) = delete; + ~Slot() noexcept = default; + + ::std::atomic version = ATOMIC_VAR_INIT(UINT64_MAX); + size_t lock_times {0}; + }; + + inline void unregister_accessor(size_t index) noexcept; + + inline void lock(size_t index) noexcept; + inline void unlock(size_t index) noexcept; + + IdAllocator _id_allocator; + ConcurrentVector _slots; + ::std::atomic _version = ATOMIC_VAR_INIT(0); + + friend Accessor; +}; + +class Epoch::Accessor { + public: + inline Accessor() noexcept = default; + inline Accessor(Accessor&&) noexcept; + Accessor(const Accessor&) = delete; + inline Accessor& operator=(Accessor&&) noexcept; + Accessor& operator=(const Accessor&) = delete; + inline ~Accessor() noexcept; + + // Whether this accessor is usable. + inline operator bool() const noexcept; + + // Explicit construct critical region. + // Satisfy STL BasicLockable requirement. + // + // Cannot mix usage of Accessor and implicit thread local style. + inline void lock() noexcept; + inline void unlock() noexcept; + + // Unbind this accessor. It is not usable anymore. + inline void release() noexcept; + + private: + inline Accessor(Epoch* epoch, size_t index) noexcept; + inline void swap(Accessor& other) noexcept; + + Epoch* _epoch {nullptr}; + size_t _index {SIZE_MAX}; + + friend Epoch; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Epoch begin +inline Epoch::Accessor Epoch::create_accessor() noexcept { + auto index = _id_allocator.allocate().value; + _slots.ensure(index); + return {this, index}; +} + +inline size_t Epoch::accessor_number() const noexcept { + return _id_allocator.end(); +} + +inline void Epoch::lock() noexcept { + auto index = ThreadId::current_thread_id().value; + _slots.ensure(index); + lock(index); +} + +inline void Epoch::unlock() noexcept { + auto index = ThreadId::current_thread_id().value; + unlock(index); +} + +inline void Epoch::unregister_accessor(size_t index) noexcept { + _id_allocator.deallocate(index); +} + +inline void Epoch::lock(size_t index) noexcept { + auto& slot = _slots[index]; + slot.lock_times += 1; + if (slot.lock_times == 1) { + auto global_version = _version.load(::std::memory_order_relaxed); + slot.version.store(global_version, ::std::memory_order_relaxed); + ::std::atomic_thread_fence(::std::memory_order_seq_cst); + } +} + +inline void Epoch::unlock(size_t index) noexcept { + auto& slot = _slots[index]; + if (slot.lock_times == 1) { + slot.version.store(UINT64_MAX, ::std::memory_order_release); + } + slot.lock_times -= 1; +} + +inline uint64_t Epoch::tick() noexcept { +#if __x86_64__ + auto version = 1 + _version.fetch_add(1, ::std::memory_order_seq_cst); +#else // !__x86_64__ + auto version = 1 + _version.fetch_add(1, ::std::memory_order_relaxed); + ::std::atomic_thread_fence(::std::memory_order_seq_cst); +#endif // !__x86_64__ + return version; +} + +inline uint64_t Epoch::low_water_mark() const noexcept { + auto min_verison = UINT64_MAX; + auto slots = _slots.snapshot(); + auto number = accessor_number(); + if (number == 0) { + number = ThreadId::end(); + } + slots.for_each(0, ::std::min(number, slots.size()), + [&](const Slot* iter, const Slot* end) { + while (iter != end) { + auto local_version = + (iter++)->version.load(::std::memory_order_acquire); + if (min_verison > local_version) { + min_verison = local_version; + } + } + }); + return min_verison; +} +// Epoch end +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Epoch::Accessor begin +inline Epoch::Accessor::Accessor(Accessor&& other) noexcept { + swap(other); +} + +inline Epoch::Accessor& Epoch::Accessor::operator=(Accessor&& other) noexcept { + swap(other); + return *this; +} + +inline Epoch::Accessor::~Accessor() noexcept { + release(); +} + +inline Epoch::Accessor::operator bool() const noexcept { + return _epoch != nullptr; +} + +inline Epoch::Accessor::Accessor(Epoch* epoch, size_t index) noexcept + : _epoch {epoch}, _index {index} {} + +inline void Epoch::Accessor::swap(Accessor& other) noexcept { + ::std::swap(_epoch, other._epoch); + ::std::swap(_index, other._index); +} + +inline void Epoch::Accessor::lock() noexcept { + _epoch->lock(_index); +} + +inline void Epoch::Accessor::unlock() noexcept { + _epoch->unlock(_index); +} + +inline void Epoch::Accessor::release() noexcept { + if (_epoch != nullptr) { + _epoch->unregister_accessor(_index); + _epoch = nullptr; + } +} +// Epoch::Accessor end +//////////////////////////////////////////////////////////////////////////////// + +BABYLON_NAMESPACE_END + +#pragma GCC diagnostic pop diff --git a/src/babylon/concurrent/garbage_collector.h b/src/babylon/concurrent/garbage_collector.h new file mode 100644 index 00000000..caa61430 --- /dev/null +++ b/src/babylon/concurrent/garbage_collector.h @@ -0,0 +1,203 @@ +#pragma once + +#include "babylon/concurrent/bounded_queue.h" +#include "babylon/concurrent/epoch.h" + +// clang-format off +#include "babylon/protect.h" +// clang-format on + +#include + +BABYLON_NAMESPACE_BEGIN + +// Standalone reclaimer implementation as a part of EBR (Epoch-Based +// Reclamation) which described in +// https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf +// +// With modifications below: +// - Delay and move the reclaim operation to a standalone thread +// +// Typical usage is: +// - Use Epoch to build critical region. All element of a lock-free structure +// accessed inside this critical region will keep valid. +// - After modify that lock-free structure. Some old element may be **retired** +// and collect by the GarbageCollector. They will finally be **reclaimed** when +// all critical region **previous to that modification** are closed. +template +class GarbageCollector { + public: + // Capture this in gc thread. So no copy nor move is allowed + GarbageCollector() noexcept = default; + GarbageCollector(GarbageCollector&&) noexcept = delete; + GarbageCollector(const GarbageCollector&) noexcept = delete; + GarbageCollector& operator=(GarbageCollector&&) noexcept = delete; + GarbageCollector& operator=(const GarbageCollector&) noexcept = delete; + ~GarbageCollector() noexcept; + + // Reclaim task is queued waiting reach the low_water_mark expected. + // Set how many task can be queued before finally blocking the retire function + void set_queue_capacity(size_t min_capacity) noexcept; + + // Start background gc thread that consume and do reclaim task + int start() noexcept; + + // Get underlying epoch instance + inline Epoch& epoch() noexcept; + + // Queue a reclaim task in. This task will be called by background thread + // when low_water_mark of epoch reach at least lowest_epoch. + // + // lowest_epoch is default set by Epoch::tick. User can do this tick outside + // to do fast batch retirements + inline void retire(R&& reclaimer) noexcept; + inline void retire(R&& reclaimer, uint64_t lowest_epoch) noexcept; + + // Stop background gc thread after current reclaim tasks are all finished + void stop() noexcept; + + private: + class ReclaimTask { + public: + ReclaimTask() noexcept = default; + ReclaimTask(ReclaimTask&&) = default; + ReclaimTask(const ReclaimTask&) = delete; + ReclaimTask& operator=(ReclaimTask&&) = default; + ReclaimTask& operator=(const ReclaimTask&) = delete; + ~ReclaimTask() noexcept = default; + + R reclaimer; + uint64_t lowest_epoch {UINT64_MAX}; + }; + + void keep_reclaim() noexcept; + bool consume_reclaim_task(size_t batch, + ::std::vector& tasks) noexcept; + size_t reclaim_start_from(size_t index, + ::std::vector& tasks) noexcept; + + Epoch _epoch; + ConcurrentBoundedQueue _queue; + ::std::thread _gc_thread; +}; + +//////////////////////////////////////////////////////////////////////////////// +// GarbageCollector begin +template +ABSL_ATTRIBUTE_NOINLINE GarbageCollector::~GarbageCollector() noexcept { + stop(); +} + +template +ABSL_ATTRIBUTE_NOINLINE void GarbageCollector::set_queue_capacity( + size_t min_capacity) noexcept { + _queue.reserve_and_clear(min_capacity); +} + +template +ABSL_ATTRIBUTE_NOINLINE int GarbageCollector::start() noexcept { + if (!_gc_thread.joinable()) { + _gc_thread = ::std::thread(&GarbageCollector::keep_reclaim, this); + } + return 0; +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE inline Epoch& +GarbageCollector::epoch() noexcept { + return _epoch; +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void GarbageCollector::retire( + R&& reclaimer) noexcept { + retire(::std::move(reclaimer), _epoch.tick()); +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void GarbageCollector::retire( + R&& reclaimer, uint64_t lowest_epoch) noexcept { + _queue.template push(ReclaimTask { + .reclaimer = ::std::move(reclaimer), .lowest_epoch = lowest_epoch}); +} + +template +ABSL_ATTRIBUTE_NOINLINE void GarbageCollector::stop() noexcept { + if (_gc_thread.joinable()) { + _queue.template push(ReclaimTask {}); + _gc_thread.join(); + } +} + +template +ABSL_ATTRIBUTE_NOINLINE void GarbageCollector::keep_reclaim() noexcept { + bool running = true; + size_t batch = ::std::min(1024, _queue.capacity()); + size_t index = 0; + ::std::vector tasks; + size_t backoff_us = 1000; + tasks.reserve(batch); + while (running) { + if (index == tasks.size()) { + tasks.clear(); + running = consume_reclaim_task(batch, tasks); + index = 0; + } + + auto reclaimed = reclaim_start_from(index, tasks); + index += reclaimed; + + if (reclaimed < 100) { + backoff_us = ::std::min(backoff_us + 10, 100000); + ::usleep(backoff_us); + } else if (reclaimed >= batch) { + backoff_us >>= 1; + } + } +} + +template +ABSL_ATTRIBUTE_NOINLINE bool GarbageCollector::consume_reclaim_task( + size_t batch, ::std::vector& tasks) noexcept { + using Iterator = typename ConcurrentBoundedQueue::Iterator; + + bool running = true; + _queue.template try_pop_n( + [&](Iterator iter, Iterator end) { + while (iter < end) { + auto& task = *iter++; + if (ABSL_PREDICT_FALSE(task.lowest_epoch == UINT64_MAX)) { + running = false; + break; + } + tasks.emplace_back(::std::move(task)); + } + }, + batch); + return running; +} + +template +ABSL_ATTRIBUTE_NOINLINE size_t GarbageCollector::reclaim_start_from( + size_t index, ::std::vector& tasks) noexcept { + size_t reclaimed = 0; + auto low_water_mark = _epoch.low_water_mark(); + for (; index < tasks.size(); ++index) { + auto& task = tasks[index]; + if (task.lowest_epoch > low_water_mark) { + break; + } + { + ReclaimTask t = ::std::move(task); + t.reclaimer(); + } + reclaimed++; + } + return reclaimed; +} +// GarbageCollector end +//////////////////////////////////////////////////////////////////////////////// + +BABYLON_NAMESPACE_END + +#include "babylon/unprotect.h" diff --git a/src/babylon/concurrent/id_allocator.hpp b/src/babylon/concurrent/id_allocator.hpp index 14e47ac7..6ab8360e 100644 --- a/src/babylon/concurrent/id_allocator.hpp +++ b/src/babylon/concurrent/id_allocator.hpp @@ -141,7 +141,12 @@ namespace concurrent_id_allocator { template struct IdAllocatorFotType { static IdAllocator& instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static IdAllocator object; +#pragma GCC diagnostic pop return object; } }; @@ -161,8 +166,13 @@ inline ABSL_ATTRIBUTE_ALWAYS_INLINE // clang-format off VersionedValue ThreadId::current_thread_id() noexcept { // clang-format on +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" thread_local ThreadId id( internal::concurrent_id_allocator::IdAllocatorFotType::instance()); +#pragma GCC diagnostic pop return id._value; } diff --git a/src/babylon/concurrent/thread_local.h b/src/babylon/concurrent/thread_local.h index a05beb9f..b0e52412 100644 --- a/src/babylon/concurrent/thread_local.h +++ b/src/babylon/concurrent/thread_local.h @@ -217,7 +217,12 @@ CompactEnumerableThreadLocal< template IdAllocator& CompactEnumerableThreadLocal::id_allocator() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static IdAllocator allocator; +#pragma GCC diagnostic pop return allocator; } @@ -225,7 +230,12 @@ template typename CompactEnumerableThreadLocal::Storage& CompactEnumerableThreadLocal::storage( size_t slot_index) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static StorageVector storage_vector; +#pragma GCC diagnostic pop return storage_vector.ensure(slot_index); } diff --git a/src/babylon/concurrent/transient_hash_table.hpp b/src/babylon/concurrent/transient_hash_table.hpp index 83587333..bc1cb7c5 100644 --- a/src/babylon/concurrent/transient_hash_table.hpp +++ b/src/babylon/concurrent/transient_hash_table.hpp @@ -108,19 +108,19 @@ class GroupIterator { inline size_t operator*() noexcept { #if defined(__ARM_NEON) - return __builtin_ctzll(_mask) >> 2; + return static_cast(__builtin_ctzll(_mask) >> 2); #else // !defined(__ARM_NEON) - return __builtin_ctzll(_mask); + return static_cast(__builtin_ctzll(_mask)); #endif // !defined(__ARM_NEON) } inline ABSL_ATTRIBUTE_ALWAYS_INLINE GroupIndex operator++(int) noexcept { #if defined(__ARM_NEON) - size_t offset = __builtin_ctzll(_mask); + auto offset = static_cast(__builtin_ctzll(_mask)); _mask = _mask - (static_cast(0xF) << offset); return offset >> 2; #else // !defined(__ARM_NEON) - size_t offset = __builtin_ctzll(_mask); + auto offset = static_cast(__builtin_ctzll(_mask)); _mask = _mask - (0x1 << offset); return offset; #endif // !defined(__ARM_NEON) @@ -142,11 +142,11 @@ class Group { static constexpr size_t CHECKER_MASK_BITS = 7; // 默认构造后的特殊状态,不存在元素,但又不可写入 - static constexpr int8_t DUMMY_CONTROL = 0x82; + static constexpr int8_t DUMMY_CONTROL = static_cast(0x82); // 元素正在写入中 - static constexpr int8_t BUSY_CONTROL = 0x81; + static constexpr int8_t BUSY_CONTROL = static_cast(0x81); // 可用未知当前也没有写入过元素 - static constexpr int8_t EMPTY_CONTROL = 0x80; + static constexpr int8_t EMPTY_CONTROL = static_cast(0x80); static_assert(sizeof(int8_t) == sizeof(::std::atomic) && alignof(int8_t) == alignof(::std::atomic), @@ -552,7 +552,7 @@ inline bool ConcurrentFixedSwissTable::empty() const noexcept { template inline size_t ConcurrentFixedSwissTable::size() const noexcept { - return _size.value(); + return static_cast(_size.value()); } template diff --git a/src/babylon/executor.cpp b/src/babylon/executor.cpp index fbe16947..fd35db08 100644 --- a/src/babylon/executor.cpp +++ b/src/babylon/executor.cpp @@ -15,7 +15,12 @@ int Executor::invoke(MoveOnlyFunction&&) noexcept { //////////////////////////////////////////////////////////////////////////////// // InplaceExecutor begin InplaceExecutor& InplaceExecutor::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static InplaceExecutor executor; +#pragma GCC diagnostic pop return executor; } @@ -51,7 +56,12 @@ int InplaceExecutor::invoke(MoveOnlyFunction&& function) noexcept { //////////////////////////////////////////////////////////////////////////////// // AlwaysUseNewThreadExecutor begin AlwaysUseNewThreadExecutor& AlwaysUseNewThreadExecutor::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static AlwaysUseNewThreadExecutor executor; +#pragma GCC diagnostic pop return executor; } diff --git a/src/babylon/logging/async_file_appender.cpp b/src/babylon/logging/async_file_appender.cpp index 5391318d..956a77e5 100644 --- a/src/babylon/logging/async_file_appender.cpp +++ b/src/babylon/logging/async_file_appender.cpp @@ -36,8 +36,13 @@ void AsyncFileAppender::write(LogEntry& entry, FileObject* file) noexcept { } void AsyncFileAppender::discard(LogEntry& entry) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static thread_local ::std::vector iov; static thread_local ::std::vector pages; +#pragma GCC diagnostic pop entry.append_to_iovec(_page_allocator->page_size(), iov); for (auto& one_iov : iov) { @@ -98,7 +103,6 @@ void AsyncFileAppender::keep_writing() noexcept { // 当一轮日志量过低时,拉长下一轮写入的周期 // 尝试进行有效的批量写入 if (poped < 100) { - _backoff_us += 10; _backoff_us = ::std::min(_backoff_us + 10, 100000); ::usleep(_backoff_us); } else if (poped >= batch) { @@ -123,13 +127,18 @@ AsyncFileAppender::Destination& AsyncFileAppender::destination( void AsyncFileAppender::write_use_plain_writev(Destination& dest, int fd) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static thread_local ::std::vector pages; +#pragma GCC diagnostic pop auto& iov = dest.iov; for (auto iter = iov.begin(); iter < iov.end();) { auto piov = &*iter; - auto size = ::std::min(IOV_MAX, iov.end() - iter); - for (size_t i = 0; i < size; ++i) { + auto size = ::std::min(IOV_MAX, iov.end() - iter); + for (ssize_t i = 0; i < size; ++i) { pages.emplace_back(piov[i].iov_base); } auto written = ::writev(fd, piov, size); diff --git a/src/babylon/logging/file_object.cpp b/src/babylon/logging/file_object.cpp index 6aa1b986..e97e04af 100644 --- a/src/babylon/logging/file_object.cpp +++ b/src/babylon/logging/file_object.cpp @@ -19,7 +19,12 @@ size_t FileObject::index() const noexcept { //////////////////////////////////////////////////////////////////////////////// // StderrFileObject begin StderrFileObject& StderrFileObject::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static StderrFileObject object; +#pragma GCC diagnostic pop return object; } diff --git a/src/babylon/logging/interface.cpp b/src/babylon/logging/interface.cpp index 0014f6d2..0ef8dfc2 100644 --- a/src/babylon/logging/interface.cpp +++ b/src/babylon/logging/interface.cpp @@ -27,7 +27,12 @@ class DefaultLogStreamProvider : public LogStreamProvider { public: virtual LogStream& stream(int severity, StringView file, int line) noexcept override { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static thread_local DefaultLogStream stream; +#pragma GCC diagnostic pop stream.set_severity(static_cast(severity)); stream.set_file(file); stream.set_line(line); @@ -37,7 +42,12 @@ class DefaultLogStreamProvider : public LogStreamProvider { #if __cplusplus < 201703L constexpr StringView DefaultLogStreamProvider::SEVERITY_NAME[]; #endif // __cplusplus < 201703L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static DefaultLogStreamProvider s_default_provider; +#pragma GCC diagnostic pop // DefaultLogStreamProvider end //////////////////////////////////////////////////////////////////////////////// @@ -51,7 +61,12 @@ void LogInterface::set_min_severity(int severity) noexcept { void LogInterface::set_provider( ::std::unique_ptr&& provider) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static ::std::unique_ptr s_provider; +#pragma GCC diagnostic pop s_provider = ::std::move(provider); if (s_provider) { _s_provider = s_provider.get(); diff --git a/src/babylon/logging/log_entry.cpp b/src/babylon/logging/log_entry.cpp index 67e7bb87..0598fbad 100644 --- a/src/babylon/logging/log_entry.cpp +++ b/src/babylon/logging/log_entry.cpp @@ -80,7 +80,7 @@ int LogStreamBuffer::overflow(int ch) noexcept { int LogStreamBuffer::sync() noexcept { auto ptr = pptr(); if (ptr > _sync_point) { - _log.size += ptr - _sync_point; + _log.size += static_cast(ptr - _sync_point); _sync_point = ptr; } return 0; diff --git a/src/babylon/logging/log_severity.h b/src/babylon/logging/log_severity.h index 1df752db..c9f5be4e 100644 --- a/src/babylon/logging/log_severity.h +++ b/src/babylon/logging/log_severity.h @@ -28,14 +28,14 @@ class LogSeverity { const LogSeverity&) noexcept = default; inline ~LogSeverity() noexcept = default; - inline constexpr LogSeverity(int8_t value) noexcept; + inline constexpr LogSeverity(uint8_t value) noexcept; - inline constexpr operator int8_t() const noexcept; + inline constexpr operator uint8_t() const noexcept; inline constexpr operator StringView() const noexcept; private: - int8_t _value {DEBUG}; + uint8_t _value {DEBUG}; static constexpr StringView names[NUM] = { [DEBUG] = "DEBUG", @@ -45,10 +45,10 @@ class LogSeverity { }; }; -inline constexpr LogSeverity::LogSeverity(int8_t value) noexcept +inline constexpr LogSeverity::LogSeverity(uint8_t value) noexcept : _value {value} {} -inline constexpr LogSeverity::operator int8_t() const noexcept { +inline constexpr LogSeverity::operator uint8_t() const noexcept { return _value; } diff --git a/src/babylon/logging/log_stream.cpp b/src/babylon/logging/log_stream.cpp index 9d4c50e2..0bd62373 100644 --- a/src/babylon/logging/log_stream.cpp +++ b/src/babylon/logging/log_stream.cpp @@ -4,6 +4,9 @@ #include "absl/time/clock.h" // absl::Now +#include // __NR_gettid +#include // ::syscall + #include // std::cerr BABYLON_NAMESPACE_BEGIN @@ -53,10 +56,11 @@ void DefaultLogStream::do_begin() noexcept { ::babylon::localtime(&now_s, &time_struct); mutex().lock(); (*this) << severity(); - format(" %d-%02d-%02d %02d:%02d:%02d.%06d %.*s:%d] ", + thread_local int tid = ::syscall(__NR_gettid); + format(" %d-%02d-%02d %02d:%02d:%02d.%06d %d %.*s:%d] ", time_struct.tm_year + 1900, time_struct.tm_mon + 1, time_struct.tm_mday, time_struct.tm_hour, time_struct.tm_min, - time_struct.tm_sec, us, file().size(), file().data(), line()); + time_struct.tm_sec, us, tid, file().size(), file().data(), line()); } void DefaultLogStream::do_end() noexcept { @@ -77,7 +81,12 @@ NullLogStream::NullLogStream() noexcept #endif // !__clang__ && BABYLON_GCC_VERSION < 50000 NullLogStream::Buffer& NullLogStream::buffer() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static Buffer static_buffer; +#pragma GCC diagnostic pop return static_buffer; } // NullLogStream end diff --git a/src/babylon/logging/log_stream.h b/src/babylon/logging/log_stream.h index 5d77a0f8..3bf8179a 100644 --- a/src/babylon/logging/log_stream.h +++ b/src/babylon/logging/log_stream.h @@ -239,7 +239,7 @@ inline LogStream& LogStream::end() noexcept { } inline LogStream& LogStream::write(const char* data, size_t size) noexcept { - rdbuf()->sputn(data, size); + rdbuf()->sputn(data, static_cast(size)); return *this; } diff --git a/src/babylon/logging/logger.cpp b/src/babylon/logging/logger.cpp index 55433f33..8f03ed64 100644 --- a/src/babylon/logging/logger.cpp +++ b/src/babylon/logging/logger.cpp @@ -6,18 +6,23 @@ BABYLON_NAMESPACE_BEGIN Logger::Logger() noexcept : _min_severity {LogSeverity::DEBUG}, _initialized {false} { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static ThreadLocalLogStream default_log_stream { [](::std::unique_ptr* ptr) { new (ptr)::std::unique_ptr {new DefaultLogStream}; }}; - for (size_t i = 0; i < static_cast(LogSeverity::NUM); ++i) { +#pragma GCC diagnostic pop + for (size_t i = 0; i < LogSeverity::NUM; ++i) { _log_streams[i].store(&default_log_stream, ::std::memory_order_relaxed); } } Logger::Logger(const Logger& other) noexcept : _min_severity {other._min_severity}, _initialized {other._initialized} { - for (size_t i = 0; i < static_cast(LogSeverity::NUM); ++i) { + for (size_t i = 0; i < LogSeverity::NUM; ++i) { _log_streams[i].store( other._log_streams[i].load(::std::memory_order_relaxed), ::std::memory_order_relaxed); @@ -25,7 +30,7 @@ Logger::Logger(const Logger& other) noexcept } Logger& Logger::operator=(const Logger& other) noexcept { - for (size_t i = 0; i < static_cast(LogSeverity::NUM); ++i) { + for (size_t i = 0; i < LogSeverity::NUM; ++i) { _log_streams[i].store( other._log_streams[i].load(::std::memory_order_relaxed), ::std::memory_order_relaxed); @@ -37,13 +42,17 @@ Logger& Logger::operator=(const Logger& other) noexcept { LogStream& Logger::stream(LogSeverity severity, StringView file, int line) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static NullLogStream nls; +#pragma GCC diagnostic pop // TODO(oathdruid): remove this after remove LogStreamProvider in interface.h if (ABSL_PREDICT_FALSE(!_initialized)) { - if (static_cast(severity) >= LogInterface::min_severity()) { - return LogInterface::provider().stream(static_cast(severity), file, - line); + if (severity >= LogInterface::min_severity()) { + return LogInterface::provider().stream(severity, file, line); } return nls; } @@ -52,9 +61,8 @@ LogStream& Logger::stream(LogSeverity severity, StringView file, return nls; } - auto& stream = *_log_streams[static_cast(severity)] - .load(::std::memory_order_acquire) - ->local(); + auto& stream = + *_log_streams[severity].load(::std::memory_order_acquire)->local(); stream.set_severity(severity); stream.set_file(file); stream.set_line(line); @@ -71,14 +79,13 @@ void Logger::set_min_severity(LogSeverity min_severity) noexcept { void Logger::set_log_stream(LogSeverity severity, ThreadLocalLogStream& log_stream) noexcept { - _log_streams[static_cast(severity)].store(&log_stream, - ::std::memory_order_release); + _log_streams[severity].store(&log_stream, ::std::memory_order_release); } //////////////////////////////////////////////////////////////////////////////// // LoggerBuilder begin LoggerBuilder::LoggerBuilder() noexcept : _min_severity {LogSeverity::INFO} { - for (int i = 0; i < static_cast(LogSeverity::NUM); ++i) { + for (size_t i = 0; i < LogSeverity::NUM; ++i) { auto severity = static_cast(i); _log_streams[i].first = severity; _log_streams[i].second.set_constructor( @@ -101,7 +108,7 @@ Logger LoggerBuilder::build() noexcept { void LoggerBuilder::set_log_stream_creator( LoggerBuilder::Creator creator) noexcept { - for (int i = 0; i < static_cast(LogSeverity::NUM); ++i) { + for (size_t i = 0; i < LogSeverity::NUM; ++i) { auto severity = static_cast(i); auto& stream = _log_streams[i].second; stream.set_constructor( @@ -114,7 +121,7 @@ void LoggerBuilder::set_log_stream_creator( void LoggerBuilder::set_log_stream_creator( LogSeverity severity, LoggerBuilder::Creator creator) noexcept { - auto& stream = _log_streams[static_cast(severity)].second; + auto& stream = _log_streams[severity].second; stream.set_constructor( [severity, creator](::std::unique_ptr* ptr) { new (ptr)::std::unique_ptr {creator()}; @@ -131,7 +138,12 @@ void LoggerBuilder::set_min_severity(LogSeverity min_severity) noexcept { //////////////////////////////////////////////////////////////////////////////// // LoggerManager begin LoggerManager& LoggerManager::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static LoggerManager object; +#pragma GCC diagnostic pop return object; } diff --git a/src/babylon/logging/logger.h b/src/babylon/logging/logger.h index 6a41d501..e3344bde 100644 --- a/src/babylon/logging/logger.h +++ b/src/babylon/logging/logger.h @@ -24,10 +24,9 @@ class Logger final { private: using ThreadLocalLogStream = EnumerableThreadLocal<::std::unique_ptr>; - using Storage = ::std::array(LogSeverity::NUM)>; - using PointerStorage = ::std::array<::std::atomic, - static_cast(LogSeverity::NUM)>; + using Storage = ::std::array; + using PointerStorage = + ::std::array<::std::atomic, LogSeverity::NUM>; Logger(const Logger& other) noexcept; Logger& operator=(const Logger& other) noexcept; @@ -62,7 +61,7 @@ class LoggerBuilder final { private: using Storage = ::std::array<::std::pair, - static_cast(LogSeverity::NUM)>; + LogSeverity::NUM>; Storage _log_streams; LogSeverity _min_severity; }; diff --git a/src/babylon/mlock.cpp b/src/babylon/mlock.cpp index b8db37fa..8620f021 100644 --- a/src/babylon/mlock.cpp +++ b/src/babylon/mlock.cpp @@ -64,7 +64,12 @@ int MemoryLocker::last_errno() const noexcept { } MemoryLocker& MemoryLocker::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static MemoryLocker object; +#pragma GCC diagnostic pop return object; } diff --git a/src/babylon/protect.h b/src/babylon/protect.h index 78cc18e8..3c396ab9 100644 --- a/src/babylon/protect.h +++ b/src/babylon/protect.h @@ -26,7 +26,10 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" -#pragma GCC diagnostic ignored "-Wc99-designator" +#pragma GCC diagnostic ignored \ + "-Wc99-designator" // Things like T[] {[0] = value0, [1] = value1} +#pragma GCC diagnostic ignored \ + "-Wc++20-compat" // Things like T {.field1 = value1, .field2 = value2} #else // BAIDU_PROTECT_H #error("protect.h without unprotect.h") diff --git a/src/babylon/reusable/memory_resource.cpp b/src/babylon/reusable/memory_resource.cpp index f04e557c..0ba42d66 100644 --- a/src/babylon/reusable/memory_resource.cpp +++ b/src/babylon/reusable/memory_resource.cpp @@ -26,7 +26,12 @@ memory_resource* new_delete_resource() noexcept { } }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static R resource; +#pragma GCC diagnostic pop return &resource; } @@ -62,7 +67,7 @@ bool MonotonicBufferResource::do_is_equal( //////////////////////////////////////////////////////////////////////////////// // ExclusiveMonotonicBufferResource begin size_t ExclusiveMonotonicBufferResource::allocate_oversize_page_num() noexcept { - return oversize_page_concurrent_adder().value(); + return static_cast(oversize_page_concurrent_adder().value()); } ExclusiveMonotonicBufferResource::ExclusiveMonotonicBufferResource( @@ -239,13 +244,13 @@ void ExclusiveMonotonicBufferResource::release() noexcept { char* tmp_pages[PAGE_ARRAY_CAPACITY]; while (_last_page_array != nullptr) { SanitizerHelper::unpoison(_last_page_array); - auto size = - _last_page_array->pages + PAGE_ARRAY_CAPACITY - _last_page_pointer; + auto size = static_cast(_last_page_array->pages + + PAGE_ARRAY_CAPACITY - _last_page_pointer); _last_page_array = _last_page_array->next; //将pages的地址提前拷一份存起来, //避免当page_rray持有自己时,page_rray所在的page被提前释放后_last_page_pointer失效 - for (auto i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) { tmp_pages[i] = SanitizerHelper::unpoison(_last_page_pointer[i], _page_allocator->page_size()); } @@ -308,7 +313,12 @@ bool ExclusiveMonotonicBufferResource::contains(const void* ptr) noexcept { ConcurrentAdder& ExclusiveMonotonicBufferResource::oversize_page_concurrent_adder() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static ConcurrentAdder _oversize_page_concurrent_adder; +#pragma GCC diagnostic pop return _oversize_page_concurrent_adder; } // ExclusiveMonotonicBufferResource end diff --git a/src/babylon/reusable/message.cpp b/src/babylon/reusable/message.cpp index c610ca65..075ce73c 100644 --- a/src/babylon/reusable/message.cpp +++ b/src/babylon/reusable/message.cpp @@ -121,14 +121,14 @@ void MessageAllocationMetadata::FieldAllocationMetadata::update_repeated_field( const ::google::protobuf::Message& message, const ::google::protobuf::Reflection* reflection) noexcept { switch (descriptor->cpp_type()) { -#define __BABYLON_TMP_CASE(case_enum, type) \ - case ::google::protobuf::FieldDescriptor::case_enum: { \ - size_t capacity = \ - reflection->GetRepeatedField(message, descriptor).Capacity(); \ - if (repeated_reserved < capacity) { \ - repeated_reserved = capacity; \ - } \ - break; \ +#define __BABYLON_TMP_CASE(case_enum, type) \ + case ::google::protobuf::FieldDescriptor::case_enum: { \ + auto capacity = static_cast( \ + reflection->GetRepeatedField(message, descriptor).Capacity()); \ + if (repeated_reserved < capacity) { \ + repeated_reserved = capacity; \ + } \ + break; \ } __BABYLON_TMP_CASE(CPPTYPE_INT32, int32_t) __BABYLON_TMP_CASE(CPPTYPE_UINT32, uint32_t) @@ -138,28 +138,29 @@ void MessageAllocationMetadata::FieldAllocationMetadata::update_repeated_field( __BABYLON_TMP_CASE(CPPTYPE_FLOAT, float) __BABYLON_TMP_CASE(CPPTYPE_BOOL, bool) case ::google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { - size_t capacity = - get_repeated_enum_field(message, reflection, descriptor).Capacity(); + auto capacity = static_cast( + get_repeated_enum_field(message, reflection, descriptor).Capacity()); if (repeated_reserved < capacity) { repeated_reserved = capacity; } break; } #undef __BABYLON_TMP_CASE -#define __BABYLON_TMP_CASE(case_enum, type) \ - case ::google::protobuf::FieldDescriptor::case_enum: { \ - auto& repeated_field = \ - reflection->GetRepeatedPtrField(message, descriptor); \ - size_t capacity = repeated_field.size() + repeated_field.ClearedCount(); \ - if (repeated_reserved < capacity) { \ - repeated_reserved = capacity; \ - } \ - auto begin = repeated_field.cbegin(); \ - auto end = repeated_field.cbegin() + capacity; \ - for (; begin != end; ++begin) { \ - update(*begin); \ - } \ - break; \ +#define __BABYLON_TMP_CASE(case_enum, type) \ + case ::google::protobuf::FieldDescriptor::case_enum: { \ + auto& repeated_field = \ + reflection->GetRepeatedPtrField(message, descriptor); \ + auto capacity = static_cast(repeated_field.size() + \ + repeated_field.ClearedCount()); \ + if (repeated_reserved < capacity) { \ + repeated_reserved = capacity; \ + } \ + auto begin = repeated_field.cbegin(); \ + auto end = repeated_field.cbegin() + static_cast(capacity); \ + for (; begin != end; ++begin) { \ + update(*begin); \ + } \ + break; \ } __BABYLON_TMP_CASE(CPPTYPE_STRING, ::std::string) __BABYLON_TMP_CASE(CPPTYPE_MESSAGE, ::google::protobuf::Message) @@ -196,11 +197,14 @@ void MessageAllocationMetadata::FieldAllocationMetadata::reserve_repeated_field( auto* repeated_field = reflection->MutableRepeatedPtrField<::std::string>( &message, descriptor); repeated_field->Reserve(repeated_reserved); - for (size_t i = repeated_field->size(); i < repeated_reserved; ++i) { + for (size_t i = static_cast(repeated_field->size()); + i < repeated_reserved; ++i) { #if GOOGLE_PROTOBUF_HAS_DONATED_STRING - repeated_field->AddAccessor()->reserve(string_reserved); + repeated_field->AddAccessor()->reserve( + static_cast(string_reserved)); #else // !GOOGLE_PROTOBUF_HAS_DONATED_STRING - stable_reserve(*repeated_field->Add(), string_reserved); + stable_reserve(*repeated_field->Add(), + static_cast(string_reserved)); #endif // !GOOGLE_PROTOBUF_HAS_DONATED_STRING } repeated_field->Clear(); diff --git a/src/babylon/reusable/message.h b/src/babylon/reusable/message.h index a64584b5..13c25985 100644 --- a/src/babylon/reusable/message.h +++ b/src/babylon/reusable/message.h @@ -166,8 +166,8 @@ class ReusableTraits<::google::protobuf::Message> static Message* create_with_allocation_metadata( SwissAllocator<> allocator, const AllocationMetadata& metadata) { - auto instance = - metadata.default_instance->New(&(Arena&)*allocator.resource()); + auto instance = metadata.default_instance->New( + &static_cast(*allocator.resource())); metadata.metadata.reserve(*instance); return instance; } diff --git a/src/babylon/reusable/message.trick.cpp b/src/babylon/reusable/message.trick.cpp index f32b9fd3..ecd2c572 100644 --- a/src/babylon/reusable/message.trick.cpp +++ b/src/babylon/reusable/message.trick.cpp @@ -128,13 +128,13 @@ void MessageAllocationMetadata::FieldAllocationMetadata::reserve_string_field( #else // GOOGLE_PROTOBUF_VERSION < 3020000 ArenaStringPtr::EmptyDefault {}, arena, donated, donating_states, mask); #endif // GOOGLE_PROTOBUF_VERSION < 3020000 - stable_reserve(string, string_reserved); + stable_reserve(string, static_cast(string_reserved)); } else #endif // GOOGLE_PROTOBUF_VERSION < 3018000 { reserve_arena_string_ptr(*reinterpret_cast(ptr), descriptor->has_default_value(), default_string, - string_reserved, arena); + static_cast(string_reserved), arena); } } diff --git a/src/babylon/reusable/page_allocator.cpp b/src/babylon/reusable/page_allocator.cpp index 7ac482e3..47891a8e 100644 --- a/src/babylon/reusable/page_allocator.cpp +++ b/src/babylon/reusable/page_allocator.cpp @@ -57,12 +57,17 @@ void SystemPageAllocator::deallocate(void** pages, size_t num) noexcept { } SystemPageAllocator& SystemPageAllocator::instance() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static SystemPageAllocator object; +#pragma GCC diagnostic pop return object; } SystemPageAllocator::SystemPageAllocator() noexcept { - _allocator.set_page_size(::sysconf(_SC_PAGE_SIZE)); + _allocator.set_page_size(static_cast(::sysconf(_SC_PAGE_SIZE))); } // SystemPageAllocator end //////////////////////////////////////////////////////////////////////////////// @@ -93,8 +98,8 @@ size_t CachedPageAllocator::page_size() const noexcept { void CachedPageAllocator::allocate(void** pages, size_t num) noexcept { auto pages_end = pages + num; - auto need_pop_num = ::std::min(num, _free_pages.capacity()); - ssize_t hit_num = need_pop_num; + auto need_pop_num = ::std::min(num, _free_pages.capacity()); + ssize_t hit_num = static_cast(need_pop_num); // 优先从缓存队列中申请,穿透时从上游申请作为补偿 _free_pages.pop_n( [&](Iterator begin, Iterator end) { @@ -120,7 +125,7 @@ void CachedPageAllocator::deallocate(void** pages, size_t num) noexcept { // 优先释放到缓存队列中,溢出时释放给上游作为补偿 _free_pages.push_n( [&](Iterator begin, Iterator end) { - size_t n = end - begin; + auto n = static_cast(end - begin); ::std::copy_n(pages, n, begin); pages += n; }, @@ -158,8 +163,9 @@ BatchPageAllocator::~BatchPageAllocator() noexcept { while (iter != end) { auto& local = *iter++; if (local.next_page < local.buffer.end()) { - _upstream->deallocate(&*local.next_page, - local.buffer.end() - local.next_page); + _upstream->deallocate( + &*local.next_page, + static_cast(local.buffer.end() - local.next_page)); } } }); @@ -211,7 +217,8 @@ void CountingPageAllocator::set_upstream(PageAllocator& upstream) noexcept { } size_t CountingPageAllocator::allocated_page_num() noexcept { - return ::std::max(0, _allocate_page_num.value()); + return static_cast( + ::std::max(0, _allocate_page_num.value())); } size_t CountingPageAllocator::page_size() const noexcept { @@ -274,7 +281,8 @@ void PageHeap::deallocate(void** pages, size_t num) noexcept { } size_t PageHeap::allocate_page_num() const noexcept { - return ::std::max(0, _allocate_page_num.value()); + return static_cast( + ::std::max(0, _allocate_page_num.value())); } size_t PageHeap::free_page_num() const noexcept { @@ -291,7 +299,12 @@ typename ConcurrentSummer::Summary PageHeap::cache_hit_summary() } PageHeap& PageHeap::system_page_heap() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static PageHeap object; +#pragma GCC diagnostic pop return object; } diff --git a/src/babylon/serialization/scalar.h b/src/babylon/serialization/scalar.h index 7e1033df..88c104a1 100644 --- a/src/babylon/serialization/scalar.h +++ b/src/babylon/serialization/scalar.h @@ -17,18 +17,18 @@ BABYLON_NAMESPACE_BEGIN static constexpr int SERIALIZED_SIZE_COMPLEXITY = \ SerializationHelper::SERIALIZED_SIZE_COMPLEXITY_SIMPLE; \ static void serialize(const type& value, CodedOutputStream& os) noexcept { \ - os.WriteVarint32(value); \ + os.WriteVarint32(static_cast(value)); \ } \ static bool deserialize(CodedInputStream& is, type& value) noexcept { \ uint32_t uvalue; \ if (ABSL_PREDICT_FALSE(!is.ReadVarint32(&uvalue))) { \ return false; \ } \ - value = uvalue; \ + value = static_cast(uvalue); \ return true; \ } \ static size_t calculate_serialized_size(const type& value) noexcept { \ - return CodedOutputStream::VarintSize32(value); \ + return CodedOutputStream::VarintSize32(static_cast(value)); \ } \ static bool print(const type& value, PrintStream& ps) noexcept { \ return ps.print_raw(::std::to_string(value)); \ @@ -55,18 +55,18 @@ BABYLON_TMP_GEN(uint32_t); static constexpr int SERIALIZED_SIZE_COMPLEXITY = \ SerializationHelper::SERIALIZED_SIZE_COMPLEXITY_SIMPLE; \ static void serialize(const type& value, CodedOutputStream& os) noexcept { \ - os.WriteVarint64(value); \ + os.WriteVarint64(static_cast(value)); \ } \ static bool deserialize(CodedInputStream& is, type& value) noexcept { \ uint64_t uvalue; \ if (ABSL_PREDICT_FALSE(!is.ReadVarint64(&uvalue))) { \ return false; \ } \ - value = uvalue; \ + value = static_cast(uvalue); \ return true; \ } \ static size_t calculate_serialized_size(const type& value) noexcept { \ - return CodedOutputStream::VarintSize64(value); \ + return CodedOutputStream::VarintSize64(static_cast(value)); \ } \ static bool print(const type& value, PrintStream& ps) noexcept { \ return ps.print_raw(::std::to_string(value)); \ diff --git a/src/babylon/serialization/string.h b/src/babylon/serialization/string.h index 415a78cd..6c977132 100644 --- a/src/babylon/serialization/string.h +++ b/src/babylon/serialization/string.h @@ -31,7 +31,8 @@ class SerializeTraits<::std::basic_string> int size; value.clear(); while (is.GetDirectBufferPointer(&data, &size)) { - value.append(reinterpret_cast(data), size); + value.append(reinterpret_cast(data), + static_cast(size)); is.Skip(size); } return true; diff --git a/src/babylon/serialization/traits.cpp b/src/babylon/serialization/traits.cpp index 9933f70e..475aef82 100644 --- a/src/babylon/serialization/traits.cpp +++ b/src/babylon/serialization/traits.cpp @@ -26,10 +26,15 @@ ::absl::flat_hash_map<::std::string, ::std::unique_ptr, ::std::hash, ::std::equal_to>& Serialization::serializers() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" static ::absl::flat_hash_map<::std::string, ::std::unique_ptr, ::std::hash, ::std::equal_to> instance; +#pragma GCC diagnostic pop return instance; } // Serialization end @@ -90,7 +95,7 @@ bool Serialization::PrintStream::print_raw(const char* data, return false; } _buffer = static_cast(buffer); - _buffer_size = buffer_size; + _buffer_size = static_cast(buffer_size); } ::memcpy(_buffer, data, size); _buffer += size; @@ -135,7 +140,7 @@ bool Serialization::PrintStream::print_blank(size_t size) noexcept { return false; } _buffer = static_cast(buffer); - _buffer_size = buffer_size; + _buffer_size = static_cast(buffer_size); } ::memset(_buffer, ' ', size); _buffer += size; diff --git a/src/babylon/serialization/traits.hpp b/src/babylon/serialization/traits.hpp index 1d87c305..96dd580a 100644 --- a/src/babylon/serialization/traits.hpp +++ b/src/babylon/serialization/traits.hpp @@ -198,7 +198,8 @@ struct SerializationHelper { if CONSTEXPR_SINCE_CXX17 (SerializeTraits::WIRE_TYPE == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { uint32_t length; - auto saved_limit = is.PushLimit(is.ReadVarint32(&length) ? length : 0); + auto saved_limit = + is.PushLimit(is.ReadVarint32(&length) ? static_cast(length) : 0); auto success = SerializeTraits::deserialize(is, value); is.PopLimit(saved_limit); return success; @@ -275,7 +276,8 @@ struct SerializationHelper { if CONSTEXPR_SINCE_CXX17 (SerializeTraits::WIRE_TYPE == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { uint32_t length; - auto saved_limit = is.PushLimit(is.ReadVarint32(&length) ? length : 0); + auto saved_limit = + is.PushLimit(is.ReadVarint32(&length) ? static_cast(length) : 0); auto success = SerializeTraits::deserialize(is, value); is.PopLimit(saved_limit); return success; diff --git a/src/babylon/serialization/vector.h b/src/babylon/serialization/vector.h index bc7b2f46..5c2e919b 100644 --- a/src/babylon/serialization/vector.h +++ b/src/babylon/serialization/vector.h @@ -43,7 +43,7 @@ class SerializeTraits<::std::vector> static bool deserialize(CodedInputStream& is, Value& value) noexcept { if CONSTEXPR_SINCE_CXX17 (::std::is_same::value || ::std::is_same::value) { - auto num = is.BytesUntilLimit() / sizeof(T); + auto num = static_cast(is.BytesUntilLimit()) / sizeof(T); value.reserve(value.size() + num); } diff --git a/src/babylon/string_view.hpp b/src/babylon/string_view.hpp index 4acd645f..d41caa2c 100644 --- a/src/babylon/string_view.hpp +++ b/src/babylon/string_view.hpp @@ -419,7 +419,7 @@ inline BABYLON_CONSTEXPR bool operator>=(BasicStringView left, template inline ::std::basic_ostream& operator<<( ::std::basic_ostream& os, BasicStringView view) noexcept { - os.write(view.data(), view.size()); + os.write(view.data(), static_cast(view.size())); return os; } diff --git a/test/BUILD b/test/BUILD index 3a43a8c7..81126500 100644 --- a/test/BUILD +++ b/test/BUILD @@ -3,12 +3,12 @@ package( ) load('@rules_cuda//cuda:defs.bzl', 'cuda_library', 'requires_cuda') -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_any', srcs = ['test_any.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:any', '@com_google_googletest//:gtest_main', @@ -18,7 +18,7 @@ cc_test( cc_test( name = 'test_application_context', srcs = ['test_application_context.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:application_context', '@com_google_googletest//:gtest_main', @@ -28,7 +28,7 @@ cc_test( cc_test( name = 'test_executor', srcs = ['test_executor.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:executor', '@com_google_googletest//:gtest_main', @@ -38,7 +38,7 @@ cc_test( cc_test( name = 'test_future', srcs = ['test_future.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:future', '@com_google_googletest//:gtest_main', @@ -48,7 +48,7 @@ cc_test( cc_test( name = 'test_mlock', srcs = ['test_mlock.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:mlock', '@com_google_googletest//:gtest_main', @@ -58,7 +58,7 @@ cc_test( cc_test( name = 'test_move_only_function', srcs = ['test_move_only_function.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:move_only_function', '@com_google_googletest//:gtest_main', @@ -68,7 +68,7 @@ cc_test( cc_test( name = 'test_string', srcs = ['test_string.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:string', '@com_google_googletest//:gtest_main', @@ -88,7 +88,7 @@ cuda_library( cc_test( name = 'test_string_view', srcs = ['test_string_view.cpp', 'test_string_view.h', 'test_string_view_in_lib.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:string_view', '@com_google_googletest//:gtest_main', @@ -101,7 +101,7 @@ cc_test( cc_test( name = 'test_time', srcs = ['test_time.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:time', '@com_google_googletest//:gtest_main', @@ -111,7 +111,7 @@ cc_test( cc_test( name = 'test_type_traits', srcs = ['test_type_traits.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:type_traits', '@com_google_googletest//:gtest_main', diff --git a/test/anyflow/BUILD b/test/anyflow/BUILD index 537fca89..2977c59f 100644 --- a/test/anyflow/BUILD +++ b/test/anyflow/BUILD @@ -2,12 +2,12 @@ package( default_visibility = [':__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_builder', srcs = ['test_builder.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -17,7 +17,7 @@ cc_test( cc_test( name = 'test_channel', srcs = ['test_channel.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -27,7 +27,7 @@ cc_test( cc_test( name = 'test_closure', srcs = ['test_closure.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -37,7 +37,7 @@ cc_test( cc_test( name = 'test_data', srcs = ['test_data.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -47,7 +47,7 @@ cc_test( cc_test( name = 'test_dependency', srcs = ['test_dependency.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -57,7 +57,7 @@ cc_test( cc_test( name = 'test_processor', srcs = ['test_processor.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '//:reusable_string', diff --git a/test/anyflow/builtin/BUILD b/test/anyflow/builtin/BUILD index 6853c963..bb1e5f59 100644 --- a/test/anyflow/builtin/BUILD +++ b/test/anyflow/builtin/BUILD @@ -2,12 +2,12 @@ package( default_visibility = ['//:__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_const', srcs = ['test_const.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -17,7 +17,7 @@ cc_test( cc_test( name = 'test_expression', srcs = ['test_expression.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', @@ -27,7 +27,7 @@ cc_test( cc_test( name = 'test_select', srcs = ['test_select.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:anyflow', '@com_google_googletest//:gtest_main', diff --git a/test/anyflow/test_processor.cpp b/test/anyflow/test_processor.cpp index 004d6282..a232348a 100644 --- a/test/anyflow/test_processor.cpp +++ b/test/anyflow/test_processor.cpp @@ -313,7 +313,7 @@ TEST_F(ProcessorTest, any_accept_any_type) { vertex.named_emit("x").to("E"); ASSERT_EQ(0, builder.finish()); graph = builder.build(); - ASSERT_TRUE((bool)graph); + ASSERT_TRUE(graph); a = graph->find_data("A"); b = graph->find_data("B"); c = graph->find_data("C"); @@ -342,7 +342,7 @@ TEST_F(ProcessorTest, mutable_data_get_non_const_pointer) { vertex.named_emit("x").to("E"); ASSERT_EQ(0, builder.finish()); graph = builder.build(); - ASSERT_TRUE((bool)graph); + ASSERT_TRUE(graph); a = graph->find_data("A"); b = graph->find_data("B"); c = graph->find_data("C"); @@ -388,7 +388,7 @@ TEST_F(ProcessorTest, downstream_function_run_before_current_one_return) { v2.named_emit("x").to("X3"); ASSERT_EQ(0, builder.finish()); graph = builder.build(); - ASSERT_TRUE((bool)graph); + ASSERT_TRUE(graph); auto* x1 = graph->find_data("X1"); auto* x3 = graph->find_data("X3"); *x1->emit() = 1; @@ -453,7 +453,7 @@ TEST_F(ProcessorTest, v3.named_emit("x").to("X4"); ASSERT_EQ(0, builder.finish()); graph = builder.build(); - ASSERT_TRUE((bool)graph); + ASSERT_TRUE(graph); auto* x1 = graph->find_data("X1"); auto* x4 = graph->find_data("X4"); *x1->emit() = 1; @@ -490,7 +490,7 @@ TEST_F(ProcessorTest, depend_essential) { v2.named_emit("x").to("X2"); ASSERT_EQ(0, builder.finish()); graph = builder.build(); - ASSERT_TRUE((bool)graph); + ASSERT_TRUE(graph); a = graph->find_data("A"); auto* x1 = graph->find_data("X1"); auto* x2 = graph->find_data("X2"); diff --git a/test/concurrent/BUILD b/test/concurrent/BUILD index 0b9f4369..48666e86 100644 --- a/test/concurrent/BUILD +++ b/test/concurrent/BUILD @@ -2,12 +2,12 @@ package( default_visibility = [':__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_bounded_queue', srcs = ['test_bounded_queue.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_bounded_queue', '//:logging_interface', @@ -18,7 +18,7 @@ cc_test( cc_test( name = 'test_bounded_queue_press_mpmc', srcs = ['test_bounded_queue_press_mpmc.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_bounded_queue', '//:logging_interface', @@ -29,27 +29,48 @@ cc_test( cc_test( name = 'test_counter', srcs = ['test_counter.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_counter', '@com_google_googletest//:gtest_main', ] ) +cc_test( + name = 'test_epoch', + srcs = ['test_epoch.cpp'], + copts = BABYLON_TEST_COPTS, + deps = [ + '//:concurrent_epoch', + '//:logging_logger', + '@com_google_googletest//:gtest_main', + ] +) + cc_test( name = 'test_execution_queue', srcs = ['test_execution_queue.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_execution_queue', '@com_google_googletest//:gtest_main', ] ) +cc_test( + name = 'test_garbage_collector', + srcs = ['test_garbage_collector.cpp'], + copts = BABYLON_TEST_COPTS, + deps = [ + '//:concurrent_garbage_collector', + '@com_google_googletest//:gtest_main', + ] +) + cc_test( name = 'test_id_allocator', srcs = ['test_id_allocator.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_id_allocator', '@com_google_googletest//:gtest_main', @@ -59,7 +80,7 @@ cc_test( cc_test( name = 'test_object_pool', srcs = ['test_object_pool.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_object_pool', '@com_google_googletest//:gtest_main', @@ -69,7 +90,7 @@ cc_test( cc_test( name = 'test_sched_interface', srcs = ['test_sched_interface.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_sched_interface', '@com_google_googletest//:gtest_main', @@ -79,7 +100,7 @@ cc_test( cc_test( name = 'test_thread_local', srcs = ['test_thread_local.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_thread_local', '@com_google_googletest//:gtest_main', @@ -89,7 +110,7 @@ cc_test( cc_test( name = 'test_transient_hash_table', srcs = ['test_transient_hash_table.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_transient_hash_table', '@com_google_googletest//:gtest_main', @@ -99,7 +120,7 @@ cc_test( cc_test( name = 'test_transient_topic', srcs = ['test_transient_topic.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_transient_topic', '@com_google_googletest//:gtest_main', @@ -109,7 +130,7 @@ cc_test( cc_test( name = 'test_vector', srcs = ['test_vector.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:concurrent_vector', '@com_google_googletest//:gtest_main', diff --git a/test/concurrent/test_epoch.cpp b/test/concurrent/test_epoch.cpp new file mode 100644 index 00000000..73b98520 --- /dev/null +++ b/test/concurrent/test_epoch.cpp @@ -0,0 +1,157 @@ +#include "babylon/concurrent/epoch.h" +#include "babylon/logging/logger.h" + +#include "gtest/gtest.h" + +#include +#include + +using ::babylon::Epoch; +using Accessor = ::babylon::Epoch::Accessor; + +struct EpochTest : public ::testing::Test { + Epoch epoch; +}; + +TEST_F(EpochTest, default_accessor_not_valid) { + Accessor accessor; + ASSERT_FALSE(accessor); + ASSERT_DEATH(accessor.lock(), ""); +} + +TEST_F(EpochTest, accessor_valid_until_release) { + auto accessor = epoch.create_accessor(); + ASSERT_TRUE(accessor); + ::std::lock_guard {accessor}; + accessor.release(); + ASSERT_FALSE(accessor); + accessor.release(); + ASSERT_FALSE(accessor); + ASSERT_DEATH(accessor.lock(), ""); +} + +TEST_F(EpochTest, accessor_auto_release_when_destruct) { + ASSERT_EQ(0, epoch.accessor_number()); + { + auto accessor = epoch.create_accessor(); + ASSERT_EQ(1, epoch.accessor_number()); + } + { + auto accessor = epoch.create_accessor(); + ASSERT_EQ(1, epoch.accessor_number()); + auto accessor2 = epoch.create_accessor(); + ASSERT_EQ(2, epoch.accessor_number()); + } +} + +TEST_F(EpochTest, accessor_movable) { + auto accessor = epoch.create_accessor(); + { + auto accessor_moved = ::std::move(accessor); + ::std::lock_guard {accessor_moved}; + ASSERT_DEATH(accessor.lock(), ""); + + accessor = ::std::move(accessor_moved); + ::std::lock_guard {accessor}; + ASSERT_DEATH(accessor_moved.lock(), ""); + } + ::std::lock_guard {accessor}; +} + +TEST_F(EpochTest, epoch_increase_when_tick) { + for (size_t i = 0; i < 10; ++i) { + ASSERT_EQ(i + 1, epoch.tick()); + } +} + +TEST_F(EpochTest, low_water_mark_count_lowest_accessor_locked) { + ::std::vector accessors; + for (size_t i = 0; i < 10; ++i) { + accessors.emplace_back(epoch.create_accessor()); + } + ASSERT_EQ(UINT64_MAX, epoch.low_water_mark()); + for (size_t i = 0; i < 5; ++i) { + accessors[i].lock(); + epoch.tick(); + } + ASSERT_EQ(0, epoch.low_water_mark()); + for (size_t i = 0; i < 4; ++i) { + accessors[i].unlock(); + ASSERT_EQ(i + 1, epoch.low_water_mark()); + } + accessors[4].unlock(); + ASSERT_EQ(UINT64_MAX, epoch.low_water_mark()); +} + +TEST_F(EpochTest, concurrent_works_fine) { + ::std::atomic<::std::string*> ptr {nullptr}; + ::std::random_device rd; + + ::std::vector<::std::thread> threads; + for (size_t i = 0; i < 128; ++i) { + threads.emplace_back([&] { + ::std::mt19937 gen {rd()}; + size_t sum = 0; + for (size_t i = 0; i < 10000; ++i) { + if (gen() % 2 == 0) { + auto accessor = epoch.create_accessor(); + ::std::lock_guard lock {accessor}; + auto s = ptr.load(::std::memory_order_acquire); + sum += s != nullptr ? ::std::stol(*s) : 0; + } else { + auto s = new ::std::string(::std::to_string(gen())); + auto old_s = ptr.exchange(s, ::std::memory_order_acq_rel); + auto reclaim_version = epoch.tick(); + sum += old_s != nullptr ? ::std::stol(*old_s) : 0; + while (reclaim_version > epoch.low_water_mark()) { + ::sched_yield(); + } + delete old_s; + } + } + BABYLON_LOG(INFO) << "sum = " << sum; + }); + } + + for (auto& thread : threads) { + thread.join(); + } + + delete ptr; +} + +TEST_F(EpochTest, concurrent_works_fine_in_thread_local_style) { + ::std::atomic<::std::string*> ptr {nullptr}; + ::std::random_device rd; + + ::std::vector<::std::thread> threads; + for (size_t i = 0; i < 128; ++i) { + threads.emplace_back([&] { + ::std::mt19937 gen {rd()}; + size_t sum = 0; + for (size_t i = 0; i < 10000; ++i) { + if (gen() % 2 == 0) { + ::std::lock_guard lock {epoch}; + auto s = ptr.load(::std::memory_order_acquire); + sum += s != nullptr ? ::std::stol(*s) : 0; + } else { + auto s = new ::std::string(::std::to_string(gen())); + auto old_s = ptr.exchange(s, ::std::memory_order_acq_rel); + auto reclaim_version = epoch.tick(); + sum += old_s != nullptr ? ::std::stol(*old_s) : 0; + while (reclaim_version > epoch.low_water_mark()) { + ::sched_yield(); + } + delete old_s; + } + } + BABYLON_LOG(INFO) << "sum = " << sum; + }); + } + + for (auto& thread : threads) { + thread.join(); + } + + delete ptr; +} diff --git a/test/concurrent/test_garbage_collector.cpp b/test/concurrent/test_garbage_collector.cpp new file mode 100644 index 00000000..9532dbb4 --- /dev/null +++ b/test/concurrent/test_garbage_collector.cpp @@ -0,0 +1,123 @@ +#include "babylon/concurrent/garbage_collector.h" + +#include "gtest/gtest.h" + +#include + +using ::babylon::Epoch; +using ::babylon::GarbageCollector; +using Accessor = Epoch::Accessor; + +struct GarbageCollectorTest : public ::testing::Test { + struct Reclaimer { + Reclaimer() = default; + Reclaimer(Reclaimer&&) = default; + Reclaimer& operator=(Reclaimer&&) = default; + + Reclaimer(::std::promise&& promise) + : promise {::std::move(promise)} {} + + void operator()() noexcept { + times++; + promise.set_value(); + } + + static size_t times; + + ::std::promise promise; + }; + + virtual void SetUp() override { + Reclaimer::times = 0; + } + + GarbageCollector gc; +}; + +size_t GarbageCollectorTest::Reclaimer::times {0}; + +TEST_F(GarbageCollectorTest, reclaim_if_no_accessor) { + gc.start(); + gc.retire({}); + gc.stop(); + ASSERT_EQ(1, Reclaimer::times); +} + +TEST_F(GarbageCollectorTest, wait_reclaim_on_destroy) { + { + GarbageCollector gc; + gc.start(); + gc.retire({}); + } + ASSERT_EQ(1, Reclaimer::times); +} + +TEST_F(GarbageCollectorTest, accessor_block_further_reclaim) { + ::std::promise p1; + auto f1 = p1.get_future(); + ::std::promise p2; + auto f2 = p2.get_future(); + + auto accessor = gc.epoch().create_accessor(); + gc.start(); + gc.retire(::std::move(p1)); + { + ::std::unique_lock lock {accessor}; + gc.retire(::std::move(p2)); + f1.get(); + ASSERT_EQ(::std::future_status::timeout, + f2.wait_for(::std::chrono::milliseconds(100))); + ASSERT_EQ(1, Reclaimer::times); + } + f2.get(); + ASSERT_EQ(2, Reclaimer::times); + gc.stop(); +} + +TEST_F(GarbageCollectorTest, thread_local_accessor_block_further_reclaim) { + ::std::promise p1; + auto f1 = p1.get_future(); + ::std::promise p2; + auto f2 = p2.get_future(); + + gc.start(); + gc.retire(::std::move(p1)); + { + ::std::unique_lock lock {gc.epoch()}; + gc.retire(::std::move(p2)); + f1.get(); + ASSERT_EQ(::std::future_status::timeout, + f2.wait_for(::std::chrono::milliseconds(100))); + ASSERT_EQ(1, Reclaimer::times); + } + f2.get(); + ASSERT_EQ(2, Reclaimer::times); + gc.stop(); +} + +TEST_F(GarbageCollectorTest, block_retire_when_queue_overflow) { + ::std::promise p1; + auto f1 = p1.get_future(); + + gc.set_queue_capacity(128); + gc.start(); + + ::std::thread t; + { + ::std::unique_lock lock {gc.epoch()}; + t = ::std::thread([&] { + auto lowest_epoch = gc.epoch().tick(); + for (size_t i = 0; i < 2048; ++i) { + gc.retire({}, lowest_epoch); + } + p1.set_value(); + }); + ASSERT_EQ(::std::future_status::timeout, + f1.wait_for(::std::chrono::milliseconds(100))); + } + + f1.get(); + t.join(); + gc.stop(); + ASSERT_EQ(2048, Reclaimer::times); +} diff --git a/test/logging/BUILD b/test/logging/BUILD index 5cc55766..d8df07d6 100644 --- a/test/logging/BUILD +++ b/test/logging/BUILD @@ -2,12 +2,12 @@ package( default_visibility = [':__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_async_file_appender', srcs = ['test_async_file_appender.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_async_file_appender', '@com_google_googletest//:gtest_main', @@ -17,7 +17,7 @@ cc_test( cc_test( name = 'test_async_log_stream', srcs = ['test_async_log_stream.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_async_log_stream', '@com_google_googletest//:gtest_main', @@ -27,7 +27,7 @@ cc_test( cc_test( name = 'test_statically_initialize', srcs = ['test_statically_initialize.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_logger', '@com_google_googletest//:gtest_main', @@ -37,7 +37,7 @@ cc_test( cc_test( name = 'test_interface', srcs = ['test_interface.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_interface', '@com_google_googletest//:gtest_main', @@ -47,7 +47,7 @@ cc_test( cc_test( name = 'test_log_entry', srcs = ['test_log_entry.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_log_entry', '@com_google_googletest//:gtest_main', @@ -57,7 +57,7 @@ cc_test( cc_test( name = 'test_log_stream', srcs = ['test_log_stream.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_log_stream', '@com_google_googletest//:gtest_main', @@ -67,7 +67,7 @@ cc_test( cc_test( name = 'test_logger', srcs = ['test_logger.cpp'], - copts = BABYLON_COPTS + ['-fno-access-control'], + copts = BABYLON_TEST_COPTS + ['-fno-access-control'], deps = [ '//:logging_logger', '@com_google_googletest//:gtest_main', @@ -77,7 +77,7 @@ cc_test( cc_test( name = 'test_log_statically', srcs = ['test_log_statically.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, linkstatic = True, deps = [ '//:logging_logger', @@ -88,7 +88,7 @@ cc_test( cc_test( name = 'test_rolling_file_object', srcs = ['test_rolling_file_object.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:logging_rolling_file_object', '@com_google_googletest//:gtest_main', diff --git a/test/reusable/BUILD b/test/reusable/BUILD index 823e52df..8b568c82 100644 --- a/test/reusable/BUILD +++ b/test/reusable/BUILD @@ -2,12 +2,12 @@ package( default_visibility = [':__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_allocator', srcs = ['test_allocator.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_allocator', '//test/proto', @@ -18,7 +18,7 @@ cc_test( cc_test( name = 'test_manager', srcs = ['test_manager.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_manager', '//:reusable_string', @@ -29,7 +29,7 @@ cc_test( cc_test( name = 'test_memory_resource', srcs = ['test_memory_resource.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_memory_resource', '//test/proto', @@ -40,7 +40,7 @@ cc_test( cc_test( name = 'test_message', srcs = ['test_message.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_manager', '//:reusable_string', @@ -52,7 +52,7 @@ cc_test( cc_test( name = 'test_page_allocator', srcs = ['test_page_allocator.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_page_allocator', '@com_google_googletest//:gtest_main', @@ -62,7 +62,7 @@ cc_test( cc_test( name = 'test_string', srcs = ['test_string.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_string', '@com_google_googletest//:gtest_main', @@ -72,7 +72,7 @@ cc_test( cc_test( name = 'test_traits', srcs = ['test_traits.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_traits', '//test/proto', @@ -83,7 +83,7 @@ cc_test( cc_test( name = 'test_vector', srcs = ['test_vector.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:reusable_vector', '//:reusable_string', diff --git a/test/reusable/test_memory_resource.cpp b/test/reusable/test_memory_resource.cpp index 7cd8f1c6..ba61cab4 100644 --- a/test/reusable/test_memory_resource.cpp +++ b/test/reusable/test_memory_resource.cpp @@ -132,10 +132,10 @@ TEST(ExclusiveMonotonicBufferResource, check_address_inside_resource) { TEST(ExclusiveMonotonicBufferResource, moveable) { ExclusiveMonotonicBufferResource resource; for (size_t i = 0; i < 10; ++i) { - ASSERT_EQ(0, (size_t)resource.allocate(1, 32) % 32); + ASSERT_EQ(0, reinterpret_cast(resource.allocate(1, 32)) % 32); } for (size_t i = 0; i < 10; ++i) { - ASSERT_EQ(0, (size_t)resource.allocate(8000, 32) % 32); + ASSERT_EQ(0, reinterpret_cast(resource.allocate(8000, 32)) % 32); } for (size_t i = 0; i < 10; ++i) { auto s = reinterpret_cast<::std::string*>( @@ -200,8 +200,8 @@ TEST(ExclusiveMonotonicBufferResource, can_work_with_monotonic) { ExclusiveMonotonicBufferResource resource; MonotonicBufferResource& mono_resource = resource; mono_resource.allocate(8, 32); - auto ptr = (::std::string*)mono_resource.allocate( - sizeof(std::string)); + auto ptr = reinterpret_cast<::std::string*>( + mono_resource.allocate(sizeof(std::string))); new (ptr)::std::string(1024, 'x'); mono_resource.register_destructor(ptr); } @@ -425,7 +425,7 @@ TEST(memory_resource, construct_with_or_without_page_heap) { TEST(memory_resource, can_use_as_arena_with_protobuf) { SwissMemoryResource resource; resource.allocate<1>(128); - auto* ptr_in_resource = (char*)resource.allocate<1>(128); + auto* ptr_in_resource = reinterpret_cast(resource.allocate<1>(128)); Arena& arena = resource; #if GOOGLE_PROTOBUF_VERSION >= 5026000 auto message = Arena::Create(&arena); @@ -438,8 +438,8 @@ TEST(memory_resource, can_use_as_arena_with_protobuf) { } ASSERT_EQ(&arena, message->GetArena()); ASSERT_EQ(&arena, message->mutable_m()->GetArena()); - ASSERT_LE(ptr_in_resource + 128, (char*)message); - ASSERT_GT(ptr_in_resource + 1024, (char*)message); + ASSERT_LE(ptr_in_resource + 128, reinterpret_cast(message)); + ASSERT_GT(ptr_in_resource + 1024, reinterpret_cast(message)); ASSERT_EQ(0, arena.SpaceUsed()); } #endif // BABYLON_USE_PROTOBUF @@ -482,7 +482,7 @@ TEST(memory_resource, release_also_clear_arena) { SwissMemoryResource resource; { resource.allocate<1>(128); - auto* ptr_in_resource = (char*)resource.allocate<1>(128); + auto* ptr_in_resource = reinterpret_cast(resource.allocate<1>(128)); Arena& arena = resource; #if GOOGLE_PROTOBUF_VERSION >= 5026000 auto message = Arena::Create(&arena); @@ -491,14 +491,14 @@ TEST(memory_resource, release_also_clear_arena) { #endif // GOOGLE_PROTOBUF_VERSION < 5026000 ASSERT_EQ(&arena, message->GetArena()); ASSERT_EQ(&arena, message->mutable_m()->GetArena()); - ASSERT_LE(ptr_in_resource + 128, (char*)message); - ASSERT_GT(ptr_in_resource + 1024, (char*)message); + ASSERT_LE(ptr_in_resource + 128, reinterpret_cast(message)); + ASSERT_GT(ptr_in_resource + 1024, reinterpret_cast(message)); Arena::Create<::std::string>(&arena); } resource.release(); { resource.allocate<1>(128); - auto* ptr_in_resource = (char*)resource.allocate<1>(128); + auto* ptr_in_resource = reinterpret_cast(resource.allocate<1>(128)); Arena& arena = resource; #if GOOGLE_PROTOBUF_VERSION >= 5026000 auto message = Arena::Create(&arena); @@ -507,8 +507,8 @@ TEST(memory_resource, release_also_clear_arena) { #endif // GOOGLE_PROTOBUF_VERSION < 5026000 ASSERT_EQ(&arena, message->GetArena()); ASSERT_EQ(&arena, message->mutable_m()->GetArena()); - ASSERT_LE(ptr_in_resource + 128, (char*)message); - ASSERT_GT(ptr_in_resource + 1024, (char*)message); + ASSERT_LE(ptr_in_resource + 128, reinterpret_cast(message)); + ASSERT_GT(ptr_in_resource + 1024, reinterpret_cast(message)); Arena::Create<::std::string>(&arena); } } diff --git a/test/serialization/BUILD b/test/serialization/BUILD index 521c664a..80e81fea 100644 --- a/test/serialization/BUILD +++ b/test/serialization/BUILD @@ -2,12 +2,12 @@ package( default_visibility = [':__subpackages__'], ) -load('//:copts.bzl', 'BABYLON_COPTS') +load('//:copts.bzl', 'BABYLON_TEST_COPTS') cc_test( name = 'test_aggregate', srcs = ['test_aggregate.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '//test/proto', @@ -18,7 +18,7 @@ cc_test( cc_test( name = 'test_array', srcs = ['test_array.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -28,7 +28,7 @@ cc_test( cc_test( name = 'test_compatible', srcs = ['test_compatible.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '//test/proto', @@ -39,7 +39,7 @@ cc_test( cc_test( name = 'test_list', srcs = ['test_list.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -49,7 +49,7 @@ cc_test( cc_test( name = 'test_map', srcs = ['test_map.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -59,7 +59,7 @@ cc_test( cc_test( name = 'test_message', srcs = ['test_message.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '//test/proto', @@ -70,7 +70,7 @@ cc_test( cc_test( name = 'test_scalar', srcs = ['test_scalar.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -80,7 +80,7 @@ cc_test( cc_test( name = 'test_serializer', srcs = ['test_serializer.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -90,7 +90,7 @@ cc_test( cc_test( name = 'test_set', srcs = ['test_set.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -100,7 +100,7 @@ cc_test( cc_test( name = 'test_shared_ptr', srcs = ['test_shared_ptr.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -110,7 +110,7 @@ cc_test( cc_test( name = 'test_string', srcs = ['test_string.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -120,7 +120,7 @@ cc_test( cc_test( name = 'test_traits', srcs = ['test_traits.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -130,7 +130,7 @@ cc_test( cc_test( name = 'test_unique_ptr', srcs = ['test_unique_ptr.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', @@ -140,7 +140,7 @@ cc_test( cc_test( name = 'test_vector', srcs = ['test_vector.cpp'], - copts = BABYLON_COPTS, + copts = BABYLON_TEST_COPTS, deps = [ '//:serialization', '@com_google_googletest//:gtest_main', diff --git a/test/test_any.cpp b/test/test_any.cpp index 6f8315b1..d4a3add2 100644 --- a/test/test_any.cpp +++ b/test/test_any.cpp @@ -117,8 +117,10 @@ TEST(any, small_object_keep_inplace) { size_t value; }; Any any((S())); - ASSERT_LT((uint64_t)&any, (uint64_t)any.get()); - ASSERT_GT((uint64_t)&any + sizeof(any), (uint64_t)any.get()); + ASSERT_LT(reinterpret_cast(&any), + reinterpret_cast(any.get())); + ASSERT_GT(reinterpret_cast(&any) + sizeof(any), + reinterpret_cast(any.get())); } TEST(any, inplace_object_copy_right) { @@ -198,7 +200,7 @@ TEST(any, get_only_support_exact_type_matching) { ASSERT_EQ(obj, dynamic_cast*>(any.get>())); } { - Any any((int32_t)1); + Any any(static_cast(1)); ASSERT_EQ(nullptr, any.get()); ASSERT_NE(nullptr, any.get()); } @@ -215,7 +217,7 @@ TEST(any, non_virtual_object_is_ok) { TEST(any, instance_type_same_means_identical) { Any any0(Normal<>(0)); Any any1(Normal<>(1)); - Any any2((int32_t)1); + Any any2(static_cast(1)); ASSERT_TRUE(any0.instance_type() == any1.instance_type()); ASSERT_TRUE(&any0.instance_type() == &any1.instance_type()); ASSERT_FALSE(any0.instance_type() == any2.instance_type()); @@ -250,7 +252,7 @@ TEST(any, copyable_when_object_is_copyable) { { // const copy赋值 Any any2; - any2 = (const Any&)any; + any2 = const_cast(any); ASSERT_NE(nullptr, any2.get>()); ASSERT_EQ(5, Normal<2>::construct_num); ASSERT_EQ(3, Normal<2>::copy_num); @@ -379,7 +381,7 @@ TEST(any, any_can_ref_to_other_contain_primitive) { TEST(any, primitive_value_handle_separately) { { int64_t value = 0xFEFEFEFEFEFEFEFEL; - Any any((int64_t)0xFEFEFEFEFEFEFEFEL); + Any any(static_cast(0xFEFEFEFEFEFEFEFEL)); ASSERT_TRUE(any); ASSERT_EQ(Any::Type::INT64, any.type()); ASSERT_NE(nullptr, any.get()); @@ -422,34 +424,34 @@ TEST(any, primitive_value_handle_separately) { { int64_t value = 0xFEFEFEFEFEFEFEFEL; Any any; - any = (int32_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::INT32, any.type()); ASSERT_NE(nullptr, any.get()); - any = (int16_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::INT16, any.type()); ASSERT_NE(nullptr, any.get()); - any = (int8_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::INT8, any.type()); ASSERT_NE(nullptr, any.get()); - any = (uint64_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::UINT64, any.type()); ASSERT_NE(nullptr, any.get()); - any = (uint32_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::UINT32, any.type()); ASSERT_NE(nullptr, any.get()); - any = (uint16_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::UINT16, any.type()); ASSERT_NE(nullptr, any.get()); - any = (uint8_t)value; + any = static_cast(value); ASSERT_EQ(Any::Type::UINT8, any.type()); ASSERT_NE(nullptr, any.get()); - any = (bool)value; + any = static_cast(value); ASSERT_EQ(Any::Type::BOOLEAN, any.type()); ASSERT_NE(nullptr, any.get()); - any = (double)value; + any = static_cast(value); ASSERT_EQ(Any::Type::DOUBLE, any.type()); ASSERT_NE(nullptr, any.get()); - any = (float)value; + any = static_cast(value); ASSERT_EQ(Any::Type::FLOAT, any.type()); ASSERT_NE(nullptr, any.get()); } diff --git a/test/test_string.cpp b/test/test_string.cpp index 91448116..4058073d 100644 --- a/test/test_string.cpp +++ b/test/test_string.cpp @@ -76,12 +76,12 @@ TEST(string, recognize_string_with_resize) { this->size = size + 25; } char& operator[](size_t) { - return (char&)size; + return reinterpret_cast(size); } size_t size {0}; } s; - ASSERT_EQ(7 + 25, *(size_t*)resize_uninitialized(s, 7)); - ASSERT_EQ(12 + 25, *(size_t*)resize_uninitialized(s, 12)); + ASSERT_EQ(7 + 25, *reinterpret_cast(resize_uninitialized(s, 7))); + ASSERT_EQ(12 + 25, *reinterpret_cast(resize_uninitialized(s, 12))); } TEST(string, recognize_string_with_resize_default_init_function) { @@ -92,12 +92,12 @@ TEST(string, recognize_string_with_resize_default_init_function) { this->size = size; } char& operator[](int) { - return *(char*)size; + return *reinterpret_cast(size); } size_t size; } s; - ASSERT_EQ(7, (size_t)resize_uninitialized(s, 7)); - ASSERT_EQ(12, (size_t)resize_uninitialized(s, 12)); + ASSERT_EQ(7, reinterpret_cast(resize_uninitialized(s, 7))); + ASSERT_EQ(12, reinterpret_cast(resize_uninitialized(s, 12))); } TEST(string, stable_reserve_keep_stable_when_recreate) {