From 09093a65e6231e0e30b03c08eeb222ba18536734 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Wed, 29 Jul 2026 18:39:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Renderive/architecture/Plot.cpp | 52 +++++++++++++++++----- Renderive/architecture/Plot.h | 2 +- Renderive/architecture/Renderable_Core.h | 3 ++ Renderive/plottable/Performance_Shower.cpp | 31 ++++++++++--- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/Renderive/architecture/Plot.cpp b/Renderive/architecture/Plot.cpp index dc216f6..22a681b 100644 --- a/Renderive/architecture/Plot.cpp +++ b/Renderive/architecture/Plot.cpp @@ -15,6 +15,8 @@ static std::uint64_t steady_now_ns() { return static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); } static double elapsed_ms(std::uint64_t start_ns, std::uint64_t end_ns) { + if (end_ns <= start_ns) + return 0.0; return static_cast(end_ns - start_ns) / 1000000.0; } static QString job_state_text(Renderable::Job_State state) { @@ -220,8 +222,12 @@ static double positive_frame_cost(double value) { struct Frame_Phase_Breakdown { double data_ms{}; double painter_ms{}; + double request_wait_ms{}; double queue_ms{}; + double scheduler_wait_ms{}; + double present_wait_ms{}; double lock_wait_ms{}; + double pipeline_ms{}; double measured_ms{}; double other_ms{}; double phase_total_ms{}; @@ -230,14 +236,20 @@ struct Frame_Phase_Breakdown { }; static Frame_Phase_Breakdown frame_phase_breakdown(const Frame_Lifecycle_Sample& sample) { Frame_Phase_Breakdown value; + double paint_overhead_ms = positive_frame_cost(sample.paint_event_ms - sample.paint_consume_ms - sample.paint_draw_image_ms); + double finish_overhead_ms = positive_frame_cost(sample.finish_render_ms - sample.publish_color_ms); value.data_ms = sample.prepare_data_ms + sample.image_prepare_ms; - value.painter_ms = sample.painter_draw_ms + sample.painter_end_ms + sample.paint_draw_image_ms; - value.queue_ms = sample.request_to_submit_ms + sample.cpu_queue_wait_ms + sample.update_to_paint_ms; + value.painter_ms = sample.painter_draw_ms + sample.painter_end_ms + sample.paint_draw_image_ms + paint_overhead_ms; + value.request_wait_ms = sample.request_to_submit_ms; + value.queue_ms = sample.cpu_queue_wait_ms; + value.scheduler_wait_ms = sample.finish_queue_wait_ms; + value.present_wait_ms = sample.update_to_paint_ms; value.lock_wait_ms = sample.color_wait_ms + sample.paint_consume_ms + sample.publish_color_ms; - value.measured_ms = value.data_ms + value.painter_ms + value.queue_ms + value.lock_wait_ms + sample.stats_log_ms; + value.pipeline_ms = sample.submit_overhead_ms + finish_overhead_ms; + value.measured_ms = value.data_ms + value.painter_ms + value.request_wait_ms + value.queue_ms + value.scheduler_wait_ms + value.present_wait_ms + value.lock_wait_ms + value.pipeline_ms + sample.stats_log_ms; value.phase_total_ms = sample.frame_total_ms > value.measured_ms ? sample.frame_total_ms : value.measured_ms; value.other_ms = positive_frame_cost(value.phase_total_ms - value.measured_ms); - value.necessary_ms = value.data_ms + value.painter_ms; + value.necessary_ms = value.data_ms + value.painter_ms + value.pipeline_ms + value.request_wait_ms + value.scheduler_wait_ms + value.present_wait_ms; value.unnecessary_ms = positive_frame_cost(value.phase_total_ms - value.necessary_ms); return value; } @@ -251,16 +263,24 @@ static void publish_frame_lifecycle_sample(Performance_Shower* shower, Frame_Lif shower->set_gauge("FrameLife", "unnecessaryMs", phase.unnecessary_ms); shower->set_gauge("FrameLife", "dataMs", phase.data_ms); shower->set_gauge("FrameLife", "painterMs", phase.painter_ms); + shower->set_gauge("FrameLife", "requestWaitMs", phase.request_wait_ms); shower->set_gauge("FrameLife", "queueMs", phase.queue_ms); + shower->set_gauge("FrameLife", "schedulerWaitMs", phase.scheduler_wait_ms); + shower->set_gauge("FrameLife", "presentWaitMs", phase.present_wait_ms); shower->set_gauge("FrameLife", "lockWaitMs", phase.lock_wait_ms); + shower->set_gauge("FrameLife", "pipelineMs", phase.pipeline_ms); shower->set_gauge("FrameLife", "otherMs", phase.other_ms); shower->set_gauge("FrameLife", "necessaryRatio", frame_ratio_percent(phase.necessary_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "unnecessaryRatio", frame_ratio_percent(phase.unnecessary_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "otherRatio", frame_ratio_percent(phase.other_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "dataRatio", frame_ratio_percent(phase.data_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "painterRatio", frame_ratio_percent(phase.painter_ms, phase.phase_total_ms)); + shower->set_gauge("FrameLife", "requestWaitRatio", frame_ratio_percent(phase.request_wait_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "queueRatio", frame_ratio_percent(phase.queue_ms, phase.phase_total_ms)); + shower->set_gauge("FrameLife", "schedulerWaitRatio", frame_ratio_percent(phase.scheduler_wait_ms, phase.phase_total_ms)); + shower->set_gauge("FrameLife", "presentWaitRatio", frame_ratio_percent(phase.present_wait_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "lockWaitRatio", frame_ratio_percent(phase.lock_wait_ms, phase.phase_total_ms)); + shower->set_gauge("FrameLife", "pipelineRatio", frame_ratio_percent(phase.pipeline_ms, phase.phase_total_ms)); shower->set_gauge("FrameLife", "renderableCount", static_cast(sample.renderable_count)); shower->set_gauge("FrameLife", "visibleRenderableCount", static_cast(sample.visible_renderable_count)); } @@ -667,7 +687,6 @@ bool Abs_Plot::submit_render_once() { if (shower) publish_pipeline_stats(d); Plot_Private* private_data = d; - std::uint64_t cpu_post_ns = steady_now_ns(); auto renderable_snapshot_owner = renderive::make_shared(std::move(snapshot)); std::size_t frame_memory_hint = estimate_frame_memory(*renderable_snapshot_owner, *frame_snapshot); Abs_Plot * plot = this; @@ -690,13 +709,15 @@ bool Abs_Plot::submit_render_once() { task_context->color_lease_owner = color_lease_owner; task_context->color = color; task_context->version = version; - task_context->cpu_post_ns = cpu_post_ns; task_context->root = root; task_context->renderable_snapshot_owner = renderable_snapshot_owner; task_context->frame_snapshot = frame_snapshot; task_context->update_states = std::move(frame_update_states); task_context->frame_memory_hint = frame_memory_hint; task_context->plot = plot; + std::uint64_t cpu_post_ns = steady_now_ns(); + frame_lifecycle_sample.submit_overhead_ms = positive_frame_cost(elapsed_ms(submit_ns, cpu_post_ns) - frame_lifecycle_sample.prepare_data_ms - frame_lifecycle_sample.color_wait_ms); + task_context->cpu_post_ns = cpu_post_ns; task_context->frame_lifecycle_sample = frame_lifecycle_sample; private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); scheduler.post_cpu([task_context]() { @@ -718,9 +739,10 @@ bool Abs_Plot::submit_render_once() { return; } Abs_Plot* plot = task_context->plot; - Global::instance()->render_scheduler().post([plot, private_data]() { + std::uint64_t finish_post_ns = steady_now_ns(); + Global::instance()->render_scheduler().post([plot, private_data, finish_post_ns]() { if (!private_data->destroying.load(std::memory_order_acquire)) - plot->finish_render(); + plot->finish_render(elapsed_ms(finish_post_ns, steady_now_ns())); notify_render_task_done(private_data); }); }); @@ -838,14 +860,18 @@ void Abs_Plot::mark_renderable_submitted(const std::shared_ptr& able return; able->d_ptr->next_render_submit_ns.store(now_ns + static_cast(1000000000.0 / fps), std::memory_order_release); } -void Abs_Plot::finish_render() { +void Abs_Plot::finish_render(double finish_queue_wait_ms) { if (d->destroying.load(std::memory_order_acquire)) return; + std::uint64_t finish_start_ns = steady_now_ns(); Renderable::Render_Pipeline& pipeline = d->pipeline; QRegion update_region; auto shower_owner = performance_shower_owner(d); Performance_Shower* shower = shower_owner.get(); Renderable::Color_Buffer* ready_color{}; + Renderable::Color_Buffer* render_color = pipeline.color_by_role(Color_Render); + if (render_color) + render_color->frame_lifecycle_sample.finish_queue_wait_ms = finish_queue_wait_ms; { std::uint64_t publish_start_ns = steady_now_ns(); update_region = pipeline.publish_render_color(); @@ -863,6 +889,10 @@ void Abs_Plot::finish_render() { ready_color->frame_lifecycle_sample.update_request_ns = update_request_ns; request_update(update_region, update_request_ns); } + else { + ready_color->frame_lifecycle_sample.update_request_ns = steady_now_ns(); + } + ready_color->frame_lifecycle_sample.finish_render_ms = elapsed_ms(finish_start_ns, steady_now_ns()); on_render_request(Render_Request_Source::Finish); } void Abs_Plot::render_color(Renderable::Color_Buffer* color, std::uint64_t version, const std::shared_ptr& root, const Renderable_Snapshot& snapshot, const Plot_Render_Snapshot& render_snapshot_data, std::pmr::vector>&& update_states, Frame_Lifecycle_Sample& frame_lifecycle_sample) { @@ -971,14 +1001,14 @@ void Abs_Plot::request_update(const QRegion& region, std::uint64_t request_ns) { if (!request_ns) request_ns = steady_now_ns(); d->last_update_request_ns.store(request_ns, std::memory_order_release); - QTimer::singleShot(0, this, [this, region]() { + QMetaObject::invokeMethod(this, [this, region]() { if (d->destroying.load(std::memory_order_acquire)) return; if (region.isEmpty()) update(); else update(region); - }); + }, Qt::QueuedConnection); } QColor Abs_Plot::background_color() { std::lock_guard lock(render_context->mutex); diff --git a/Renderive/architecture/Plot.h b/Renderive/architecture/Plot.h index 686226a..79c5c10 100644 --- a/Renderive/architecture/Plot.h +++ b/Renderive/architecture/Plot.h @@ -82,7 +82,7 @@ private: void schedule_max_fps_submit(std::uint64_t target_ns); bool renderable_ready_for_submit(const std::shared_ptr& able, Render_Request_Source source, std::uint64_t now_ns); void mark_renderable_submitted(const std::shared_ptr& able, std::uint64_t now_ns); - void finish_render(); + void finish_render(double finish_queue_wait_ms); void request_update(const QRegion& region, std::uint64_t request_ns = 0); static void render_color(Renderable::Color_Buffer* color, std::uint64_t version, const std::shared_ptr& root, const Renderable_Snapshot& snapshot, const Plot_Render_Snapshot& render_snapshot_data, std::pmr::vector>&& update_states, Frame_Lifecycle_Sample& frame_lifecycle_sample); friend class Render_Scheduler; diff --git a/Renderive/architecture/Renderable_Core.h b/Renderive/architecture/Renderable_Core.h index cf13e5a..d3d8473 100644 --- a/Renderive/architecture/Renderable_Core.h +++ b/Renderive/architecture/Renderable_Core.h @@ -20,13 +20,16 @@ struct Frame_Lifecycle_Sample { double request_to_submit_ms{}; double prepare_data_ms{}; double renderable_prepare_ms{}; + double submit_overhead_ms{}; double color_wait_ms{}; double cpu_queue_wait_ms{}; + double finish_queue_wait_ms{}; double render_color_ms{}; double image_prepare_ms{}; double painter_draw_ms{}; double painter_end_ms{}; double publish_color_ms{}; + double finish_render_ms{}; double update_to_paint_ms{}; double paint_event_ms{}; double paint_consume_ms{}; diff --git a/Renderive/plottable/Performance_Shower.cpp b/Renderive/plottable/Performance_Shower.cpp index beb180d..5cae16d 100644 --- a/Renderive/plottable/Performance_Shower.cpp +++ b/Renderive/plottable/Performance_Shower.cpp @@ -15,8 +15,12 @@ static double ratio_percent(double value, double total) { struct Frame_Phase_Breakdown { double data_ms{}; double painter_ms{}; + double request_wait_ms{}; double queue_ms{}; + double scheduler_wait_ms{}; + double present_wait_ms{}; double lock_wait_ms{}; + double pipeline_ms{}; double measured_ms{}; double other_ms{}; double phase_total_ms{}; @@ -25,14 +29,20 @@ struct Frame_Phase_Breakdown { }; static Frame_Phase_Breakdown frame_phase_breakdown(const Frame_Lifecycle_Sample& sample) { Frame_Phase_Breakdown value; + double paint_overhead_ms = non_negative(sample.paint_event_ms - sample.paint_consume_ms - sample.paint_draw_image_ms); + double finish_overhead_ms = non_negative(sample.finish_render_ms - sample.publish_color_ms); value.data_ms = sample.prepare_data_ms + sample.image_prepare_ms; - value.painter_ms = sample.painter_draw_ms + sample.painter_end_ms + sample.paint_draw_image_ms; - value.queue_ms = sample.request_to_submit_ms + sample.cpu_queue_wait_ms + sample.update_to_paint_ms; + value.painter_ms = sample.painter_draw_ms + sample.painter_end_ms + sample.paint_draw_image_ms + paint_overhead_ms; + value.request_wait_ms = sample.request_to_submit_ms; + value.queue_ms = sample.cpu_queue_wait_ms; + value.scheduler_wait_ms = sample.finish_queue_wait_ms; + value.present_wait_ms = sample.update_to_paint_ms; value.lock_wait_ms = sample.color_wait_ms + sample.paint_consume_ms + sample.publish_color_ms; - value.measured_ms = value.data_ms + value.painter_ms + value.queue_ms + value.lock_wait_ms + sample.stats_log_ms; + value.pipeline_ms = sample.submit_overhead_ms + finish_overhead_ms; + value.measured_ms = value.data_ms + value.painter_ms + value.request_wait_ms + value.queue_ms + value.scheduler_wait_ms + value.present_wait_ms + value.lock_wait_ms + value.pipeline_ms + sample.stats_log_ms; value.phase_total_ms = sample.frame_total_ms > value.measured_ms ? sample.frame_total_ms : value.measured_ms; value.other_ms = non_negative(value.phase_total_ms - value.measured_ms); - value.necessary_ms = value.data_ms + value.painter_ms; + value.necessary_ms = value.data_ms + value.painter_ms + value.pipeline_ms + value.request_wait_ms + value.scheduler_wait_ms + value.present_wait_ms; value.unnecessary_ms = non_negative(value.phase_total_ms - value.necessary_ms); return value; } @@ -52,27 +62,38 @@ public: << phase.unnecessary_ms << ',' << phase.data_ms << ',' << phase.painter_ms << ',' + << phase.request_wait_ms << ',' << phase.queue_ms << ',' + << phase.scheduler_wait_ms << ',' + << phase.present_wait_ms << ',' << phase.lock_wait_ms << ',' + << phase.pipeline_ms << ',' << phase.other_ms << ',' << ratio_percent(phase.necessary_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.unnecessary_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.other_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.data_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.painter_ms, phase.phase_total_ms) << ',' + << ratio_percent(phase.request_wait_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.queue_ms, phase.phase_total_ms) << ',' + << ratio_percent(phase.scheduler_wait_ms, phase.phase_total_ms) << ',' + << ratio_percent(phase.present_wait_ms, phase.phase_total_ms) << ',' << ratio_percent(phase.lock_wait_ms, phase.phase_total_ms) << ',' + << ratio_percent(phase.pipeline_ms, phase.phase_total_ms) << ',' << ratio_percent(sample.stats_log_ms, phase.phase_total_ms) << ',' << sample.request_to_submit_ms << ',' << sample.prepare_data_ms << ',' << sample.renderable_prepare_ms << ',' + << sample.submit_overhead_ms << ',' << sample.color_wait_ms << ',' << sample.cpu_queue_wait_ms << ',' + << sample.finish_queue_wait_ms << ',' << sample.render_color_ms << ',' << sample.image_prepare_ms << ',' << sample.painter_draw_ms << ',' << sample.painter_end_ms << ',' << sample.publish_color_ms << ',' + << sample.finish_render_ms << ',' << sample.update_to_paint_ms << ',' << sample.paint_event_ms << ',' << sample.paint_consume_ms << ',' @@ -110,7 +131,7 @@ private: return QDir(dir).filePath("renderive_performance_log.csv"); } std::string header() const { - return "plot_id,version,frame_total_ms,phase_total_ms,necessary_ms,unnecessary_ms,data_ms,painter_ms,queue_ms,lock_wait_ms,other_ms,necessary_ratio,unnecessary_ratio,other_ratio,data_ratio,painter_ratio,queue_ratio,lock_wait_ratio,stats_log_ratio,request_to_submit_ms,prepare_data_ms,renderable_prepare_ms,color_wait_ms,cpu_queue_wait_ms,render_color_ms,image_prepare_ms,painter_draw_ms,painter_end_ms,publish_color_ms,update_to_paint_ms,paint_event_ms,paint_consume_ms,paint_draw_image_ms,stats_log_ms,renderable_count,visible_renderable_count,direct_draw_count,local_cache_count"; + return "plot_id,version,frame_total_ms,phase_total_ms,necessary_ms,unnecessary_ms,data_ms,painter_ms,request_wait_ms,queue_ms,scheduler_wait_ms,present_wait_ms,lock_wait_ms,pipeline_ms,other_ms,necessary_ratio,unnecessary_ratio,other_ratio,data_ratio,painter_ratio,request_wait_ratio,queue_ratio,scheduler_wait_ratio,present_wait_ratio,lock_wait_ratio,pipeline_ratio,stats_log_ratio,request_to_submit_ms,prepare_data_ms,renderable_prepare_ms,submit_overhead_ms,color_wait_ms,cpu_queue_wait_ms,finish_queue_wait_ms,render_color_ms,image_prepare_ms,painter_draw_ms,painter_end_ms,publish_color_ms,finish_render_ms,update_to_paint_ms,paint_event_ms,paint_consume_ms,paint_draw_image_ms,stats_log_ms,renderable_count,visible_renderable_count,direct_draw_count,local_cache_count"; } }; Performance_Frame_Log& frame_log() {