#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace aethera::mcp::benchmarks { namespace { [[nodiscard]] Plot_Input_Request timestamped_drag_request( Event_Type type = Event_Type::pointer_move) { Plot_Input_Request request; request.plot = "datoviz_point"; request.event.type = type; request.event.time_milliseconds = 1'000.0; request.event.position = {240.0, 180.0}; request.event.global_position = {240.0, 180.0}; request.event.button = Mouse_Button::left; request.event.buttons = 1; return request; } void decode_timestamped_drag(benchmark::State& state) { const auto encoded = encode_protocol_value(timestamped_drag_request()); for ([[maybe_unused]] auto iteration : state) { Plot_Input_Request decoded; decode_protocol_value(decoded, encoded); benchmark::DoNotOptimize(decoded.event.time_milliseconds); benchmark::ClobberMemory(); } state.SetItemsProcessed(state.iterations()); } void decode_timed_render(benchmark::State& state) { const auto encoded = encode_protocol_value( Plot_Render_Request{"datoviz_point", 1'000.0, 720, 420}); for ([[maybe_unused]] auto iteration : state) { Plot_Render_Request decoded; decode_protocol_value(decoded, encoded); benchmark::DoNotOptimize(decoded.time_milliseconds); benchmark::ClobberMemory(); } state.SetItemsProcessed(state.iterations()); } class Control_Path : public benchmark::Fixture { public: void SetUp(const benchmark::State&) override { service = Control_Service::create(); } void TearDown(const benchmark::State&) override { service.reset(); } protected: std::shared_ptr service; }; constexpr std::array plot_3d_ids{ "datoviz_point", "datoviz_splat", "datoviz_pixel", "datoviz_marker", "datoviz_sphere", "datoviz_segment", "datoviz_vector", "datoviz_primitive", "datoviz_mesh", "datoviz_spectrogram", "datoviz_path", "datoviz_image", "datoviz_labels", "datoviz_glyph", "datoviz_text", "datoviz_volume"}; constexpr std::size_t splat_plot_index{1}; enum struct Input_Workload : std::uint8_t { steady, drag, wheel, mixed }; struct Concurrent_Workload_State { std::array completed{}; /* Per-Plot publish counts for this benchmark interval. */ }; [[nodiscard]] Plot_Input_Request concurrent_input_request( Input_Workload workload, std::size_t plot_index, std::uint64_t sequence) { Plot_Input_Request request; request.plot = plot_3d_ids[plot_index]; request.event.time_milliseconds = 1'000.0 + static_cast(sequence) * (1'000.0 / 120.0); request.event.position = { 360.0 + static_cast( static_cast((sequence + plot_index * 7U) % 121U) - 60), 210.0 + static_cast( static_cast((sequence * 3U + plot_index * 11U) % 81U) - 40)}; request.event.global_position = request.event.position; if (workload == Input_Workload::wheel || (workload == Input_Workload::mixed && (plot_index & 1U) != 0U)) { request.event.type = Event_Type::wheel; request.event.pixel_delta_y = (sequence & 1U) != 0U ? 120.0 : -120.0; request.event.angle_delta_y = request.event.pixel_delta_y; return request; } request.event.type = Event_Type::pointer_move; request.event.button = Mouse_Button::left; request.event.buttons = 1; return request; } class Concurrent_3D : public benchmark::Fixture { public: void SetUp(const benchmark::State&) override { if (shared_service) { service = shared_service; workload = shared_workload; plots = shared_plots; streams = shared_streams; return; } shared_service = Control_Service::create(); shared_workload = std::make_shared(); shared_plots.reserve(plot_3d_ids.size()); shared_streams.reserve(plot_3d_ids.size()); for (std::size_t index = 0; index < plot_3d_ids.size(); ++index) { auto plot = shared_service->find_plot(plot_3d_ids[index]); if (!plot) throw std::logic_error("concurrent 3D benchmark Plot is unavailable"); const auto stream = plot->subscribe( [workload = shared_workload, index]( std::shared_ptr frame) { if (!frame || !frame->pixels) return; workload->completed[index].fetch_add( 1, std::memory_order_relaxed); }); plot->configure_stream(stream, 720, 420); shared_plots.push_back(std::move(plot)); shared_streams.push_back(stream); } service = shared_service; workload = shared_workload; plots = shared_plots; streams = shared_streams; } void TearDown(const benchmark::State&) override {} static void shutdown() { if (!shared_workload) return; for (std::size_t index = 0; index < shared_plots.size(); ++index) shared_plots[index]->unsubscribe(shared_streams[index]); shared_plots.clear(); shared_streams.clear(); shared_service.reset(); shared_workload.reset(); } protected: [[nodiscard]] bool submit_input_batch( Input_Workload input, std::uint64_t sequence, std::optional pointer_type = std::nullopt) { for (std::size_t plot_index = 0; plot_index < plot_3d_ids.size(); ++plot_index) { const bool wheel = input == Input_Workload::wheel || (input == Input_Workload::mixed && (plot_index & 1U) != 0U); if (pointer_type && wheel) continue; auto request = concurrent_input_request( input, plot_index, sequence); if (pointer_type) { request.event.type = *pointer_type; request.event.buttons = *pointer_type == Event_Type::pointer_release ? 0 : 1; } const auto result = service->call_tool( "aethera_plot_input", encode_protocol_value(request)); if (result.result != Tool_Call_Result::ok) return false; } return true; } void run(benchmark::State& state, Input_Workload input) { for (auto& count : workload->completed) count.store(0, std::memory_order_relaxed); for (const auto& plot : plots) plot->reset_diagnostics(); if (input == Input_Workload::drag || input == Input_Workload::mixed) { if (!submit_input_batch( input, 0, Event_Type::pointer_press)) { state.SkipWithError("16-Plot pointer press batch was rejected"); return; } } const auto runtime_begin = service->call_tool( "aethera_task_runtime", nlohmann::json::object()); const auto started = std::chrono::steady_clock::now(); constexpr auto input_period = std::chrono::nanoseconds{ 1'000'000'000 / 120}; auto next_input = started + input_period; std::uint64_t input_batches{}; std::uint64_t input_requests{}; std::uint32_t input_poll{}; for ([[maybe_unused]] auto iteration : state) { benchmark::DoNotOptimize( workload->completed[splat_plot_index].load( std::memory_order_relaxed)); benchmark::ClobberMemory(); if ((++input_poll & 0x3FFU) != 0U) continue; const auto now = std::chrono::steady_clock::now(); if (input == Input_Workload::steady) continue; if (now < next_input) continue; ++input_batches; if (!submit_input_batch(input, input_batches)) { state.SkipWithError("16-Plot interaction batch was rejected"); break; } input_requests += plot_3d_ids.size(); do next_input += input_period; while (next_input <= now); } const auto finished = std::chrono::steady_clock::now(); if (input == Input_Workload::drag || input == Input_Workload::mixed) { static_cast(submit_input_batch( input, input_batches + 1U, Event_Type::pointer_release)); } const double elapsed_seconds = std::chrono::duration( finished - started).count(); std::uint64_t total_completed{}; double minimum_fps = std::numeric_limits::max(); double maximum_fps{}; double splat_fps{}; for (std::size_t index = 0; index < plots.size(); ++index) { const auto count = workload->completed[index].load( std::memory_order_relaxed); total_completed += count; const double fps = elapsed_seconds > 0.0 ? static_cast(count) / elapsed_seconds : 0.0; minimum_fps = std::min(minimum_fps, fps); maximum_fps = std::max(maximum_fps, fps); if (index == splat_plot_index) splat_fps = fps; const auto diagnostics = plots[index]->diagnostics(); const auto& policy = diagnostics.at("frame_policy"); const auto prefix = "p" + std::to_string(index) + "_"; state.counters[prefix + "fps"] = fps; state.counters[prefix + "requested"] = policy.at("observation").at("request_count").get(); state.counters[prefix + "submitted"] = policy.at("observation").at("submitted_frame_count").get(); state.counters[prefix + "completed"] = policy.at("observation").at("completed_frame_count").get(); state.counters[prefix + "active"] = policy.at("observation").at("active_frame_count").get(); state.counters[prefix + "scene_rejected"] = policy.at("requests").at("scene_rejected").get(); state.counters[prefix + "slot_backpressure"] = policy.at("requests").at("frame_slot_backpressure").get(); state.counters[prefix + "completion_ms"] = policy.at("latency").at("average_completion_ms").get(); const auto& frame_statistics = diagnostics.at("frame_statistics"); const auto statistic_average = [&](std::string_view name) { const auto found = frame_statistics.find(name); return found == frame_statistics.end() ? 0.0 : found->at("average").get(); }; state.counters[prefix + "backend_queue_ms"] = statistic_average("backend_queue_ms"); state.counters[prefix + "backend_plan_ms"] = statistic_average("backend_plan_ms"); } const auto runtime_end = service->call_tool( "aethera_task_runtime", nlohmann::json::object()); const auto runtime_delta = [&](std::string_view key) { if (runtime_begin.result != Tool_Call_Result::ok || runtime_end.result != Tool_Call_Result::ok) return 0.0; const auto begin = runtime_begin.content.at(key).get(); const auto end = runtime_end.content.at(key).get(); return static_cast(end >= begin ? end - begin : 0U); }; const double wall_ns = runtime_delta("observed_wall_time_ns"); const double busy_ns = runtime_delta("worker_busy_time_ns"); const double cpu_ns = runtime_delta("worker_cpu_time_ns"); const double worker_count = runtime_end.result == Tool_Call_Result::ok ? runtime_end.content.at("worker_count").get() : 0.0; state.counters["aggregate_fps"] = elapsed_seconds > 0.0 ? static_cast(total_completed) / elapsed_seconds : 0.0; state.counters["minimum_plot_fps"] = minimum_fps; state.counters["maximum_plot_fps"] = maximum_fps; state.counters["splat_fps"] = splat_fps; state.counters["fairness_pct"] = maximum_fps > 0.0 ? minimum_fps / maximum_fps * 100.0 : 0.0; state.counters["worker_busy_pct"] = wall_ns > 0.0 && worker_count > 0.0 ? busy_ns / (wall_ns * worker_count) * 100.0 : 0.0; state.counters["worker_cpu_pct"] = wall_ns > 0.0 && worker_count > 0.0 ? cpu_ns / (wall_ns * worker_count) * 100.0 : 0.0; state.counters["input_batches"] = static_cast(input_batches); state.counters["input_requests"] = static_cast(input_requests); state.counters["input_request_rate"] = elapsed_seconds > 0.0 ? static_cast(input_requests) / elapsed_seconds : 0.0; state.SetItemsProcessed(static_cast(total_completed)); } private: inline static std::shared_ptr shared_service{}; inline static std::shared_ptr shared_workload{}; inline static std::vector> shared_plots{}; inline static std::vector shared_streams{}; std::shared_ptr service{}; std::shared_ptr workload{}; std::vector> plots{}; std::vector streams{}; }; BENCHMARK_DEFINE_F(Concurrent_3D, Warmup)(benchmark::State& state) { run(state, Input_Workload::steady); } BENCHMARK_DEFINE_F(Concurrent_3D, Steady)(benchmark::State& state) { run(state, Input_Workload::steady); } BENCHMARK_DEFINE_F(Concurrent_3D, All_Plots_Drag)(benchmark::State& state) { run(state, Input_Workload::drag); } BENCHMARK_DEFINE_F(Concurrent_3D, All_Plots_Wheel)(benchmark::State& state) { run(state, Input_Workload::wheel); } BENCHMARK_DEFINE_F(Concurrent_3D, All_Plots_Mixed)(benchmark::State& state) { run(state, Input_Workload::mixed); } BENCHMARK_DEFINE_F(Control_Path, Timestamped_Drag_Admission)( benchmark::State& state) { auto request = timestamped_drag_request(Event_Type::pointer_press); auto arguments = encode_protocol_value(request); const auto press = service->call_tool("aethera_plot_input", arguments); if (press.result != Tool_Call_Result::ok) { state.SkipWithError("timestamped pointer press was rejected"); return; } arguments["event"]["type"] = "pointer_move"; double time_milliseconds = request.event.time_milliseconds; for ([[maybe_unused]] auto iteration : state) { time_milliseconds += 1'000.0 / 120.0; arguments["event"]["time_milliseconds"] = time_milliseconds; const auto result = service->call_tool( "aethera_plot_input", arguments); if (result.result != Tool_Call_Result::ok) { state.SkipWithError("timestamped pointer move was rejected"); break; } benchmark::DoNotOptimize(result.result); } state.SetItemsProcessed(state.iterations()); const auto runtime = service->call_tool( "aethera_task_runtime", nlohmann::json::object()); if (runtime.result != Tool_Call_Result::ok) { state.SkipWithError("Taskflow runtime diagnostics were rejected"); return; } const auto milliseconds = [](const nlohmann::json& value, std::string_view key) { return static_cast(value.at(key).get()) / 1'000'000.0; }; state.counters["taskflow_wall_ms"] = milliseconds(runtime.content, "observed_wall_time_ns"); state.counters["worker_busy_ms"] = milliseconds(runtime.content, "worker_busy_time_ns"); state.counters["worker_cpu_ms"] = milliseconds(runtime.content, "worker_cpu_time_ns"); state.counters["worker_utilization_pct"] = runtime.content.at("worker_utilization").get(); state.counters["worker_cpu_utilization_pct"] = runtime.content.at("worker_cpu_utilization").get(); state.counters["active_taskflows"] = static_cast(runtime.content.at("active_taskflows").get()); state.counters["completed_taskflows"] = static_cast(runtime.content.at("completed_taskflows").get()); state.SetLabel(runtime.content.at("longest_task").at("name").get()); } BENCHMARK(decode_timestamped_drag); BENCHMARK(decode_timed_render); BENCHMARK_REGISTER_F(Control_Path, Timestamped_Drag_Admission) ->Iterations(512); /* Fixture 静态持有 16 个 Plot;MinTime 校准不会重建 Datoviz Scene。 */ BENCHMARK_REGISTER_F(Concurrent_3D, Warmup) ->MinTime(10.0)->UseRealTime(); BENCHMARK_REGISTER_F(Concurrent_3D, Steady) ->MinTime(10.0)->UseRealTime(); BENCHMARK_REGISTER_F(Concurrent_3D, All_Plots_Drag) ->MinTime(10.0)->UseRealTime(); BENCHMARK_REGISTER_F(Concurrent_3D, All_Plots_Wheel) ->MinTime(10.0)->UseRealTime(); BENCHMARK_REGISTER_F(Concurrent_3D, All_Plots_Mixed) ->MinTime(10.0)->UseRealTime(); void shutdown_concurrent_3d_benchmark() { Concurrent_3D::shutdown(); } } } int main(int argc, char** argv) { aethera::initialize_runtime({}); benchmark::Initialize(&argc, argv); if (benchmark::ReportUnrecognizedArguments(argc, argv)) return 2; benchmark::RunSpecifiedBenchmarks(); aethera::mcp::benchmarks::shutdown_concurrent_3d_benchmark(); benchmark::Shutdown(); return 0; }