3D优化完成

This commit is contained in:
2026-08-28 21:11:39 +08:00
parent 93d3f93774
commit 647ad6a66c
36 changed files with 1974 additions and 1548 deletions
+286
View File
@@ -3,8 +3,16 @@
#include <mcp/core/Protocol_Type.hpp>
#include <benchmark/benchmark.h>
#include <render_common.hpp>
#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <string_view>
#include <vector>
namespace aethera::mcp::benchmarks {
namespace {
@@ -59,6 +67,268 @@ protected:
std::shared_ptr<Control_Service> service;
};
constexpr std::array<std::string_view, 16> 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<std::atomic_uint64_t, plot_3d_ids.size()> 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<double>(sequence) * (1'000.0 / 120.0);
request.event.position = {
360.0 + static_cast<double>(
static_cast<std::int64_t>((sequence + plot_index * 7U) % 121U) - 60),
210.0 + static_cast<double>(
static_cast<std::int64_t>((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<Concurrent_Workload_State>();
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<const web::Plot_Stream_Frame> 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<Event_Type> 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<void>(submit_input_batch(
input, input_batches + 1U, Event_Type::pointer_release));
}
const double elapsed_seconds = std::chrono::duration<double>(
finished - started).count();
std::uint64_t total_completed{};
double minimum_fps = std::numeric_limits<double>::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<double>(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<double>();
state.counters[prefix + "submitted"] =
policy.at("observation").at("submitted_frame_count").get<double>();
state.counters[prefix + "completed"] =
policy.at("observation").at("completed_frame_count").get<double>();
state.counters[prefix + "active"] =
policy.at("observation").at("active_frame_count").get<double>();
state.counters[prefix + "scene_rejected"] =
policy.at("requests").at("scene_rejected").get<double>();
state.counters[prefix + "slot_backpressure"] =
policy.at("requests").at("frame_slot_backpressure").get<double>();
state.counters[prefix + "completion_ms"] =
policy.at("latency").at("average_completion_ms").get<double>();
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<double>();
};
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<std::uint64_t>();
const auto end = runtime_end.content.at(key).get<std::uint64_t>();
return static_cast<double>(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<double>() : 0.0;
state.counters["aggregate_fps"] = elapsed_seconds > 0.0
? static_cast<double>(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<double>(input_batches);
state.counters["input_requests"] = static_cast<double>(input_requests);
state.counters["input_request_rate"] = elapsed_seconds > 0.0
? static_cast<double>(input_requests) / elapsed_seconds : 0.0;
state.SetItemsProcessed(static_cast<std::int64_t>(total_completed));
}
private:
inline static std::shared_ptr<Control_Service> shared_service{};
inline static std::shared_ptr<Concurrent_Workload_State> shared_workload{};
inline static std::vector<std::shared_ptr<web::Plot>> shared_plots{};
inline static std::vector<web::Plot::Stream_Id> shared_streams{};
std::shared_ptr<Control_Service> service{};
std::shared_ptr<Concurrent_Workload_State> workload{};
std::vector<std::shared_ptr<web::Plot>> plots{};
std::vector<web::Plot::Stream_Id> 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);
@@ -116,6 +386,21 @@ BENCHMARK(decode_timestamped_drag);
BENCHMARK(decode_timed_render);
BENCHMARK_REGISTER_F(Control_Path, Timestamped_Drag_Admission)
->Iterations(512);
/* Fixture 静态持有 16 个 PlotMinTime 校准不会重建 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();
}
}
}
@@ -125,6 +410,7 @@ int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv)) return 2;
benchmark::RunSpecifiedBenchmarks();
aethera::mcp::benchmarks::shutdown_concurrent_3d_benchmark();
benchmark::Shutdown();
return 0;
}