Files
Aethera/kernel/src/kernel/frame_statistics.hpp
T
2026-08-25 15:03:33 +08:00

177 lines
5.2 KiB
C++

#pragma once
#include "frame.hpp"
#include <array>
#include <bitset>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <vector>
namespace aethera {
enum class Frame_Dimension : std::uint8_t { two_dimensional, three_dimensional };
enum class Frame_Statistic : std::uint8_t {
plot_tick_queue_ms,
plot_update_ms,
plot_publish_ms,
server_completion_ms,
scene_render_ms,
event_dispatch_ms,
prepare_ms,
paint_ms,
backend_queue_ms,
gpu_submission_ms,
readback_stage_ms,
callback_ms,
backend_apply_ms,
backend_plan_ms,
backend_execute_ms,
backend_submit_ms,
gpu_fence_wait_ms,
gpu_render_ms,
gpu_transition_ms,
gpu_copy_ms,
gpu_total_ms,
readback_ms,
pipeline_2d_event_ms,
pipeline_2d_prepare_ms,
pipeline_2d_paint_ms,
pipeline_2d_frame_target_ms,
pipeline_2d_background_ms,
pipeline_2d_cache_targets_ms,
pipeline_2d_taskflow_ms,
pipeline_2d_paint_coordination_ms,
pipeline_2d_scene_coordination_ms,
pipeline_2d_callback_ms,
pipeline_2d_frame_handoff_ms,
pipeline_3d_event_ms,
pipeline_3d_prepare_ms,
pipeline_3d_submit_graph_ms,
pipeline_3d_scene_coordination_ms,
pipeline_3d_prepare_queue_ms,
pipeline_3d_backend_apply_ms,
pipeline_3d_backend_plan_ms,
pipeline_3d_backend_execute_ms,
pipeline_3d_backend_commands_ms,
pipeline_3d_backend_queue_ms,
pipeline_3d_backend_submit_ms,
pipeline_3d_submit_handoff_ms,
pipeline_3d_gpu_render_ms,
pipeline_3d_gpu_transition_ms,
pipeline_3d_gpu_copy_ms,
pipeline_3d_gpu_sync_ms,
pipeline_3d_readback_ms,
pipeline_3d_callback_ms,
pipeline_3d_completion_handoff_ms,
frame_interval_ms,
count
};
inline constexpr std::size_t frame_statistic_count =
static_cast<std::size_t>(Frame_Statistic::count);
struct Frame_Statistics_Sample {
std::array<double, frame_statistic_count> values{};
std::bitset<frame_statistic_count> present{};
void set(Frame_Statistic statistic, double value) noexcept;
};
struct Statistic_State {
std::size_t count{};
double latest{};
double minimum{};
double maximum{};
double average{};
double trimmed_average{};
double variability{};
double p50{};
double p95{};
double p99{};
bool operator==(const Statistic_State&) const = default;
};
class Sliding_Statistics final {
public:
Sliding_Statistics();
explicit Sliding_Statistics(std::size_t capacity);
[[nodiscard]] Statistic_State submit(double value);
[[nodiscard]] const Statistic_State& state() const noexcept;
void reset() noexcept;
private:
/* P² 只维护五个标记点,分位数是从 reset 起的在线估计,不保存样本。 */
class Quantile_Estimator final {
public:
explicit Quantile_Estimator(double probability) noexcept;
void submit(double value) noexcept;
[[nodiscard]] double value() const noexcept;
void reset() noexcept;
private:
double probability_{};
std::array<double, 5> initial_{};
std::array<double, 5> heights_{};
std::array<double, 5> positions_{};
std::array<double, 5> desired_{};
std::array<double, 5> increments_{};
std::size_t count_{};
};
/* 预分配单调队列,O(1) 摊还维护精确滑动窗口极值。 */
class Extremum_Queue final {
public:
Extremum_Queue(std::size_t capacity, bool minimum);
void submit(double value, std::uint64_t sequence,
std::size_t window) noexcept;
[[nodiscard]] double value() const noexcept;
void reset() noexcept;
private:
struct Node { double value{}; std::uint64_t sequence{}; };
std::vector<Node> nodes_;
std::size_t head_{};
std::size_t tail_{};
bool minimum_{};
};
/* 原始值和截尾值只为精确滑动均值/方差服务,构造后不再分配。 */
std::vector<double> values_;
std::vector<double> trimmed_values_;
std::size_t size_{};
std::size_t next_{};
double sum_{};
double squared_sum_{};
double trimmed_sum_{};
bool trimmed_window_initialized_{};
std::uint64_t sequence_{};
Extremum_Queue minimum_;
Extremum_Queue maximum_;
Quantile_Estimator p05_{0.05};
Quantile_Estimator p50_{0.50};
Quantile_Estimator p95_{0.95};
Quantile_Estimator p99_{0.99};
Statistic_State state_{};
};
struct Frame_Statistics_State {
/* 可直接通过 Scene State 双缓冲发布的定长结果;不含统计器内部样本。 */
std::array<Statistic_State, frame_statistic_count> values{};
Frame_Identity identity{};
std::uint64_t created_time_unix_ns{};
std::uint64_t dropped_sequences{};
bool operator==(const Frame_Statistics_State&) const = default;
};
class Frame_Statistics_Accumulator final {
public:
explicit Frame_Statistics_Accumulator(std::size_t capacity = 600);
[[nodiscard]] const Frame_Statistics_State& submit(
const Render_Frame& frame, Frame_Dimension dimension);
void reset() noexcept;
private:
std::vector<Sliding_Statistics> values_;
Frame_Statistics_State state_{};
std::chrono::steady_clock::time_point previous_completion_{};
std::uint64_t previous_sequence_{};
};
}