From 3e289e395998b543ee6f5f5ce3dbf5481001e088 Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Thu, 6 Aug 2026 15:31:25 +0300 Subject: [PATCH 1/7] remove allocation for event_controller in event --- runtime-light/coroutine/event.h | 38 ++++++++++----------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/runtime-light/coroutine/event.h b/runtime-light/coroutine/event.h index 905345c97a..298f0c7321 100644 --- a/runtime-light/coroutine/event.h +++ b/runtime-light/coroutine/event.h @@ -6,14 +6,12 @@ #include #include -#include #include #include #include "common/containers/intrusive-list.h" #include "common/mixin/not_copyable.h" #include "common/wrappers/overloaded.h" -#include "runtime-common/core/allocator/script-allocator-managed.h" #include "runtime-light/coroutine/async-stack.h" #include "runtime-light/coroutine/coroutine-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" @@ -21,7 +19,7 @@ namespace kphp::coro { class event { - struct event_controller : kphp::memory::script_allocator_managed, vk::not_copyable { + struct event_controller : vk::not_copyable { // 1) std::monostate => not set and no coroutines are waiting // 2) non empty list => linked list of coroutines waiting for the event to trigger // 3) empty list => the event is triggered and all coroutines are resumed @@ -55,29 +53,19 @@ class event { auto await_resume() noexcept -> void; }; - std::unique_ptr m_controller; + event_controller m_controller; public: - event() noexcept - : m_controller(std::make_unique()) { - kphp::log::assertion(m_controller != nullptr); - } + event() = default; - event(event&& other) noexcept - : m_controller(std::move(other.m_controller)) {} + event(const event&) = delete; + event(event&& other) = delete; - event& operator=(event&& other) noexcept { - if (this != std::addressof(other)) { - m_controller = std::move(other.m_controller); - } - return *this; - } + event& operator=(const event&) = delete; + event& operator=(event&& other) = delete; ~event() = default; - event(const event&) = delete; - event& operator=(const event&) = delete; - auto set() noexcept -> void; auto unset() noexcept -> void; auto is_set() const noexcept -> bool; @@ -148,23 +136,19 @@ inline auto event::event_controller::is_set() const noexcept -> bool { } inline auto event::set() noexcept -> void { - kphp::log::assertion(m_controller != nullptr); - m_controller->set(); + m_controller.set(); } inline auto event::unset() noexcept -> void { - kphp::log::assertion(m_controller != nullptr); - m_controller->unset(); + m_controller.unset(); } inline auto event::is_set() const noexcept -> bool { - kphp::log::assertion(m_controller != nullptr); - return m_controller->is_set(); + return m_controller.is_set(); } inline auto event::operator co_await() noexcept { - kphp::log::assertion(m_controller != nullptr); - return event::awaiter{*this->m_controller}; + return event::awaiter{m_controller}; } } // namespace kphp::coro From 14f3bc440d8853df103691141e2b549a00f2c4ca Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Thu, 6 Aug 2026 16:05:30 +0300 Subject: [PATCH 2/7] remove move semantic in shared_state --- runtime-light/streams/connection.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/runtime-light/streams/connection.h b/runtime-light/streams/connection.h index 1cdddc49ab..25499720f3 100644 --- a/runtime-light/streams/connection.h +++ b/runtime-light/streams/connection.h @@ -24,12 +24,14 @@ class connection { std::optional m_unwatch_event; shared_state() noexcept = default; - shared_state(shared_state&&) noexcept = default; - shared_state& operator=(shared_state&&) noexcept = default; - ~shared_state() = default; + shared_state(shared_state&&) noexcept = delete; shared_state(const shared_state&) = delete; + + shared_state& operator=(shared_state&&) noexcept = delete; shared_state operator=(const shared_state&) = delete; + + ~shared_state() = default; }; class_instance m_shared_state; From 54491d4a5856134cd049a4aa7400c93421ca4822 Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Thu, 6 Aug 2026 17:53:07 +0300 Subject: [PATCH 3/7] replace emplace with try_emplace in client --- .../stdlib/component/inter-component-session/client.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime-light/stdlib/component/inter-component-session/client.h b/runtime-light/stdlib/component/inter-component-session/client.h index 934b958ed9..b822649937 100644 --- a/runtime-light/stdlib/component/inter-component-session/client.h +++ b/runtime-light/stdlib/component/inter-component-session/client.h @@ -56,7 +56,7 @@ class client final { // Wait until transport is available if (is_occupied) [[unlikely]] { - transport_readiness_notifier.emplace(qid, kphp::coro::event{}); + transport_readiness_notifier.try_emplace(qid); queue.push(qid); co_await transport_readiness_notifier[qid]; } @@ -105,7 +105,7 @@ class client final { } auto write(shared_transport_type t, query_id_type qid, std::span payload) noexcept -> kphp::coro::task> { - req_finish_notifier.emplace(qid, kphp::coro::event{}); + req_finish_notifier.try_emplace(qid); // The protocol design assumes that interrupting the transfer in the middle of a frame leads to critical error. // Therefore, we need to write the request in a separate coroutine. @@ -230,7 +230,7 @@ class client final { ctx.get()->query2resp_buffer_provider.emplace(qid, std::move(buffer_provider)); // Register notifier - ctx.get()->resp_finish_notifier.emplace(qid, kphp::coro::event{}); + ctx.get()->resp_finish_notifier.try_emplace(qid); } } reader; From afe945abd3e4025b2513b4b84b59a067f3bdeb03 Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Thu, 6 Aug 2026 19:01:56 +0300 Subject: [PATCH 4/7] add operator new/delete overloads into event --- runtime-light/coroutine/event.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/runtime-light/coroutine/event.h b/runtime-light/coroutine/event.h index 298f0c7321..ce43e57044 100644 --- a/runtime-light/coroutine/event.h +++ b/runtime-light/coroutine/event.h @@ -12,6 +12,7 @@ #include "common/containers/intrusive-list.h" #include "common/mixin/not_copyable.h" #include "common/wrappers/overloaded.h" +#include "runtime-common/core/allocator/script-malloc-interface.h" #include "runtime-light/coroutine/async-stack.h" #include "runtime-light/coroutine/coroutine-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" @@ -66,6 +67,20 @@ class event { ~event() = default; + template + void* operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept { + return kphp::memory::script::alloc(n); + } + + template + auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + return kphp::memory::script::alloc_aligned(n, al); + } + + void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept { + kphp::memory::script::free(ptr); + } + auto set() noexcept -> void; auto unset() noexcept -> void; auto is_set() const noexcept -> bool; From 3544f2d208da610d12aeffac08be5fca55572f0a Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Thu, 6 Aug 2026 19:02:51 +0300 Subject: [PATCH 5/7] remove allocation for await_broker in await_set --- runtime-light/coroutine/await-set.h | 47 ++++++++++---------- runtime-light/coroutine/detail/await-set.h | 16 +------ runtime-light/state/instance-state.cpp | 8 ++-- runtime-light/stdlib/fork/wait-queue-state.h | 2 +- runtime-light/stdlib/rpc/rpc-api.cpp | 3 +- runtime-light/stdlib/rpc/rpc-client-state.h | 3 +- runtime-light/stdlib/rpc/rpc-queue-state.h | 2 +- 7 files changed, 36 insertions(+), 45 deletions(-) diff --git a/runtime-light/coroutine/await-set.h b/runtime-light/coroutine/await-set.h index 1fbf78de2e..c9b12814cb 100644 --- a/runtime-light/coroutine/await-set.h +++ b/runtime-light/coroutine/await-set.h @@ -5,7 +5,6 @@ #pragma once #include -#include #include #include @@ -14,45 +13,48 @@ #include "runtime-light/coroutine/coroutine-state.h" #include "runtime-light/coroutine/detail/await-set.h" #include "runtime-light/coroutine/type-traits.h" -#include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro { template class await_set { - std::unique_ptr> m_await_broker; + detail::await_set::await_broker m_await_broker; kphp::coro::async_stack_root& m_coroutine_stack_root; public: await_set() noexcept - : m_await_broker(std::make_unique>()), - m_coroutine_stack_root(CoroutineInstanceState::get().coroutine_stack_root) {} + : m_coroutine_stack_root(CoroutineInstanceState::get().coroutine_stack_root) {} - await_set(await_set&& other) noexcept - : m_await_broker(std::move(other.m_await_broker)), - m_coroutine_stack_root(other.m_coroutine_stack_root) {} + await_set(const await_set&) = delete; + await_set(await_set&& other) = delete; - await_set& operator=(await_set&& other) noexcept { - if (this != std::addressof(other)) { - m_await_broker = std::move(other.m_await_broker); - m_coroutine_stack_root = other.m_coroutine_stack_root; - } - return *this; + await_set& operator=(const await_set&) = delete; + await_set& operator=(await_set&& other) = delete; + + ~await_set() = default; + + template + void* operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept { + return kphp::memory::script::alloc(n); } - await_set(const await_set&) = delete; - await_set& operator=(const await_set&) = delete; + template + auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + return kphp::memory::script::alloc_aligned(n, al); + } + + void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept { + kphp::memory::script::free(ptr); + } template requires kphp::coro::concepts::awaitable && std::is_same_v::awaiter_return_type, return_type> void push(awaitable_type awaitable) noexcept { - kphp::log::assertion(m_await_broker != nullptr); - m_await_broker->start_task(detail::await_set::make_await_set_task(std::move(awaitable)), m_coroutine_stack_root, STACK_RETURN_ADDRESS); + m_await_broker.start_task(detail::await_set::make_await_set_task(std::move(awaitable)), m_coroutine_stack_root, STACK_RETURN_ADDRESS); } auto next() noexcept { - kphp::log::assertion(m_await_broker != nullptr); - return detail::await_set::await_set_awaitable{*m_await_broker}; + return detail::await_set::await_set_awaitable{m_await_broker}; } auto try_next() noexcept { @@ -60,7 +62,7 @@ class await_set { if (m_await_broker == nullptr) [[unlikely]] { return result_type{std::nullopt}; } - return result_type{m_await_broker->try_get_result()}; + return result_type{m_await_broker.try_get_result()}; } bool empty() const noexcept { @@ -68,8 +70,7 @@ class await_set { } size_t size() const noexcept { - kphp::log::assertion(m_await_broker != nullptr); - return m_await_broker->size(); + return m_await_broker.size(); } }; diff --git a/runtime-light/coroutine/detail/await-set.h b/runtime-light/coroutine/detail/await-set.h index 81fb98665e..d117515076 100644 --- a/runtime-light/coroutine/detail/await-set.h +++ b/runtime-light/coroutine/detail/await-set.h @@ -51,20 +51,6 @@ class await_broker { await_broker& operator=(const await_broker&) = delete; await_broker& operator=(await_broker&& other) = delete; - template - void* operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept { - return kphp::memory::script::alloc(n); - } - - template - auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { - return kphp::memory::script::alloc_aligned(n, al); - } - - void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept { - kphp::memory::script::free(ptr); - } - void start_task(await_set_task&& task, kphp::coro::async_stack_root& coroutine_stack_root, void* return_address) noexcept { auto& promise{task.m_promise}; m_tasks_storage.push_front(promise.m_coroutine_node); @@ -154,7 +140,7 @@ class await_broker { } } - size_t size() noexcept { + size_t size() const noexcept { return m_tasks_count; } diff --git a/runtime-light/state/instance-state.cpp b/runtime-light/state/instance-state.cpp index 4bb90f6e55..565245ca1d 100644 --- a/runtime-light/state/instance-state.cpp +++ b/runtime-light/state/instance-state.cpp @@ -235,9 +235,11 @@ kphp::coro::task<> InstanceState::run_instance_epilogue() noexcept { */ { auto& rpc_client_instance_st{RpcClientInstanceState::get()}; - auto ignore_answer_request_await_set{std::exchange(rpc_client_instance_st.ignore_answer_request_awaiter_tasks, kphp::coro::await_set{})}; - while (!ignore_answer_request_await_set.empty()) { - co_await ignore_answer_request_await_set.next(); + auto ignore_answer_request_await_set{ + std::exchange(rpc_client_instance_st.ignore_answer_request_awaiter_tasks, std::make_unique>())}; + kphp::log::assertion(ignore_answer_request_await_set != nullptr); + while (!ignore_answer_request_await_set->empty()) { + co_await ignore_answer_request_await_set->next(); } } diff --git a/runtime-light/stdlib/fork/wait-queue-state.h b/runtime-light/stdlib/fork/wait-queue-state.h index e9eac3e7a9..aeaf028e6b 100644 --- a/runtime-light/stdlib/fork/wait-queue-state.h +++ b/runtime-light/stdlib/fork/wait-queue-state.h @@ -24,7 +24,7 @@ class WaitQueueInstanceState { [[nodiscard]] int64_t create_queue() noexcept { const int64_t wait_queue_id{m_next_wait_queue_id++}; - m_queues.emplace(wait_queue_id, kphp::coro::await_set{}); + m_queues.try_emplace(wait_queue_id); return wait_queue_id; } diff --git a/runtime-light/stdlib/rpc/rpc-api.cpp b/runtime-light/stdlib/rpc/rpc-api.cpp index d881fa3c11..6b85a674d9 100644 --- a/runtime-light/stdlib/rpc/rpc-api.cpp +++ b/runtime-light/stdlib/rpc/rpc-api.cpp @@ -367,7 +367,8 @@ kphp::coro::task send_request(std::string_view actor, std auto ignore_answer_awaiter_task{ignore_answer_awaiter_coroutine(std::move(stream), timeout)}; kphp::log::assertion(kphp::coro::io_scheduler::get().start(ignore_answer_awaiter_task)); - rpc_client_instance_st.ignore_answer_request_awaiter_tasks.push(std::move(ignore_answer_awaiter_task)); + kphp::log::assertion(rpc_client_instance_st.ignore_answer_request_awaiter_tasks != nullptr); + rpc_client_instance_st.ignore_answer_request_awaiter_tasks->push(std::move(ignore_answer_awaiter_task)); co_return kphp::rpc::query_info{.id = kphp::rpc::IGNORED_ANSWER_QUERY_ID, .request_size = request_size, .timestamp = timestamp}; } // start awaiter task diff --git a/runtime-light/stdlib/rpc/rpc-client-state.h b/runtime-light/stdlib/rpc/rpc-client-state.h index c4d86416b2..51736e6d50 100644 --- a/runtime-light/stdlib/rpc/rpc-client-state.h +++ b/runtime-light/stdlib/rpc/rpc-client-state.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -27,7 +28,7 @@ struct RpcClientInstanceState final : private vk::not_copyable { kphp::stl::unordered_map, kphp::memory::script_allocator> response_fetcher_instances; kphp::stl::unordered_map, kphp::memory::script_allocator> rpc_responses_extra_info; - kphp::coro::await_set ignore_answer_request_awaiter_tasks; + std::unique_ptr> ignore_answer_request_awaiter_tasks{std::make_unique>()}; RpcClientInstanceState() noexcept = default; diff --git a/runtime-light/stdlib/rpc/rpc-queue-state.h b/runtime-light/stdlib/rpc/rpc-queue-state.h index 7c307dd27c..e71518b8f4 100644 --- a/runtime-light/stdlib/rpc/rpc-queue-state.h +++ b/runtime-light/stdlib/rpc/rpc-queue-state.h @@ -25,7 +25,7 @@ class RpcQueueInstanceState final : private vk::not_copyable { [[nodiscard]] int64_t create_queue() noexcept { const int64_t wait_queue_id{m_rpc_wait_queue_id++}; - m_queues.emplace(wait_queue_id, kphp::coro::await_set{}); + m_queues.try_emplace(wait_queue_id); return wait_queue_id; } From 0896034cefd95cc5dd7635c6ef66d94ad9855e99 Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Fri, 7 Aug 2026 14:03:11 +0300 Subject: [PATCH 6/7] add allocator traits --- runtime-common/core/allocator/platform-allocator.h | 4 ++++ runtime-common/core/allocator/script-allocator.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/runtime-common/core/allocator/platform-allocator.h b/runtime-common/core/allocator/platform-allocator.h index 6ae1134683..45b879eef0 100644 --- a/runtime-common/core/allocator/platform-allocator.h +++ b/runtime-common/core/allocator/platform-allocator.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "runtime-common/core/allocator/runtime-allocator.h" @@ -13,6 +14,9 @@ namespace kphp::memory { template struct platform_allocator { using value_type = T; + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; platform_allocator() noexcept = default; diff --git a/runtime-common/core/allocator/script-allocator.h b/runtime-common/core/allocator/script-allocator.h index 6cc50ca2f1..538f76f11d 100644 --- a/runtime-common/core/allocator/script-allocator.h +++ b/runtime-common/core/allocator/script-allocator.h @@ -15,6 +15,9 @@ namespace memory { template struct script_allocator { using value_type = T; + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; script_allocator() noexcept = default; From b51d0cddc79a6f38e247d5aafad2558f52cd8b79 Mon Sep 17 00:00:00 2001 From: Kirill Kotliar Date: Fri, 7 Aug 2026 15:42:19 +0300 Subject: [PATCH 7/7] fix compilation error in await-set --- runtime-light/coroutine/await-set.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime-light/coroutine/await-set.h b/runtime-light/coroutine/await-set.h index c9b12814cb..8cabf68151 100644 --- a/runtime-light/coroutine/await-set.h +++ b/runtime-light/coroutine/await-set.h @@ -59,9 +59,6 @@ class await_set { auto try_next() noexcept { using result_type = std::optional::promise_type>().result())>; - if (m_await_broker == nullptr) [[unlikely]] { - return result_type{std::nullopt}; - } return result_type{m_await_broker.try_get_result()}; }