aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorarkady-e1ppa <arkady-e1ppa@yandex-team.com>2024-04-05 15:42:36 +0300
committerarkady-e1ppa <arkady-e1ppa@yandex-team.com>2024-04-05 15:51:06 +0300
commitbeb1725856691d2bd11a0e2ec8ce7b45cebb9804 (patch)
tree36347f8f8b8c3797fcab9747115ab53ed668b358 /library/cpp
parent431eb68d0e52caf69928b4581df3555d18e706b3 (diff)
downloadydb-beb1725856691d2bd11a0e2ec8ce7b45cebb9804.tar.gz
YT-21402: Fibers Refactoring pt.1: Introduce FunctionView to use it as AfterSwitch and improved registry algorithm
1) Added FunctionView -- non-owning type-erasure container. If we know that lambda lifetime is long enough, we can save up allocation by using this instead of TCallback. 2) Used FunctionView as AfterSwitch inside FiberSchedulerThread. We saved up a bunch of allocations (e.g. net worst-case allocations per suspend changed from 4 (x2 after switch + fiber allocation + enqueue to idle pool lf stack) to 2 (fiber allocation + enqueue to idle pool lf stack). 3) Fiber is not longer RefCounted. Its lifetime is managed via contract with TFiberRegistry. 4) TFiberRegistry is now lock-free for fiber insertion and deletion. For introspector it is still blocking. 5) "Introduced" SimpleIntrusiveList and IntrusiveMPSCStack to work be used in aforementioned TFiberRegistry. 6) elsedef branch of YT_REUSE_FIBERS was broken for about 3 years cause of double SetAfterSwitch. Now fixed. 7) (3), (4) and (5) caused some changes in yt_fiber_printers because some stuff was hardcoded there. Compat is in place. d6cf2ae5801c87813a21ca3e7243e1b2baa09f35
Diffstat (limited to 'library/cpp')
-rw-r--r--library/cpp/yt/misc/function_view-inl.h71
-rw-r--r--library/cpp/yt/misc/function_view.h139
2 files changed, 210 insertions, 0 deletions
diff --git a/library/cpp/yt/misc/function_view-inl.h b/library/cpp/yt/misc/function_view-inl.h
new file mode 100644
index 0000000000..ececfdf335
--- /dev/null
+++ b/library/cpp/yt/misc/function_view-inl.h
@@ -0,0 +1,71 @@
+#pragma once
+#ifndef FUNCTION_VIEW_INL_H_
+#error "Direct inclusion of this file is not allowed, include function_view.h"
+// For the sake of sane code completion.
+#include "function_view.h"
+#endif
+
+#include <library/cpp/yt/assert/assert.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TResult, bool NoExcept, class... TArgs>
+template <CTypeErasable<TResult(TArgs...) noexcept(NoExcept)> TConcrete>
+TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::TFunctionView(TConcrete& concreteRef) noexcept
+ : TFunctionView(&concreteRef)
+{ }
+
+template <class TResult, bool NoExcept, class... TArgs>
+template <CTypeErasable<TResult(TArgs...) noexcept(NoExcept)> TConcrete>
+TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::TFunctionView(TConcrete* concretePtr) noexcept
+{
+ Ptr_ = reinterpret_cast<void*>(concretePtr);
+ Invoke_ = &TFunctionView::ConcreteInvoke<TConcrete>;
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+TFunctionView<TResult(TArgs...) noexcept(NoExcept)>
+TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::Release() noexcept
+{
+ auto copy = *this;
+ Reset();
+ return copy;
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+TResult TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::operator()(TArgs... args) noexcept(NoExcept)
+{
+ YT_VERIFY(Ptr_);
+ return Invoke_(std::forward<TArgs>(args)..., Ptr_);
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+template <class TConcrete>
+TResult TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::ConcreteInvoke(TArgs... args, TErasedPtr ptr) noexcept(NoExcept)
+{
+ return (*reinterpret_cast<TConcrete*>(ptr))(std::forward<TArgs>(args)...);
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::operator bool() const noexcept
+{
+ return IsValid();
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+bool TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::IsValid() const noexcept
+{
+ return Ptr_ != nullptr;
+}
+
+template <class TResult, bool NoExcept, class... TArgs>
+void TFunctionView<TResult(TArgs...) noexcept(NoExcept)>::Reset() noexcept
+{
+ Ptr_ = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/function_view.h b/library/cpp/yt/misc/function_view.h
new file mode 100644
index 0000000000..259238521f
--- /dev/null
+++ b/library/cpp/yt/misc/function_view.h
@@ -0,0 +1,139 @@
+#pragma once
+
+#include <concepts>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <class TSignature>
+struct TTypeErasureTraits;
+
+template <class TResult, bool NoExcept, class... TArgs>
+struct TTypeErasureTraits<TResult(TArgs...) noexcept(NoExcept)>
+{
+ using TSignature = TResult(TArgs...) noexcept(NoExcept);
+
+ // TODO(arkady-e1ppa): Support pointer-to-member-function?
+ template <class T>
+ static constexpr bool IsInvocable = NoExcept
+ ? requires (T obj, TArgs... args) {
+ { obj(std::forward<TArgs>(args)...) } noexcept -> std::same_as<TResult>;
+ }
+ : requires (T obj, TArgs... args) {
+ { obj(std::forward<TArgs>(args)...) } -> std::same_as<TResult>;
+ };
+};
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Non-owning type-erasure container.
+/*
+ Example:
+
+ template <class T>
+ class TSerializedObject
+ {
+ public:
+ explicit TSerializedObject(T value)
+ : Object_(value)
+ { }
+
+ void Lock(TFunctionView<void(const T&)> callback)
+ {
+ auto guard = Guard(SpinLock_);
+ callback(Object_);
+ }
+
+ private:
+ TSpinLock SpinLock_;
+ T Object_;
+ };
+
+ int main()
+ {
+ TSerializedObject<int> object(42);
+
+ // object.Lock([] (const int& value) {
+ // fmt::println("Value is {}", value);
+ // });
+ // ^ CE -- cannot pass rvalue.
+
+ auto callback = [] (const int& value) {
+ fmt::println("Value is {}", value);
+ };
+
+ object.Lock(callback); // <- prints "Value is 42".
+ }
+*/
+template <class TSignature>
+class TFunctionView;
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class TSignature>
+concept CTypeErasable =
+ NDetail::TTypeErasureTraits<TSignature>::template IsInvocable<T> &&
+ (!std::same_as<T, TFunctionView<TSignature>>);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TResult, bool NoExcept, class... TArgs>
+class TFunctionView<TResult(TArgs...) noexcept(NoExcept)>
+{
+public:
+ using TSignature = TResult(TArgs...) noexcept(NoExcept);
+
+ TFunctionView() = default;
+
+ template <CTypeErasable<TSignature> TConcrete>
+ TFunctionView(TConcrete& concreteRef) noexcept;
+
+ template <CTypeErasable<TSignature> TConcrete>
+ TFunctionView(TConcrete* concretePtr) noexcept;
+
+ TResult operator()(TArgs... args) noexcept(NoExcept);
+
+ explicit operator bool() const noexcept;
+
+ TFunctionView Release() noexcept;
+
+ bool IsValid() const noexcept;
+ void Reset() noexcept;
+
+ // bool operator==(const TFunctionView& other) const & = default;
+
+private:
+ // NB: Technically, this is UB according to C standard, which
+ // was not changed for C++ standard.
+ // This is so because it is allowed to have
+ // function pointers to be modelled by entities
+ // different from object pointers.
+ // No reasonable system architecture (e.g. x86 or ARM
+ // or any other POSIX compliant one) does this.
+ // No reasonable compiler (clang/gcc) does anything with this.
+ // Accounting for such requirement would cause this class
+ // to have std::variant-like storage which would make this class
+ // weight more. Thus, we have decided to keep it this way,
+ // since we are safe on x86 or ARM + clang.
+ using TErasedPtr = void*;
+ using TErasedInvoke = TResult(*)(TArgs..., TErasedPtr);
+
+ TErasedPtr Ptr_ = nullptr;
+ TErasedInvoke Invoke_ = nullptr;
+
+ template <class TConcrete>
+ static TResult ConcreteInvoke(TArgs... args, TErasedPtr ptr) noexcept(NoExcept);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define FUNCTION_VIEW_INL_H_
+#include "function_view-inl.h"
+#undef FUNCTION_VIEW_INL_H_