From af8e85ba90e47977f4439374f88cf5fc38227b8e Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Jun 2026 18:18:19 +0300 Subject: [PATCH 1/3] [k2] add coroutine cpu cycles --- runtime-light/coroutine/detail/await-set.h | 4 ++ .../coroutine/detail/task-self-deleting.h | 4 ++ runtime-light/coroutine/detail/when-all.h | 4 ++ runtime-light/coroutine/detail/when-any.h | 4 ++ runtime-light/coroutine/shared-task.h | 4 ++ runtime-light/coroutine/task.h | 4 ++ runtime-light/runtime-light.cpp | 21 ++++++++++ runtime-light/state/instance-state.h | 2 + .../stdlib/cpu-info/cpu-info-state.cpp | 11 +++++ .../stdlib/cpu-info/cpu-info-state.h | 42 +++++++++++++++++++ runtime-light/stdlib/stdlib.cmake | 1 + 11 files changed, 101 insertions(+) create mode 100644 runtime-light/stdlib/cpu-info/cpu-info-state.cpp create mode 100644 runtime-light/stdlib/cpu-info/cpu-info-state.h diff --git a/runtime-light/coroutine/detail/await-set.h b/runtime-light/coroutine/detail/await-set.h index 2c05be0c6e..f307f26850 100644 --- a/runtime-light/coroutine/detail/await-set.h +++ b/runtime-light/coroutine/detail/await-set.h @@ -15,6 +15,7 @@ #include "runtime-light/coroutine/async-stack.h" #include "runtime-light/coroutine/type-traits.h" #include "runtime-light/coroutine/void-value.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro { @@ -58,15 +59,18 @@ class await_broker { template void* operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/coroutine/detail/task-self-deleting.h b/runtime-light/coroutine/detail/task-self-deleting.h index 3ff19f1831..795123c585 100644 --- a/runtime-light/coroutine/detail/task-self-deleting.h +++ b/runtime-light/coroutine/detail/task-self-deleting.h @@ -12,6 +12,7 @@ #include "runtime-light/coroutine/async-stack.h" #include "runtime-light/coroutine/concepts.h" #include "runtime-light/coroutine/coroutine-state.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro::detail { @@ -32,15 +33,18 @@ struct promise_self_deleting : kphp::coro::async_stack_element { template auto operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/coroutine/detail/when-all.h b/runtime-light/coroutine/detail/when-all.h index 2386e4fbb6..133df6363e 100644 --- a/runtime-light/coroutine/detail/when-all.h +++ b/runtime-light/coroutine/detail/when-all.h @@ -18,6 +18,7 @@ #include "runtime-light/coroutine/concepts.h" #include "runtime-light/coroutine/type-traits.h" #include "runtime-light/coroutine/void-value.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro::detail::when_all { @@ -152,15 +153,18 @@ class when_all_task_promise_base : public kphp::coro::async_stack_element { template auto operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/coroutine/detail/when-any.h b/runtime-light/coroutine/detail/when-any.h index f5ee01549e..fb4bd96a1c 100644 --- a/runtime-light/coroutine/detail/when-any.h +++ b/runtime-light/coroutine/detail/when-any.h @@ -17,6 +17,7 @@ #include "runtime-light/coroutine/type-traits.h" #include "runtime-light/coroutine/void-value.h" #include "runtime-light/metaprogramming/type-functions.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro::detail::when_any { @@ -162,15 +163,18 @@ class when_any_task_promise_base : public kphp::coro::async_stack_element { template auto operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/coroutine/shared-task.h b/runtime-light/coroutine/shared-task.h index ddec603c58..eacb345061 100644 --- a/runtime-light/coroutine/shared-task.h +++ b/runtime-light/coroutine/shared-task.h @@ -17,6 +17,7 @@ #include "runtime-common/core/allocator/script-malloc-interface.h" #include "runtime-light/coroutine/async-stack.h" #include "runtime-light/coroutine/void-value.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro { @@ -145,15 +146,18 @@ struct promise_base : kphp::coro::async_stack_element { template auto operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/coroutine/task.h b/runtime-light/coroutine/task.h index d5c064720b..aad7f3a4b6 100644 --- a/runtime-light/coroutine/task.h +++ b/runtime-light/coroutine/task.h @@ -13,6 +13,7 @@ #include "common/containers/final_action.h" #include "runtime-common/core/allocator/script-malloc-interface.h" #include "runtime-light/coroutine/async-stack.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::coro { @@ -66,15 +67,18 @@ struct promise_base : kphp::coro::async_stack_element { template auto operator new(size_t n, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc(n); } template auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_alloc_cycles)}; return kphp::memory::script::alloc_aligned(n, al); } auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void { + auto writer{CpuInfoInstanceState::write_cycles(CpuInfoInstanceState::get().coro_free_cycles)}; kphp::memory::script::free(ptr); } diff --git a/runtime-light/runtime-light.cpp b/runtime-light/runtime-light.cpp index e65f3a0966..fb8279906d 100644 --- a/runtime-light/runtime-light.cpp +++ b/runtime-light/runtime-light.cpp @@ -65,6 +65,11 @@ VISIBILITY_DEFAULT void k2_init_instance() { k2::details::instance_state_ptr = k2_instance_state(); kphp::log::debug("start instance state init"); new (k2::instance_state()) InstanceState{}; + + auto& cpu_info_instance_state{CpuInfoInstanceState::get()}; + cpu_info_instance_state.init(); + cpu_info_instance_state.total_cycles = -CpuInfoInstanceState::rdtsc(); + k2::instance_state()->init_script_execution(); kphp::log::debug("finish instance state init"); } @@ -75,6 +80,22 @@ VISIBILITY_DEFAULT k2::PollStatus k2_poll() { k2::details::instance_state_ptr = k2_instance_state(); kphp::log::debug("k2_poll started"); const auto poll_status{kphp::coro::io_scheduler::get().process_events()}; + + if (poll_status == k2::PollStatus::PollFinishedOk) { + auto& cpu_info_instance_state{CpuInfoInstanceState::get()}; + cpu_info_instance_state.total_cycles += CpuInfoInstanceState::rdtsc(); + + uint64_t coro_alloc_cycles{cpu_info_instance_state.coro_alloc_cycles}; + uint64_t coro_free_cycles{cpu_info_instance_state.coro_free_cycles}; + uint64_t coro_alloc_free_cycles{coro_alloc_cycles + coro_free_cycles}; + + kphp::log::info("\ntotal cpu cycles -> {}\n" + "coro_alloc_cycles -> {} ({}%)\n" + "coro_free_cycles -> {} ({}%)\n" + "coro_alloc+free_cycles -> {} ({}%)", + cpu_info_instance_state.total_cycles, coro_alloc_cycles, cpu_info_instance_state.get_percent(coro_alloc_cycles), coro_free_cycles, + cpu_info_instance_state.get_percent(coro_free_cycles), coro_alloc_free_cycles, cpu_info_instance_state.get_percent(coro_alloc_free_cycles)); + } kphp::log::debug("k2_poll finished: {}", std::to_underlying(poll_status)); return poll_status; } diff --git a/runtime-light/state/instance-state.h b/runtime-light/state/instance-state.h index f48a39f9c8..ceef7fd5d4 100644 --- a/runtime-light/state/instance-state.h +++ b/runtime-light/state/instance-state.h @@ -22,6 +22,7 @@ #include "runtime-light/server/rpc/rpc-server-state.h" #include "runtime-light/state/component-state.h" #include "runtime-light/stdlib/confdata/confdata-state.h" +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" #include "runtime-light/stdlib/curl/curl-state.h" #include "runtime-light/stdlib/diagnostics/contextual-tags.h" #include "runtime-light/stdlib/diagnostics/error-handling-state.h" @@ -98,6 +99,7 @@ struct InstanceState final : vk::not_copyable { WaitQueueInstanceState wait_queue_instance_state; RpcQueueInstanceState rpc_queue_instance_state; PhpScriptMutableGlobals php_script_mutable_globals_singleton; + CpuInfoInstanceState cpu_info_instance_state; RuntimeContext runtime_context; CLIInstanceInstance cli_instance_instate; diff --git a/runtime-light/stdlib/cpu-info/cpu-info-state.cpp b/runtime-light/stdlib/cpu-info/cpu-info-state.cpp new file mode 100644 index 0000000000..cb38369e68 --- /dev/null +++ b/runtime-light/stdlib/cpu-info/cpu-info-state.cpp @@ -0,0 +1,11 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2026 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime-light/stdlib/cpu-info/cpu-info-state.h" + +#include "runtime-light/state/instance-state.h" + +CpuInfoInstanceState& CpuInfoInstanceState::get() noexcept { + return InstanceState::get().cpu_info_instance_state; +} diff --git a/runtime-light/stdlib/cpu-info/cpu-info-state.h b/runtime-light/stdlib/cpu-info/cpu-info-state.h new file mode 100644 index 0000000000..d688b3fd50 --- /dev/null +++ b/runtime-light/stdlib/cpu-info/cpu-info-state.h @@ -0,0 +1,42 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2026 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include +#include + +#include "common/containers/final_action.h" +#include "runtime-light/stdlib/diagnostics/logs.h" + +class CpuInfoInstanceState { +public: + CpuInfoInstanceState() noexcept = default; + + static CpuInfoInstanceState& get() noexcept; + + [[gnu::always_inline]] static uint64_t rdtsc() noexcept { + return __rdtsc(); + } + + static auto write_cycles(uint64_t& dist) noexcept { + uint64_t start{CpuInfoInstanceState::rdtsc()}; + return vk::final_action([start, &dist]() noexcept { dist += CpuInfoInstanceState::rdtsc() - start; }); + } + + double get_percent(uint64_t cycles) const noexcept { + kphp::log::assertion(cycles <= total_cycles); + return 100.0 * cycles / total_cycles; + } + + void init() noexcept { + total_cycles = 0; + coro_alloc_cycles = 0; + coro_free_cycles = 0; + } + + uint64_t total_cycles; + uint64_t coro_alloc_cycles; + uint64_t coro_free_cycles; +}; diff --git a/runtime-light/stdlib/stdlib.cmake b/runtime-light/stdlib/stdlib.cmake index 92f67cd6b4..b82d1c1e6d 100644 --- a/runtime-light/stdlib/stdlib.cmake +++ b/runtime-light/stdlib/stdlib.cmake @@ -3,6 +3,7 @@ prepend( stdlib/ confdata/confdata-functions.cpp confdata/confdata-state.cpp + cpu-info/cpu-info-state.cpp crypto/crypto-functions.cpp curl/curl-state.cpp web-transfer-lib/web-state.cpp From 4b5a99feba8f3b267ae03cc9154fe606fae07b4c Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Jun 2026 18:22:21 +0300 Subject: [PATCH 2/3] minor fix --- runtime-light/stdlib/cpu-info/cpu-info-state.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime-light/stdlib/cpu-info/cpu-info-state.h b/runtime-light/stdlib/cpu-info/cpu-info-state.h index d688b3fd50..b312c814bb 100644 --- a/runtime-light/stdlib/cpu-info/cpu-info-state.h +++ b/runtime-light/stdlib/cpu-info/cpu-info-state.h @@ -26,7 +26,9 @@ class CpuInfoInstanceState { } double get_percent(uint64_t cycles) const noexcept { - kphp::log::assertion(cycles <= total_cycles); + if (cycles > total_cycles) { + kphp::log::warning("CpuInfo. Something wrong: cycles {} > total_cycles {}", cycles, total_cycles); + } return 100.0 * cycles / total_cycles; } From 484a424394e92dc66e663313192327dc3f40d0ea Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Jun 2026 18:25:24 +0300 Subject: [PATCH 3/3] minor fix --- runtime-light/runtime-light.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime-light/runtime-light.cpp b/runtime-light/runtime-light.cpp index fb8279906d..10a2484efb 100644 --- a/runtime-light/runtime-light.cpp +++ b/runtime-light/runtime-light.cpp @@ -90,9 +90,9 @@ VISIBILITY_DEFAULT k2::PollStatus k2_poll() { uint64_t coro_alloc_free_cycles{coro_alloc_cycles + coro_free_cycles}; kphp::log::info("\ntotal cpu cycles -> {}\n" - "coro_alloc_cycles -> {} ({}%)\n" - "coro_free_cycles -> {} ({}%)\n" - "coro_alloc+free_cycles -> {} ({}%)", + "coro alloc cycles -> {} ({}%)\n" + "coro free cycles -> {} ({}%)\n" + "coro alloc+free cycles -> {} ({}%)\n", cpu_info_instance_state.total_cycles, coro_alloc_cycles, cpu_info_instance_state.get_percent(coro_alloc_cycles), coro_free_cycles, cpu_info_instance_state.get_percent(coro_free_cycles), coro_alloc_free_cycles, cpu_info_instance_state.get_percent(coro_alloc_free_cycles)); }