177 lines
5.2 KiB
C++
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_{};
|
|
};
|
|
}
|