仍然闪烁
This commit is contained in:
@@ -9,37 +9,42 @@
|
||||
#include <thread>
|
||||
|
||||
namespace renderive {
|
||||
struct Render_Executor_Metrics;
|
||||
|
||||
struct Frame_Task_Counters {
|
||||
std::atomic_uint32_t task_count{0};
|
||||
std::atomic_uint32_t active_count{0};
|
||||
std::atomic_uint32_t peak_parallelism{0};
|
||||
std::atomic_uint64_t task_duration_total_ns{0};
|
||||
};
|
||||
|
||||
struct Taskflow_Graph_Impl {
|
||||
explicit Taskflow_Graph_Impl(tf::Taskflow& taskflow) : taskflow(taskflow) {}
|
||||
Taskflow_Graph_Impl(
|
||||
tf::Taskflow& taskflow,
|
||||
std::shared_ptr<Render_Executor_Metrics> metrics,
|
||||
std::shared_ptr<Frame_Task_Counters> frame_counters)
|
||||
: taskflow(taskflow),
|
||||
metrics(std::move(metrics)),
|
||||
frame_counters(std::move(frame_counters)) {}
|
||||
tf::Taskflow& taskflow;
|
||||
std::shared_ptr<Render_Executor_Metrics> metrics;
|
||||
std::shared_ptr<Frame_Task_Counters> frame_counters;
|
||||
std::vector<tf::Task> tasks;
|
||||
};
|
||||
|
||||
Render_Task_Graph::Render_Task_Graph(void* impl) noexcept : impl(impl) {}
|
||||
|
||||
Render_Task_Graph_Node Render_Task_Graph::emplace(Task work) {
|
||||
auto* graph = static_cast<Taskflow_Graph_Impl*>(impl);
|
||||
if (!graph || !work)
|
||||
return {};
|
||||
auto work_ptr = std::make_shared<Task>(std::move(work));
|
||||
auto task = graph->taskflow.emplace([work_ptr]() mutable {
|
||||
if (work_ptr && *work_ptr)
|
||||
(*work_ptr)();
|
||||
});
|
||||
graph->tasks.push_back(task);
|
||||
return {static_cast<std::uint32_t>(graph->tasks.size() - 1)};
|
||||
}
|
||||
|
||||
void Render_Task_Graph::precede(Render_Task_Graph_Node before, Render_Task_Graph_Node after) {
|
||||
auto* graph = static_cast<Taskflow_Graph_Impl*>(impl);
|
||||
if (!graph || !before || !after)
|
||||
return;
|
||||
if (before.index >= graph->tasks.size() || after.index >= graph->tasks.size())
|
||||
return;
|
||||
graph->tasks[before.index].precede(graph->tasks[after.index]);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Taskflow_Subflow_Impl {
|
||||
Taskflow_Subflow_Impl(
|
||||
tf::Subflow& subflow,
|
||||
std::shared_ptr<Render_Executor_Metrics> metrics,
|
||||
std::shared_ptr<Frame_Task_Counters> frame_counters)
|
||||
: subflow(subflow),
|
||||
metrics(std::move(metrics)),
|
||||
frame_counters(std::move(frame_counters)) {}
|
||||
tf::Subflow& subflow;
|
||||
std::shared_ptr<Render_Executor_Metrics> metrics;
|
||||
std::shared_ptr<Frame_Task_Counters> frame_counters;
|
||||
std::vector<tf::Task> tasks;
|
||||
};
|
||||
|
||||
struct Render_Executor_Metrics {
|
||||
std::size_t worker_count{};
|
||||
@@ -89,7 +94,113 @@ void add_kind_count(Render_Executor_Metrics& metrics, Render_Task_Kind kind) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
void begin_business_task(Render_Executor_Metrics* metrics, Frame_Task_Counters* counters, Render_Task_Kind kind) {
|
||||
if (metrics)
|
||||
add_kind_count(*metrics, kind);
|
||||
if (!counters)
|
||||
return;
|
||||
counters->task_count.fetch_add(1, std::memory_order_relaxed);
|
||||
std::uint32_t active = counters->active_count.fetch_add(1, std::memory_order_acq_rel) + 1;
|
||||
std::uint32_t peak = counters->peak_parallelism.load(std::memory_order_acquire);
|
||||
while (peak < active && !counters->peak_parallelism.compare_exchange_weak(peak, active, std::memory_order_acq_rel, std::memory_order_acquire)) {}
|
||||
}
|
||||
|
||||
void end_business_task(Frame_Task_Counters* counters, std::uint64_t begin_ns) {
|
||||
if (!counters)
|
||||
return;
|
||||
std::uint64_t end_ns = steady_now_ns();
|
||||
counters->task_duration_total_ns.fetch_add(end_ns > begin_ns ? end_ns - begin_ns : 0, std::memory_order_relaxed);
|
||||
counters->active_count.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
Task wrap_business_task(
|
||||
Render_Task_Kind kind,
|
||||
Task work,
|
||||
std::shared_ptr<Render_Executor_Metrics> metrics,
|
||||
std::shared_ptr<Frame_Task_Counters> counters) {
|
||||
return Task([kind, work = std::move(work), metrics = std::move(metrics), counters = std::move(counters)]() mutable {
|
||||
std::uint64_t begin_ns = steady_now_ns();
|
||||
begin_business_task(metrics.get(), counters.get(), kind);
|
||||
if (work)
|
||||
work();
|
||||
end_business_task(counters.get(), begin_ns);
|
||||
});
|
||||
}
|
||||
|
||||
Render_Task_Subflow::Render_Task_Subflow(void* impl) noexcept : impl(impl) {}
|
||||
|
||||
Render_Task_Graph_Node Render_Task_Subflow::emplace(Render_Task_Kind kind, Task work) {
|
||||
auto* graph = static_cast<Taskflow_Subflow_Impl*>(impl);
|
||||
if (!graph || !work)
|
||||
return {};
|
||||
auto wrapped = std::make_shared<Task>(wrap_business_task(kind, std::move(work), graph->metrics, graph->frame_counters));
|
||||
auto task = graph->subflow.emplace([wrapped]() mutable {
|
||||
if (wrapped && *wrapped)
|
||||
(*wrapped)();
|
||||
});
|
||||
graph->tasks.push_back(task);
|
||||
return {static_cast<std::uint32_t>(graph->tasks.size() - 1)};
|
||||
}
|
||||
|
||||
void Render_Task_Subflow::precede(Render_Task_Graph_Node before, Render_Task_Graph_Node after) {
|
||||
auto* graph = static_cast<Taskflow_Subflow_Impl*>(impl);
|
||||
if (!graph || !before || !after)
|
||||
return;
|
||||
if (before.index >= graph->tasks.size() || after.index >= graph->tasks.size())
|
||||
return;
|
||||
graph->tasks[before.index].precede(graph->tasks[after.index]);
|
||||
}
|
||||
|
||||
void Render_Task_Subflow::join() {
|
||||
if (joined)
|
||||
return;
|
||||
auto* graph = static_cast<Taskflow_Subflow_Impl*>(impl);
|
||||
if (!graph)
|
||||
return;
|
||||
graph->subflow.join();
|
||||
joined = true;
|
||||
}
|
||||
|
||||
Render_Task_Graph::Render_Task_Graph(void* impl) noexcept : impl(impl) {}
|
||||
|
||||
Render_Task_Graph_Node Render_Task_Graph::emplace(Render_Task_Kind kind, Task work) {
|
||||
auto* graph = static_cast<Taskflow_Graph_Impl*>(impl);
|
||||
if (!graph || !work)
|
||||
return {};
|
||||
auto wrapped = std::make_shared<Task>(wrap_business_task(kind, std::move(work), graph->metrics, graph->frame_counters));
|
||||
auto task = graph->taskflow.emplace([wrapped]() mutable {
|
||||
if (wrapped && *wrapped)
|
||||
(*wrapped)();
|
||||
});
|
||||
graph->tasks.push_back(task);
|
||||
return {static_cast<std::uint32_t>(graph->tasks.size() - 1)};
|
||||
}
|
||||
|
||||
Render_Task_Graph_Node Render_Task_Graph::emplace_subflow(Render_Task_Kind kind, Subflow_Builder builder) {
|
||||
auto* graph = static_cast<Taskflow_Graph_Impl*>(impl);
|
||||
if (!graph || !builder)
|
||||
return {};
|
||||
auto task = graph->taskflow.emplace([kind, builder = std::move(builder), metrics = graph->metrics, counters = graph->frame_counters](tf::Subflow& raw_subflow) mutable {
|
||||
std::uint64_t begin_ns = steady_now_ns();
|
||||
begin_business_task(metrics.get(), counters.get(), kind);
|
||||
Taskflow_Subflow_Impl subflow_impl(raw_subflow, metrics, counters);
|
||||
Render_Task_Subflow subflow(&subflow_impl);
|
||||
builder(subflow);
|
||||
subflow.join();
|
||||
end_business_task(counters.get(), begin_ns);
|
||||
});
|
||||
graph->tasks.push_back(task);
|
||||
return {static_cast<std::uint32_t>(graph->tasks.size() - 1)};
|
||||
}
|
||||
|
||||
void Render_Task_Graph::precede(Render_Task_Graph_Node before, Render_Task_Graph_Node after) {
|
||||
auto* graph = static_cast<Taskflow_Graph_Impl*>(impl);
|
||||
if (!graph || !before || !after)
|
||||
return;
|
||||
if (before.index >= graph->tasks.size() || after.index >= graph->tasks.size())
|
||||
return;
|
||||
graph->tasks[before.index].precede(graph->tasks[after.index]);
|
||||
}
|
||||
|
||||
class Render_Executor_Observer final : public tf::ObserverInterface {
|
||||
public:
|
||||
@@ -209,7 +320,6 @@ public:
|
||||
private:
|
||||
void record_submission(Render_Executor_Task& task) {
|
||||
metrics->submitted_tasks.fetch_add(1, std::memory_order_relaxed);
|
||||
add_kind_count(*metrics, task.kind);
|
||||
if (task.frame_job)
|
||||
metrics->queued_frame_jobs.fetch_add(1, std::memory_order_relaxed);
|
||||
if (task.frame_stat)
|
||||
@@ -220,6 +330,7 @@ private:
|
||||
auto task_ptr = std::make_shared<Render_Executor_Task>(std::move(task));
|
||||
auto completion = std::make_shared<Task>(std::move(task_ptr->completion));
|
||||
auto run_record = std::make_shared<Task_Run_Record>();
|
||||
auto frame_counters = std::make_shared<Frame_Task_Counters>();
|
||||
auto topology = std::make_shared<tf::Taskflow>();
|
||||
auto entry = topology->emplace([this, enqueue_ns, task_ptr, run_record]() mutable {
|
||||
Render_Executor_Task& task = *task_ptr;
|
||||
@@ -234,7 +345,7 @@ private:
|
||||
metrics->active_frame_jobs.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
});
|
||||
auto exit = topology->emplace([this, task_ptr, run_record]() mutable {
|
||||
auto exit = topology->emplace([this, task_ptr, run_record, frame_counters]() mutable {
|
||||
Render_Executor_Task& task = *task_ptr;
|
||||
std::uint64_t end_ns = steady_now_ns();
|
||||
std::uint64_t begin_ns = run_record->begin_ns;
|
||||
@@ -242,11 +353,14 @@ private:
|
||||
std::uint64_t run_ns = end_ns > begin_ns ? end_ns - begin_ns : 0;
|
||||
if (task.frame_stat) {
|
||||
Frame_Worker_Stats& stat = *task.frame_stat;
|
||||
stat.task_count += std::max<std::uint32_t>(1, task.logical_task_count);
|
||||
stat.peak_parallelism = static_cast<std::uint32_t>(std::max<std::uint64_t>(stat.peak_parallelism, metrics->peak_concurrency.load(std::memory_order_acquire)));
|
||||
std::uint32_t task_count = frame_counters ? frame_counters->task_count.load(std::memory_order_acquire) : 0;
|
||||
std::uint32_t peak_parallelism = frame_counters ? frame_counters->peak_parallelism.load(std::memory_order_acquire) : 0;
|
||||
std::uint64_t task_duration_total_ns = frame_counters ? frame_counters->task_duration_total_ns.load(std::memory_order_acquire) : 0;
|
||||
stat.task_count += task_count;
|
||||
stat.peak_parallelism = std::max(stat.peak_parallelism, peak_parallelism);
|
||||
stat.queue_wait_total_ns += queue_wait_ns;
|
||||
stat.queue_wait_max_ns = std::max(stat.queue_wait_max_ns, queue_wait_ns);
|
||||
stat.worker_run_total_ns += run_ns;
|
||||
stat.worker_run_total_ns += task_duration_total_ns;
|
||||
stat.parallel_stage_wall_ns += run_ns;
|
||||
stat.executor_at_finish = snapshot();
|
||||
}
|
||||
@@ -254,16 +368,17 @@ private:
|
||||
metrics->active_frame_jobs.fetch_sub(1, std::memory_order_relaxed);
|
||||
});
|
||||
if (task_ptr->build_graph) {
|
||||
Taskflow_Graph_Impl graph_impl(*topology);
|
||||
Taskflow_Graph_Impl graph_impl(*topology, metrics, frame_counters);
|
||||
graph_impl.tasks.push_back(entry);
|
||||
graph_impl.tasks.push_back(exit);
|
||||
Render_Task_Graph graph(&graph_impl);
|
||||
task_ptr->build_graph(graph, {0}, {1});
|
||||
}
|
||||
else {
|
||||
auto work = topology->emplace([task_ptr]() mutable {
|
||||
if (task_ptr->work)
|
||||
task_ptr->work();
|
||||
auto wrapped = std::make_shared<Task>(wrap_business_task(task_ptr->kind, std::move(task_ptr->work), metrics, frame_counters));
|
||||
auto work = topology->emplace([wrapped]() mutable {
|
||||
if (wrapped && *wrapped)
|
||||
(*wrapped)();
|
||||
});
|
||||
entry.precede(work);
|
||||
work.precede(exit);
|
||||
|
||||
Reference in New Issue
Block a user