优化
This commit is contained in:
@@ -277,7 +277,10 @@ protected:
|
||||
const auto input = configuration.input;
|
||||
for (auto& count : workload->completed)
|
||||
count->store(0, std::memory_order_relaxed);
|
||||
for (const auto& plot : plots) plot->reset_diagnostics();
|
||||
for (const auto& plot : plots) {
|
||||
plot->reset_diagnostics();
|
||||
plot->request_taskflow_trace(1);
|
||||
}
|
||||
if (input == Input_Workload::drag || input == Input_Workload::mixed) {
|
||||
if (!submit_input_batch(
|
||||
input, 0, Event_Type::pointer_press)) {
|
||||
@@ -478,6 +481,29 @@ protected:
|
||||
? 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;
|
||||
double longest_sampled_busy_ms{};
|
||||
std::string longest_sampled_busy_node;
|
||||
std::string longest_sampled_busy_plot;
|
||||
for (std::size_t plot_index = 0; plot_index < plots.size(); ++plot_index) {
|
||||
const auto trace = plots[plot_index]->taskflow_trace();
|
||||
if (!trace.value("complete", false)) continue;
|
||||
for (const auto& frame : trace.at("frames"))
|
||||
for (const auto& execution : frame.at("executions")) {
|
||||
const auto busy = std::max(
|
||||
0.0, execution.value("duration_ms", 0.0) -
|
||||
execution.value("cooperative_wait_ms", 0.0));
|
||||
if (busy <= longest_sampled_busy_ms) continue;
|
||||
longest_sampled_busy_ms = busy;
|
||||
longest_sampled_busy_node = execution.value(
|
||||
"node_id", std::string{});
|
||||
longest_sampled_busy_plot =
|
||||
std::string{configuration.plot_ids[plot_index]};
|
||||
}
|
||||
}
|
||||
state.counters["sampled_longest_busy_ms"] = longest_sampled_busy_ms;
|
||||
if (!longest_sampled_busy_node.empty())
|
||||
state.SetLabel("busy=" + longest_sampled_busy_plot + ":" +
|
||||
longest_sampled_busy_node);
|
||||
state.counters["cooperative_yields"] = cooperative_waits;
|
||||
state.counters["cooperative_wait_ms"] =
|
||||
cooperative_wait_ns / 1'000'000.0;
|
||||
@@ -632,9 +658,13 @@ public:
|
||||
<< " input_requests/s=" << counter("input_request_rate")
|
||||
<< " worker_busy=" << counter("worker_busy_pct") << "%"
|
||||
<< " worker_cpu=" << counter("worker_cpu_pct") << "%"
|
||||
<< " sampled_busy_max="
|
||||
<< counter("sampled_longest_busy_ms") << " ms"
|
||||
<< " cooperative_yields=" << counter("cooperative_yields")
|
||||
<< " cooperative_wait=" << counter("cooperative_wait_ms")
|
||||
<< " ms\n";
|
||||
if (!report.report_label.empty())
|
||||
output << report.report_label << '\n';
|
||||
}
|
||||
output.flags(flags);
|
||||
output.precision(precision);
|
||||
|
||||
@@ -137,7 +137,7 @@ private:
|
||||
owner<DvzDrp2Runtime*> runtime{}; /* 本目标槽独占的 DRP2 Runtime。 */
|
||||
owner<DvzFramePlanEmitter*> emitter{}; /* 本目标槽独占的帧计划 emitter。 */
|
||||
};
|
||||
std::shared_ptr<Datoviz_Render_Context> render_context_{}; /* 本 Scene 独占 GPU 上下文的共享销毁闸门。 */
|
||||
std::shared_ptr<Datoviz_Render_Context> render_context_{}; /* 按 GPU 索引与验证模式共享的进程级上下文。 */
|
||||
std::uintptr_t command_pool_{}; /* 本 Scene 独占 Vulkan Command Pool。 */
|
||||
std::uintptr_t descriptor_pool_{}; /* 本 Scene 独占 Vulkan Descriptor Pool。 */
|
||||
std::array<Runtime_Slot, 3> runtime_slots_{}; /* 三个固定目标槽的 Runtime。 */
|
||||
|
||||
@@ -507,7 +507,7 @@ void Scene_Datoviz_State::quarantine(
|
||||
void Scene_Datoviz_State::abandon_resources() noexcept {
|
||||
quarantined_.store(true, std::memory_order_release);
|
||||
static_cast<void>(targets_.release());
|
||||
retain_quarantined_context(render_context_);
|
||||
render_context_.reset();
|
||||
}
|
||||
/* 必须在无在途帧时调用;按 Runtime -> Scene -> Vulkan 池 -> GPU 上下文逆序释放。 */
|
||||
void Scene_Datoviz_State::destroy() {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <numbers>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
@@ -126,10 +125,7 @@ struct Datoviz_Render_Context final :
|
||||
std::enable_shared_from_this<Datoviz_Render_Context> {
|
||||
public:
|
||||
[[nodiscard]] static std::shared_ptr<Datoviz_Render_Context> acquire(
|
||||
std::uint32_t gpu_index, bool validation_enabled) {
|
||||
return std::shared_ptr<Datoviz_Render_Context>(
|
||||
new Datoviz_Render_Context(gpu_index, validation_enabled));
|
||||
}
|
||||
std::uint32_t gpu_index, bool validation_enabled);
|
||||
~Datoviz_Render_Context() {
|
||||
if (gpu_context_ != nullptr) dvz_gpu_ctx_destroy(gpu_context_);
|
||||
}
|
||||
@@ -151,6 +147,10 @@ public:
|
||||
&configuration, &Datoviz_Render_Context::submit_immediate, this);
|
||||
}
|
||||
private:
|
||||
struct Registry_Entry;
|
||||
struct Registry;
|
||||
static Registry registry_;
|
||||
|
||||
struct Immediate_Submission final {
|
||||
explicit Immediate_Submission(VkDevice device_value) noexcept :
|
||||
device(device_value) {}
|
||||
@@ -263,20 +263,82 @@ private:
|
||||
if (submission_generation_.load(std::memory_order_acquire) != observed)
|
||||
arm_submission_drain();
|
||||
}
|
||||
owner<DvzGpuCtx*> gpu_context_{}; /* 当前 Scene 独占 GPU Device 与分配器。 */
|
||||
owner<DvzGpuCtx*> gpu_context_{}; /* 同 GPU 配置的 Scene 共享的进程级 Device 与分配器。 */
|
||||
moodycamel::ConcurrentQueue<std::function<void()>> submissions_{};
|
||||
std::atomic_uint64_t submission_generation_{};
|
||||
std::atomic_bool submission_drain_active_{};
|
||||
};
|
||||
void retain_quarantined_context(
|
||||
std::shared_ptr<Datoviz_Render_Context>& context) noexcept {
|
||||
if (!context) return;
|
||||
static moodycamel::ConcurrentQueue<
|
||||
std::shared_ptr<Datoviz_Render_Context>> quarantined;
|
||||
if (quarantined.enqueue(context))
|
||||
context.reset();
|
||||
else
|
||||
static_cast<void>(new(std::nothrow)
|
||||
std::shared_ptr<Datoviz_Render_Context>(std::move(context)));
|
||||
|
||||
/*
|
||||
* Sole process authority for a Datoviz GPU configuration. Entries and their
|
||||
* contexts are immutable after publication, so readers neither lock nor wait.
|
||||
*/
|
||||
struct Datoviz_Render_Context::Registry_Entry final {
|
||||
Registry_Entry(std::uint32_t gpu_index_value, bool validation_value,
|
||||
std::shared_ptr<Datoviz_Render_Context> context_value) noexcept :
|
||||
gpu_index(gpu_index_value), validation_enabled(validation_value),
|
||||
context(std::move(context_value)) {}
|
||||
|
||||
std::uint32_t gpu_index{};
|
||||
bool validation_enabled{};
|
||||
std::shared_ptr<Datoviz_Render_Context> context{};
|
||||
Registry_Entry* next{}; /* Nullable, non-owning link; Registry::head owns every published entry. */
|
||||
};
|
||||
|
||||
struct Datoviz_Render_Context::Registry final {
|
||||
Registry() = default;
|
||||
~Registry() {
|
||||
owner<Registry_Entry*> entry = head.exchange(
|
||||
nullptr, std::memory_order_acq_rel);
|
||||
while (entry != nullptr) {
|
||||
owner<Registry_Entry*> next = entry->next;
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
Registry(const Registry&) = delete;
|
||||
Registry& operator=(const Registry&) = delete;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Datoviz_Render_Context> acquire(
|
||||
std::uint32_t gpu_index, bool validation_enabled) {
|
||||
const auto find = [gpu_index, validation_enabled](
|
||||
Registry_Entry* first) noexcept -> Registry_Entry* {
|
||||
for (auto* entry = first; entry != nullptr; entry = entry->next) {
|
||||
if (entry->gpu_index == gpu_index &&
|
||||
entry->validation_enabled == validation_enabled)
|
||||
return entry;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
if (auto* entry = find(head.load(std::memory_order_acquire)))
|
||||
return entry->context;
|
||||
|
||||
auto context = std::shared_ptr<Datoviz_Render_Context>(
|
||||
new Datoviz_Render_Context(gpu_index, validation_enabled));
|
||||
auto candidate = std::make_unique<Registry_Entry>(
|
||||
gpu_index, validation_enabled, context);
|
||||
for (;;) {
|
||||
Registry_Entry* first = head.load(std::memory_order_acquire);
|
||||
if (auto* entry = find(first)) return entry->context;
|
||||
candidate->next = first;
|
||||
Registry_Entry* published = candidate.get();
|
||||
if (head.compare_exchange_weak(
|
||||
first, published, std::memory_order_release,
|
||||
std::memory_order_acquire)) {
|
||||
static_cast<void>(candidate.release());
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<owner<Registry_Entry*>> head{};
|
||||
};
|
||||
|
||||
inline Datoviz_Render_Context::Registry Datoviz_Render_Context::registry_{};
|
||||
|
||||
std::shared_ptr<Datoviz_Render_Context> Datoviz_Render_Context::acquire(
|
||||
std::uint32_t gpu_index, bool validation_enabled) {
|
||||
return registry_.acquire(gpu_index, validation_enabled);
|
||||
}
|
||||
} // namespace aethera::render_3d::detail
|
||||
|
||||
Reference in New Issue
Block a user