更新
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
# Aethera P0/P1 follow-up
|
||||
基线:142 提交 `46962440a22b50c9cbda929cdb549f564e429efa` 已叠加 `Aethera_observation_p0_p1_refactor_46962440_20260905_164237_CST.zip`。
|
||||
从本包目录执行:
|
||||
```text
|
||||
cmake -DAETHERA_ROOT=D:/path/to/Aethera -P apply.cmake
|
||||
```
|
||||
修复内容:
|
||||
- Immediate Vulkan completion 不再依赖 `timing != nullptr`,`timing` 只控制诊断返回值。
|
||||
- 恢复 frame-bound `gpu_submitted` 生命周期事件,与 `gpu_completed` 使用同一确定性 submission correlation。
|
||||
- 不恢复 Vulkan mirror、全局 Observation state 或额外 snapshot。
|
||||
本包不包含 Python 文件。
|
||||
@@ -1,37 +0,0 @@
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
def copy_tree(package: Path, repository: Path, name: str) -> None:
|
||||
source_root = package / name
|
||||
if not source_root.exists():
|
||||
return
|
||||
for source in source_root.rglob("*"):
|
||||
if not source.is_file():
|
||||
continue
|
||||
target = repository / source.relative_to(package)
|
||||
if source.resolve() == target.resolve():
|
||||
continue
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(source, target)
|
||||
def main() -> None:
|
||||
package = Path(__file__).resolve().parent
|
||||
repository = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
copy_tree(package, repository, "kernel")
|
||||
copy_tree(package, repository, "render_3D")
|
||||
for relative in [
|
||||
"kernel/kernel/include/observation/Frame_Attention.hpp",
|
||||
"kernel/kernel/include/observation/Tracy_Vulkan.hpp"
|
||||
]:
|
||||
target = repository / relative
|
||||
if target.exists():
|
||||
target.unlink()
|
||||
for script in [
|
||||
"apply_taskflow_observation_context.py",
|
||||
"apply_render_3D_observation.py",
|
||||
"apply_gpu_completion_observation.py",
|
||||
"apply_frame_policy_observation.py"
|
||||
]:
|
||||
subprocess.run([sys.executable, str(package / "patches" / script), str(repository)], check=True)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
get_filename_component(aethera_package_root "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
|
||||
set(aethera_package_items
|
||||
"kernel/src"
|
||||
"kernel/kernel"
|
||||
"kernel/main.cmake"
|
||||
"render_2D/render_2D"
|
||||
"render_2D/tests"
|
||||
|
||||
@@ -12,10 +12,6 @@ struct Frame_Context {
|
||||
const auto identity = make_identity(frame, generation);
|
||||
return Frame_Context{make_root_context(identity), frame, generation};
|
||||
}
|
||||
inline void trace_frame(const Frame_Context& value) noexcept {
|
||||
AETHERA_TRACE_FRAME("Aethera.Frame");
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const Frame_Context& value) {
|
||||
sink.field("event", "frame");
|
||||
@@ -23,4 +19,8 @@ void trace_serialize(Sink& sink, const Frame_Context& value) {
|
||||
sink.field("frame", value.frame);
|
||||
sink.field("generation", value.generation);
|
||||
}
|
||||
inline void trace_frame(const Frame_Context& value) noexcept {
|
||||
AETHERA_TRACE_FRAME("Aethera.Frame");
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
#pragma once
|
||||
#include "Frame_Timing.hpp"
|
||||
#include "GPU_Completion.hpp"
|
||||
#include "Frame_Policy.hpp"
|
||||
#include "Tracy.hpp"
|
||||
#include "Vulkan.hpp"
|
||||
#include <cstdint>
|
||||
namespace aethera::observation {
|
||||
struct Frame_Attention {
|
||||
Frame_Timing timing{};
|
||||
std::uint64_t gpu_render_ns{};
|
||||
std::uint64_t gpu_total_ns{};
|
||||
std::uint64_t uploaded_bytes{};
|
||||
std::uint64_t readback_bytes{};
|
||||
std::uint64_t upload_ns{};
|
||||
std::uint64_t upload_queue_wait_ns{};
|
||||
std::uint64_t upload_fence_wait_ns{};
|
||||
std::uint64_t shader_compile_ns{};
|
||||
std::uint64_t pipeline_create_ns{};
|
||||
std::uint32_t pipeline_create_count{};
|
||||
Vulkan_State vulkan{};
|
||||
GPU_Completion_State gpu_completion{};
|
||||
};
|
||||
struct Frame_Attention_Index {
|
||||
Frame_Context frame{};
|
||||
bool resource_activity{};
|
||||
bool upload_wait{};
|
||||
bool pipeline_build{};
|
||||
bool frame_overlap{};
|
||||
bool non_frame_submission{};
|
||||
bool completion_queue_gap{};
|
||||
bool completion_saturated{};
|
||||
};
|
||||
[[nodiscard]] inline Frame_Attention_Index make_frame_attention_index(const Frame_Attention& value) noexcept {
|
||||
return Frame_Attention_Index{
|
||||
value.timing.frame,
|
||||
value.uploaded_bytes != 0 || value.readback_bytes != 0 || value.upload_ns != 0 || value.shader_compile_ns != 0 || value.pipeline_create_ns != 0 || value.pipeline_create_count != 0,
|
||||
value.upload_queue_wait_ns != 0 || value.upload_fence_wait_ns != 0,
|
||||
value.shader_compile_ns != 0 || value.pipeline_create_ns != 0 || value.pipeline_create_count != 0,
|
||||
value.vulkan.frames_in_flight > 1,
|
||||
value.vulkan.pending_submissions > value.vulkan.frames_in_flight,
|
||||
value.gpu_completion.in_flight > value.gpu_completion.active,
|
||||
value.gpu_completion.capacity != 0 && value.gpu_completion.in_flight >= value.gpu_completion.capacity};
|
||||
}
|
||||
[[nodiscard]] inline bool has_frame_attention_index(const Frame_Attention_Index& value) noexcept {
|
||||
return value.resource_activity || value.upload_wait || value.pipeline_build || value.frame_overlap || value.non_frame_submission || value.completion_queue_gap || value.completion_saturated;
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const Frame_Attention& value) {
|
||||
sink.field("event", "frame_attention");
|
||||
trace_serialize(sink, value.timing.frame.context);
|
||||
sink.field("frame", value.timing.frame.frame);
|
||||
sink.field("generation", value.timing.frame.generation);
|
||||
sink.field("render_latency_ns", value.timing.render_latency_ns);
|
||||
sink.field("graph_start_latency_ns", value.timing.graph_start_latency_ns);
|
||||
sink.field("graph_to_submit_ns", value.timing.graph_to_submit_ns);
|
||||
sink.field("backend_prepare_ns", value.timing.backend_prepare_ns);
|
||||
sink.field("submit_path_ns", value.timing.submit_path_ns);
|
||||
sink.field("completion_tail_ns", value.timing.completion_tail_ns);
|
||||
sink.field("gpu_render_ns", value.gpu_render_ns);
|
||||
sink.field("gpu_total_ns", value.gpu_total_ns);
|
||||
sink.field("uploaded_bytes", value.uploaded_bytes);
|
||||
sink.field("readback_bytes", value.readback_bytes);
|
||||
sink.field("upload_ns", value.upload_ns);
|
||||
sink.field("upload_queue_wait_ns", value.upload_queue_wait_ns);
|
||||
sink.field("upload_fence_wait_ns", value.upload_fence_wait_ns);
|
||||
sink.field("shader_compile_ns", value.shader_compile_ns);
|
||||
sink.field("pipeline_create_ns", value.pipeline_create_ns);
|
||||
sink.field("pipeline_create_count", value.pipeline_create_count);
|
||||
sink.field("vulkan_pending", value.vulkan.pending_submissions);
|
||||
sink.field("frames_in_flight", value.vulkan.frames_in_flight);
|
||||
sink.field("completion_in_flight", value.gpu_completion.in_flight);
|
||||
sink.field("completion_active", value.gpu_completion.active);
|
||||
sink.field("completion_capacity", value.gpu_completion.capacity);
|
||||
sink.field("completion_capacity_exhausted", value.gpu_completion.capacity_exhausted_count);
|
||||
sink.field("completion_errors", value.gpu_completion.error_count);
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const Frame_Attention_Index& value) {
|
||||
sink.field("event", "frame_attention_index");
|
||||
trace_serialize(sink, value.frame.context);
|
||||
sink.field("frame", value.frame.frame);
|
||||
sink.field("generation", value.frame.generation);
|
||||
if (value.resource_activity) sink.field("resource_activity", true);
|
||||
if (value.upload_wait) sink.field("upload_wait", true);
|
||||
if (value.pipeline_build) sink.field("pipeline_build", true);
|
||||
if (value.frame_overlap) sink.field("frame_overlap", true);
|
||||
if (value.non_frame_submission) sink.field("non_frame_submission", true);
|
||||
if (value.completion_queue_gap) sink.field("completion_queue_gap", true);
|
||||
if (value.completion_saturated) sink.field("completion_saturated", true);
|
||||
}
|
||||
inline void trace_frame_attention(const Frame_Attention& value) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
if (!tracy_connected()) return;
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
trace_frame_policy_context(value.timing.frame);
|
||||
const auto index = make_frame_attention_index(value);
|
||||
if (has_frame_attention_index(index)) AETHERA_TRACE_MESSAGE_TAGS(index);
|
||||
#else
|
||||
static_cast<void>(value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,6 @@ struct Frame_Policy_State_View {
|
||||
const State& state;
|
||||
Frame_Policy_Slots slots{};
|
||||
};
|
||||
template <class State>
|
||||
inline void trace_frame_policy_state(std::uintptr_t policy, const State& state, Frame_Policy_Slots slots) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_MESSAGE_TAGS(Frame_Policy_State_View<State>{policy, state, slots});
|
||||
#else
|
||||
static_cast<void>(policy);
|
||||
static_cast<void>(state);
|
||||
static_cast<void>(slots);
|
||||
#endif
|
||||
}
|
||||
template <class Sink, class State>
|
||||
void trace_serialize(Sink& sink, const Frame_Policy_State_View<State>& value) {
|
||||
sink.field("event", "frame_policy_state");
|
||||
@@ -55,4 +45,14 @@ void trace_serialize(Sink& sink, const Frame_Policy_State_View<State>& value) {
|
||||
sink.field("end_to_end_stddev_ns", value.state.end_to_end_time_ns.standard_deviation);
|
||||
}
|
||||
}
|
||||
template <class State>
|
||||
inline void trace_frame_policy_state(std::uintptr_t policy, const State& state, Frame_Policy_Slots slots) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_MESSAGE_TAGS(Frame_Policy_State_View<State>{policy, state, slots});
|
||||
#else
|
||||
static_cast<void>(policy);
|
||||
static_cast<void>(state);
|
||||
static_cast<void>(slots);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,16 @@ struct GPU_Completion_Metrics {
|
||||
std::int32_t error{};
|
||||
std::int32_t backend_result{};
|
||||
};
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const GPU_Completion_Metrics& value) {
|
||||
sink.field("event", value.event);
|
||||
sink.field("in_flight", value.in_flight);
|
||||
sink.field("active", value.active);
|
||||
sink.field("capacity", value.capacity);
|
||||
if (value.wait_ns != 0) sink.field("wait_ns", value.wait_ns);
|
||||
if (value.error != 0) sink.field("error", value.error);
|
||||
if (value.backend_result != 0) sink.field("backend_result", value.backend_result);
|
||||
}
|
||||
inline void trace_gpu_completion_admitted(std::size_t in_flight) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_PLOT_I("Aethera.GPUCompletion.InFlight", in_flight);
|
||||
@@ -71,14 +81,4 @@ inline void trace_gpu_completion_completed(std::size_t in_flight, std::size_t ac
|
||||
static_cast<void>(backend_result);
|
||||
#endif
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const GPU_Completion_Metrics& value) {
|
||||
sink.field("event", value.event);
|
||||
sink.field("in_flight", value.in_flight);
|
||||
sink.field("active", value.active);
|
||||
sink.field("capacity", value.capacity);
|
||||
if (value.wait_ns != 0) sink.field("wait_ns", value.wait_ns);
|
||||
if (value.error != 0) sink.field("error", value.error);
|
||||
if (value.backend_result != 0) sink.field("backend_result", value.backend_result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,20 +32,6 @@ struct Frame_Resource_Metrics {
|
||||
[[nodiscard]] constexpr bool has_resource_activity(const Frame_Resource_Metrics& value) noexcept {
|
||||
return value.uploaded_bytes != 0 || value.readback_bytes != 0 || value.buffer_create_ns != 0 || value.texture_create_ns != 0 || value.shader_compile_ns != 0 || value.pipeline_create_ns != 0 || value.upload_ns != 0 || value.staging_allocate_ns != 0 || value.host_copy_ns != 0 || value.submit_queue_wait_ns != 0 || value.fence_wait_ns != 0 || value.transfer_ns != 0 || value.pipeline_create_count != 0;
|
||||
}
|
||||
inline void trace_frame_resources(const Frame_Resource_Metrics& value) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadedBytes", value.uploaded_bytes);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.ReadbackBytes", value.readback_bytes);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadNs", value.upload_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadQueueWaitNs", value.submit_queue_wait_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadFenceWaitNs", value.fence_wait_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.ShaderCompileNs", value.shader_compile_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.PipelineCreateNs", value.pipeline_create_ns);
|
||||
if (has_resource_activity(value)) AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
#else
|
||||
static_cast<void>(value);
|
||||
#endif
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const Frame_Resource_Metrics& value) {
|
||||
sink.field("event", "frame_resources");
|
||||
@@ -66,4 +52,18 @@ void trace_serialize(Sink& sink, const Frame_Resource_Metrics& value) {
|
||||
sink.field("transfer_ns", value.transfer_ns);
|
||||
sink.field("pipeline_create_count", value.pipeline_create_count);
|
||||
}
|
||||
inline void trace_frame_resources(const Frame_Resource_Metrics& value) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadedBytes", value.uploaded_bytes);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.ReadbackBytes", value.readback_bytes);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadNs", value.upload_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadQueueWaitNs", value.submit_queue_wait_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.UploadFenceWaitNs", value.fence_wait_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.ShaderCompileNs", value.shader_compile_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Resource.PipelineCreateNs", value.pipeline_create_ns);
|
||||
if (has_resource_activity(value)) AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
#else
|
||||
static_cast<void>(value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <utility>
|
||||
namespace aethera::observation {
|
||||
namespace detail {
|
||||
void trace_serialize() = delete;
|
||||
template <class Sink, class T>
|
||||
concept Custom_Serializable = requires(Sink& sink, const T& value) { trace_serialize(sink, value); };
|
||||
template <class Sink, class T>
|
||||
|
||||
@@ -125,7 +125,7 @@ struct Tracy_Task_Zone {
|
||||
inline void trace_tracy_text_truncation(const char* channel, const Tracy_Text_Sink& truncated) noexcept {
|
||||
Tracy_Text_Sink sink;
|
||||
serialize(sink, Tracy_Text_Truncation{channel, truncated.required_size(), truncated.capacity()});
|
||||
TracyCMessage(sink.data(), sink.size())
|
||||
TracyCMessage(sink.data(), sink.size());
|
||||
}
|
||||
inline void set_tracy_thread_name(const char* name) noexcept {
|
||||
TracyCSetThreadName(name)
|
||||
@@ -161,7 +161,7 @@ void emit_tracy_message(const Tags& tags) {
|
||||
if (!trace_capture_active()) return;
|
||||
Tracy_Text_Sink sink;
|
||||
serialize(sink, tags);
|
||||
if (!sink.empty()) TracyCMessage(sink.data(), sink.size())
|
||||
if (!sink.empty()) TracyCMessage(sink.data(), sink.size());
|
||||
if (sink.truncated()) trace_tracy_text_truncation("message", sink);
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include "Tracy.hpp"
|
||||
#ifdef TRACY_ENABLE
|
||||
#include <tracy/TracyVulkan.hpp>
|
||||
#define AETHERA_TRACE_VULKAN_CONTEXT(...) TracyVkContext(__VA_ARGS__)
|
||||
#define AETHERA_TRACE_VULKAN_DESTROY(context) TracyVkDestroy(context)
|
||||
#define AETHERA_TRACE_VULKAN_CONTEXT_NAME(context, name, size) TracyVkContextName(context, name, size)
|
||||
#define AETHERA_TRACE_VULKAN_ZONE(context, command_buffer, name) TracyVkZone(context, command_buffer, name)
|
||||
#define AETHERA_TRACE_VULKAN_ZONE_TAGS(context, command_buffer, name, ...) AETHERA_TRACE_MESSAGE_TAGS(__VA_ARGS__); TracyVkZone(context, command_buffer, name)
|
||||
#define AETHERA_TRACE_VULKAN_COLLECT(context, command_buffer) TracyVkCollect(context, command_buffer)
|
||||
#define AETHERA_TRACE_VULKAN_COLLECT_HOST(context) TracyVkCollectHost(context)
|
||||
#else
|
||||
#define AETHERA_TRACE_VULKAN_CONTEXT(...) nullptr
|
||||
#define AETHERA_TRACE_VULKAN_DESTROY(context)
|
||||
#define AETHERA_TRACE_VULKAN_CONTEXT_NAME(context, name, size)
|
||||
#define AETHERA_TRACE_VULKAN_ZONE(context, command_buffer, name)
|
||||
#define AETHERA_TRACE_VULKAN_ZONE_TAGS(context, command_buffer, name, ...)
|
||||
#define AETHERA_TRACE_VULKAN_COLLECT(context, command_buffer)
|
||||
#define AETHERA_TRACE_VULKAN_COLLECT_HOST(context)
|
||||
#endif
|
||||
@@ -55,38 +55,6 @@ decltype(auto) trace_vulkan_submit(Submit&& submit) {
|
||||
AETHERA_TRACE_ZONE("Vulkan.Submit");
|
||||
return std::invoke(std::forward<Submit>(submit));
|
||||
}
|
||||
inline void trace_vulkan_submitted(const Vulkan_Submission_Context& submission) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_MESSAGE_TAGS(submission);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
#endif
|
||||
}
|
||||
inline void trace_vulkan_completed(const Vulkan_Submission_Context& submission, std::uint64_t latency_ns) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto value = make_vulkan_completion_context(submission, latency_ns);
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
if (submission.frame_bound) AETHERA_TRACE_PLOT_I("Aethera.Vulkan.FrameSubmitToCompleteNs", latency_ns);
|
||||
else AETHERA_TRACE_PLOT_I("Aethera.Vulkan.ImmediateSubmitToCompleteNs", latency_ns);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
static_cast<void>(latency_ns);
|
||||
#endif
|
||||
}
|
||||
inline void trace_vulkan_gpu_timing(const Vulkan_Submission_Context& submission, std::uint64_t render_ns, std::uint64_t transition_ns, std::uint64_t copy_ns, std::uint64_t total_ns) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto value = make_vulkan_gpu_timing_context(submission, render_ns, transition_ns, copy_ns, total_ns);
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Vulkan.GPU.RenderNs", render_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Vulkan.GPU.TotalNs", total_ns);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
static_cast<void>(render_ns);
|
||||
static_cast<void>(transition_ns);
|
||||
static_cast<void>(copy_ns);
|
||||
static_cast<void>(total_ns);
|
||||
#endif
|
||||
}
|
||||
template <class Sink>
|
||||
void trace_serialize(Sink& sink, const Vulkan_Submission_Context& value) {
|
||||
sink.field("event", "vulkan_submit");
|
||||
@@ -122,4 +90,36 @@ void trace_serialize(Sink& sink, const Vulkan_Completion_Context& value) {
|
||||
if (value.queue != 0) sink.field("queue", value.queue);
|
||||
sink.field("latency_ns", value.latency_ns);
|
||||
}
|
||||
inline void trace_vulkan_submitted(const Vulkan_Submission_Context& submission) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
AETHERA_TRACE_MESSAGE_TAGS(submission);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
#endif
|
||||
}
|
||||
inline void trace_vulkan_completed(const Vulkan_Submission_Context& submission, std::uint64_t latency_ns) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto value = make_vulkan_completion_context(submission, latency_ns);
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
if (submission.frame_bound) AETHERA_TRACE_PLOT_I("Aethera.Vulkan.FrameSubmitToCompleteNs", latency_ns);
|
||||
else AETHERA_TRACE_PLOT_I("Aethera.Vulkan.ImmediateSubmitToCompleteNs", latency_ns);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
static_cast<void>(latency_ns);
|
||||
#endif
|
||||
}
|
||||
inline void trace_vulkan_gpu_timing(const Vulkan_Submission_Context& submission, std::uint64_t render_ns, std::uint64_t transition_ns, std::uint64_t copy_ns, std::uint64_t total_ns) noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto value = make_vulkan_gpu_timing_context(submission, render_ns, transition_ns, copy_ns, total_ns);
|
||||
AETHERA_TRACE_MESSAGE_TAGS(value);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Vulkan.GPU.RenderNs", render_ns);
|
||||
AETHERA_TRACE_PLOT_I("Aethera.Vulkan.GPU.TotalNs", total_ns);
|
||||
#else
|
||||
static_cast<void>(submission);
|
||||
static_cast<void>(render_ns);
|
||||
static_cast<void>(transition_ns);
|
||||
static_cast<void>(copy_ns);
|
||||
static_cast<void>(total_ns);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Throttled_Latest_Only.hpp"
|
||||
#include "Error_handling_specification/Failure_Policy.hpp"
|
||||
#include "Trace_Adapter.hpp"
|
||||
#include <algorithm>
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
@@ -385,6 +386,9 @@ void Throttled_Latest_only::Private::finish_stop_if_ready() {
|
||||
}
|
||||
}
|
||||
void Throttled_Latest_only::Private::publish_state() {
|
||||
#ifdef TRACY_ENABLE
|
||||
frame_policy_trace::published(this, *concurrent<State_Tag>().internal.use(), frames);
|
||||
#endif
|
||||
concurrent<State_Tag>().internal.advance();
|
||||
}
|
||||
bool Throttled_Latest_only::Private::destructible() const noexcept {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Task_Runtime.hpp"
|
||||
#include "detail/Taskflow_Execution.ipp"
|
||||
#include "observation/Tracy.hpp"
|
||||
#include "Trace_Adapter.hpp"
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
@@ -71,28 +71,15 @@ const tf::Worker& task_worker(const tf::WorkerView& worker) noexcept {
|
||||
struct Task_Observer final : tf::ObserverInterface {
|
||||
#ifdef TRACY_ENABLE
|
||||
static constexpr std::size_t Tracy_Zone_Depth = 128;
|
||||
struct Frame_Task_Trace_Tags {
|
||||
std::uint64_t frame{};
|
||||
std::uint64_t generation{};
|
||||
std::string_view graph{};
|
||||
std::size_t worker{};
|
||||
std::uint64_t task{};
|
||||
};
|
||||
struct Tracy_Worker_State {
|
||||
std::array<observation::Tracy_Task_Zone, Tracy_Zone_Depth> zones{};
|
||||
std::array<task_flow_trace::Task_Zone, Tracy_Zone_Depth> zones{};
|
||||
std::size_t depth{};
|
||||
std::size_t ignored_depth{};
|
||||
bool named{};
|
||||
};
|
||||
void name_worker(Tracy_Worker_State& state, std::size_t worker_id) noexcept {
|
||||
if (state.named) return;
|
||||
constexpr std::string_view Prefix{"Aethera.Taskflow."};
|
||||
std::array<char, 64> name{};
|
||||
std::memcpy(name.data(), Prefix.data(), Prefix.size());
|
||||
const auto [end, error] = std::to_chars(name.data() + Prefix.size(), name.data() + name.size() - 1, worker_id);
|
||||
if (error != std::errc{}) return;
|
||||
*end = '\0';
|
||||
observation::set_tracy_thread_name(name.data());
|
||||
task_flow_trace::name_worker(worker_id);
|
||||
state.named = true;
|
||||
}
|
||||
void trace_entry(const tf::Worker& worker, const tf::TaskView& task, std::uint64_t native_id, const detail::Taskflow_Observation_Execution* execution) noexcept {
|
||||
@@ -102,7 +89,7 @@ struct Task_Observer final : tf::ObserverInterface {
|
||||
++state.ignored_depth;
|
||||
return;
|
||||
}
|
||||
if (!observation::tracy_connected()) {
|
||||
if (!task_flow_trace::capture_active()) {
|
||||
if (state.depth != 0) state.ignored_depth = 1;
|
||||
return;
|
||||
}
|
||||
@@ -112,12 +99,12 @@ struct Task_Observer final : tf::ObserverInterface {
|
||||
}
|
||||
const std::string_view name{task.name()};
|
||||
auto& zone = state.zones[state.depth++];
|
||||
zone = observation::begin_tracy_task_zone(name, native_id);
|
||||
zone = task_flow_trace::begin_task(name, native_id);
|
||||
if (execution == nullptr) return;
|
||||
std::string_view graph;
|
||||
const auto* context = execution->trace_context(graph);
|
||||
if (context == nullptr) return;
|
||||
observation::attach_tracy_task_tags(zone, Frame_Task_Trace_Tags{context->frame, context->generation, graph, worker.id(), native_id});
|
||||
task_flow_trace::attach_frame(zone, *context);
|
||||
}
|
||||
void trace_exit(const tf::Worker& worker) noexcept {
|
||||
auto& state = tracy_worker_states[worker.id()];
|
||||
@@ -126,7 +113,7 @@ struct Task_Observer final : tf::ObserverInterface {
|
||||
return;
|
||||
}
|
||||
if (state.depth == 0) return;
|
||||
observation::end_tracy_task_zone(state.zones[--state.depth]);
|
||||
task_flow_trace::end_task(state.zones[--state.depth]);
|
||||
}
|
||||
std::vector<Tracy_Worker_State> tracy_worker_states;
|
||||
#endif
|
||||
@@ -223,7 +210,7 @@ public:
|
||||
return Run_Taskflow_Result::observation_unavailable;
|
||||
}
|
||||
#ifdef TRACY_ENABLE
|
||||
if (trace_context && observation::tracy_connected()) observation_execution->set_trace_context(*trace_context, graph_execution->native_taskflow().name());
|
||||
if (trace_context && task_flow_trace::capture_active()) observation_execution->set_trace_context(*trace_context, graph_execution->native_taskflow().name());
|
||||
#else
|
||||
(void)trace_context;
|
||||
#endif
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(old)
|
||||
if count == 0 and not new and os.environ.get("AETHERA_TEXT_GUARDRAIL_UPGRADE") == "1":
|
||||
return
|
||||
if count != 1:
|
||||
raise RuntimeError(f"expected exactly one match in {path}: {old[:80]!r}")
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
source = root / "kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp"
|
||||
replace_once(source, '#include "Error_handling_specification/Failure_Policy.hpp"\n', '#include "Error_handling_specification/Failure_Policy.hpp"\n#include "Trace_Adapter.hpp"\n')
|
||||
replace_once(source, 'void Throttled_Latest_only::Private::publish_state() {\n concurrent<State_Tag>().internal.advance();\n}\n', '''void Throttled_Latest_only::Private::publish_state() {
|
||||
#ifdef TRACY_ENABLE
|
||||
frame_policy_trace::published(this, *concurrent<State_Tag>().internal.use(), frames);
|
||||
#endif
|
||||
concurrent<State_Tag>().internal.advance();
|
||||
}
|
||||
''')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,44 +0,0 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(old)
|
||||
if count == 0 and not new and os.environ.get("AETHERA_TEXT_GUARDRAIL_UPGRADE") == "1":
|
||||
return
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one match, found {count}")
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
source = root / "render_3D/render_3D/detail/Gpu_Completion_Service.cpp"
|
||||
replace_once(source, '#include "Exception.hpp"\n', '#include "Exception.hpp"\n#include "Trace_Adapter.hpp"\n')
|
||||
replace_once(source, ' while (count < Private::capacity && !d->in_flight.compare_exchange_weak(count, count + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) {}\n if (count >= Private::capacity) return {{}, Admission_Result::capacity_exhausted};\n', ' while (count < Private::capacity && !d->in_flight.compare_exchange_weak(count, count + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) {}\n if (count >= Private::capacity) {\n aethera::trace_adapter::gpu_completion_capacity_exhausted(count, Private::capacity);\n return {{}, Admission_Result::capacity_exhausted};\n }\n')
|
||||
replace_once(source, ' if (!d->incoming.enqueue(pending)) {\n d->in_flight.fetch_sub(1, std::memory_order_release);\n throw std::bad_alloc{};\n }\n d->request_poll(std::chrono::nanoseconds{1});\n', ' if (!d->incoming.enqueue(pending)) {\n d->in_flight.fetch_sub(1, std::memory_order_release);\n throw std::bad_alloc{};\n }\n aethera::trace_adapter::gpu_completion_admitted(count + 1);\n d->request_poll(std::chrono::nanoseconds{1});\n')
|
||||
replace_once(source, 'void Gpu_Completion_Service::Private::poll() noexcept {\n std::shared_ptr<Gpu_Completion_Pending_Fence> incoming_value;\n while (incoming.try_dequeue(incoming_value)) {\n active.push_back(std::move(incoming_value));\n incoming_value.reset();\n }\n', 'void Gpu_Completion_Service::Private::poll() noexcept {\n#ifdef TRACY_ENABLE\n const auto trace_active_before = active.size();\n#endif\n std::shared_ptr<Gpu_Completion_Pending_Fence> incoming_value;\n while (incoming.try_dequeue(incoming_value)) {\n active.push_back(std::move(incoming_value));\n incoming_value.reset();\n }\n#ifdef TRACY_ENABLE\n if (active.size() != trace_active_before) aethera::trace_adapter::gpu_completion_active(in_flight.load(std::memory_order_relaxed), active.size());\n#endif\n')
|
||||
replace_once(source, ' if (status == Gpu_Completion_Pending_Fence::Status::canceled) {\n iterator = active.erase(iterator);\n in_flight.fetch_sub(1, std::memory_order_release);\n continue;\n }\n', ''' if (status == Gpu_Completion_Pending_Fence::Status::canceled) {
|
||||
iterator = active.erase(iterator);
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;
|
||||
aethera::trace_adapter::gpu_completion_canceled(remaining, active.size(), capacity);
|
||||
#else
|
||||
in_flight.fetch_sub(1, std::memory_order_release);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
''')
|
||||
replace_once(source, ' Result result{error, static_cast<std::int32_t>(vulkan_result), pending->observe ? elapsed_nanoseconds(pending->watched_at) : 0};\n iterator = active.erase(iterator);\n in_flight.fetch_sub(1, std::memory_order_release);\n try {\n', '''#ifdef TRACY_ENABLE
|
||||
const auto trace_watched_at = pending->watched_at;
|
||||
#endif
|
||||
Result result{error, static_cast<std::int32_t>(vulkan_result), pending->observe ? elapsed_nanoseconds(pending->watched_at) : 0};
|
||||
iterator = active.erase(iterator);
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;
|
||||
aethera::trace_adapter::gpu_completion_completed(remaining, active.size(), capacity, trace_watched_at, static_cast<std::int32_t>(error), static_cast<std::int32_t>(vulkan_result));
|
||||
#else
|
||||
in_flight.fetch_sub(1, std::memory_order_release);
|
||||
#endif
|
||||
try {
|
||||
''')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,45 +0,0 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(old)
|
||||
if count == 0 and not new and os.environ.get("AETHERA_TEXT_GUARDRAIL_UPGRADE") == "1":
|
||||
return
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one match, found {count}")
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
frame_header = root / "render_3D/render_3D/base/Frame_3D.hpp"
|
||||
frame = root / "render_3D/render_3D/base/Frame_3D.cpp"
|
||||
model = root / "render_3D/render_3D/scene/Render_Scene_3D_Model.ipp"
|
||||
common = root / "render_3D/render_3D/scene/detail/Datoviz_Scene_Common.ipp"
|
||||
pipeline = root / "render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp"
|
||||
scene = root / "render_3D/render_3D/scene/Render_Scene_3D.ipp"
|
||||
replace_once(frame_header, '#include <task_flow/export/Taskflow_Observation.hpp>\n', '#include <task_flow/export/export.h>\n')
|
||||
replace_once(frame_header, ' static void assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation);\n [[nodiscard]] static Taskflow_Observation taskflow_observation(Frame_3D* frame);\n', ' static void assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation);\n static Run_Taskflow_Result run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Compose_Facade>& graph, Taskflow_Completion completion);\n [[nodiscard]] static Taskflow_Observation taskflow_observation(Frame_3D* frame);\n')
|
||||
replace_once(frame, '#include "Frame_3D.hpp"\n', '#include "Frame_3D.hpp"\n#include "../detail/Trace_Adapter.hpp"\n')
|
||||
replace_once(frame, 'void Frame_3D::mark(Frame_Trace_Marker marker) noexcept {\n const auto index = static_cast<std::size_t>(marker);\n if (index >= marker_count) return;\n const auto elapsed = std::chrono::steady_clock::now() - d->created_at;\n const auto elapsed_ns = static_cast<std::uint64_t>(std::max<std::int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()));\n std::uint64_t expected{};\n d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed);\n}\n', 'void Frame_3D::mark(Frame_Trace_Marker marker) noexcept {\n const auto index = static_cast<std::size_t>(marker);\n if (index >= marker_count) return;\n const auto elapsed = std::chrono::steady_clock::now() - d->created_at;\n const auto elapsed_ns = static_cast<std::uint64_t>(std::max<std::int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()));\n std::uint64_t expected{};\n if (!d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed)) return;\n aethera::trace_adapter::frame_marker(d->identity, d->markers, marker);\n}\n')
|
||||
replace_once(frame, 'void detail::Frame_3D_Access::assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation) {\n if (!frame) throw std::invalid_argument("Frame_3D diagnostic target is null");\n frame->d->datoviz_observation.emplace(std::move(observation));\n}\n', 'void detail::Frame_3D_Access::assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation) {\n if (!frame) throw std::invalid_argument("Frame_3D diagnostic target is null");\n aethera::trace_adapter::datoviz_observation(frame->d->identity, observation);\n frame->d->datoviz_observation.emplace(std::move(observation));\n}\n')
|
||||
replace_once(frame, 'Taskflow_Observation detail::Frame_3D_Access::taskflow_observation(Frame_3D* frame) {\n if (!frame || !frame->d->taskflow_observation) throw std::logic_error("Frame_3D has no Taskflow observation request");\n return *frame->d->taskflow_observation;\n}\n', 'Run_Taskflow_Result detail::Frame_3D_Access::run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Compose_Facade>& graph, Taskflow_Completion completion) {\n if (frame->d->taskflow_observation) return aethera::trace_adapter::run_taskflow_observed(frame->d->identity, graph, std::move(completion), taskflow_observation(frame));\n return aethera::trace_adapter::run_taskflow(frame->d->identity, graph, std::move(completion));\n}\nTaskflow_Observation detail::Frame_3D_Access::taskflow_observation(Frame_3D* frame) {\n if (!frame || !frame->d->taskflow_observation) throw std::logic_error("Frame_3D has no Taskflow observation request");\n return *frame->d->taskflow_observation;\n}\n')
|
||||
replace_once(model, '#include "observation/Tracy.hpp"\n', '')
|
||||
for line in [
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.Submit.Callback", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.GPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.Frame.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_FRAME("Render3D");\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.CPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});\n'
|
||||
]:
|
||||
replace_once(model, line, '')
|
||||
replace_once(model, ' const auto submitted = graph->run([execution](std::exception_ptr runtime_failure) mutable {\n complete_execution(std::move(execution), std::move(runtime_failure));\n } AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(execution->frame->identity().sequence, execution->frame->identity().generation));\n', ' const auto submitted = detail::Frame_3D_Access::run_taskflow(execution->frame, graph, [execution](std::exception_ptr runtime_failure) mutable {\n complete_execution(std::move(execution), std::move(runtime_failure));\n });\n')
|
||||
replace_once(model, ' const auto submitted = frame->taskflow_trace_requested() ? graph->run_observed(std::move(completed), detail::Frame_3D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : graph->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation));\n', ' const auto submitted = detail::Frame_3D_Access::run_taskflow(frame, graph, std::move(completed));\n')
|
||||
replace_once(common, '#include <volk.h>\n', '#include <volk.h>\n#include "../../detail/Trace_Adapter.hpp"\n')
|
||||
replace_once(common, ' submission->queue_started_ns = trace_now_ns();\n const VkResult result = vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);\n submission->queue_finished_ns = trace_now_ns();\n submission->submission_result.store(result, std::memory_order_relaxed);\n', ' submission->queue_started_ns = trace_now_ns();\n const VkResult result = aethera::trace_adapter::vulkan_submit([&] {\n return vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);\n });\n submission->queue_finished_ns = trace_now_ns();\n submission->submission_result.store(result, std::memory_order_relaxed);\n')
|
||||
replace_once(common, ' const auto completion_observed = trace_now_ns();\n timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished\n', ' const auto completion_observed = trace_now_ns();\n if (static_cast<VkResult>(submission->submission_result.load(std::memory_order_relaxed)) == VK_SUCCESS) aethera::trace_adapter::immediate_vulkan_completed(reinterpret_cast<std::uintptr_t>(submission.get()), queue_finished != 0 && completion_observed > queue_finished ? completion_observed - queue_finished : 0);\n timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished\n')
|
||||
replace_once(pipeline, ' target(pending).submit();\n', ' aethera::trace_adapter::vulkan_submit([&] {\n target(pending).submit();\n });\n')
|
||||
replace_once(scene, '#include <mutex>\n', '#include <mutex>\n#include "synchronization/Mutex.hpp"\n')
|
||||
replace_once(scene, ' mutable std::mutex target_mutex_{}; /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */\n', ' mutable AETHERA_MUTEX(target_mutex_, "Render3D.Target"); /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */\n')
|
||||
replace_once(pipeline, ' std::mutex& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */\n', ' decltype(target_mutex_)& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */\n')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,41 +0,0 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(old)
|
||||
if count == 0 and not new and os.environ.get("AETHERA_TEXT_GUARDRAIL_UPGRADE") == "1":
|
||||
return
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one match, found {count}")
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
runtime = root / "kernel/kernel/module/task_flow/src/Task_Runtime.cpp"
|
||||
replace_once(runtime, '#include "observation/Tracy.hpp"\n', '#include "Trace_Adapter.hpp"\n')
|
||||
replace_once(runtime, ' struct Frame_Task_Trace_Tags {\n std::uint64_t frame{};\n std::uint64_t generation{};\n std::string_view graph{};\n std::size_t worker{};\n std::uint64_t task{};\n };\n', '')
|
||||
replace_once(runtime, ' std::array<observation::Tracy_Task_Zone, Tracy_Zone_Depth> zones{};\n', ' std::array<task_flow_trace::Task_Zone, Tracy_Zone_Depth> zones{};\n')
|
||||
replace_once(runtime, ''' void name_worker(Tracy_Worker_State& state, std::size_t worker_id) noexcept {
|
||||
if (state.named) return;
|
||||
constexpr std::string_view Prefix{"Aethera.Taskflow."};
|
||||
std::array<char, 64> name{};
|
||||
std::memcpy(name.data(), Prefix.data(), Prefix.size());
|
||||
const auto [end, error] = std::to_chars(name.data() + Prefix.size(), name.data() + name.size() - 1, worker_id);
|
||||
if (error != std::errc{}) return;
|
||||
*end = '\0';
|
||||
observation::set_tracy_thread_name(name.data());
|
||||
state.named = true;
|
||||
}
|
||||
''', ''' void name_worker(Tracy_Worker_State& state, std::size_t worker_id) noexcept {
|
||||
if (state.named) return;
|
||||
task_flow_trace::name_worker(worker_id);
|
||||
state.named = true;
|
||||
}
|
||||
''')
|
||||
replace_once(runtime, ' if (!observation::tracy_connected()) {\n', ' if (!task_flow_trace::capture_active()) {\n')
|
||||
replace_once(runtime, ' zone = observation::begin_tracy_task_zone(name, native_id);\n', ' zone = task_flow_trace::begin_task(name, native_id);\n')
|
||||
replace_once(runtime, ' observation::attach_tracy_task_tags(zone, Frame_Task_Trace_Tags{context->frame, context->generation, graph, worker.id(), native_id});\n', ' task_flow_trace::attach_frame(zone, *context);\n')
|
||||
replace_once(runtime, ' observation::end_tracy_task_zone(state.zones[--state.depth]);\n', ' task_flow_trace::end_task(state.zones[--state.depth]);\n')
|
||||
replace_once(runtime, ' if (trace_context && observation::tracy_connected()) observation_execution->set_trace_context(*trace_context, graph_execution->native_taskflow().name());\n', ' if (trace_context && task_flow_trace::capture_active()) observation_execution->set_trace_context(*trace_context, graph_execution->native_taskflow().name());\n')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,37 +0,0 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
if not new:
|
||||
return
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(new)
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one current-state match, found {count}")
|
||||
path.write_text(text.replace(new, old, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
source = root / "kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp"
|
||||
replace_once(source, '#include "Error_handling_specification/Failure_Policy.hpp"\n', '#include "Error_handling_specification/Failure_Policy.hpp"\n#include "observation/Frame_Policy.hpp"\n')
|
||||
replace_once(source, 'void Throttled_Latest_only::Private::publish_state() {\n concurrent<State_Tag>().internal.advance();\n}\n', '''void Throttled_Latest_only::Private::publish_state() {
|
||||
const auto& state = *concurrent<State_Tag>().internal.use();
|
||||
std::size_t idle{};
|
||||
std::size_t rendering{};
|
||||
std::size_t ready{};
|
||||
std::size_t sending{};
|
||||
for (const auto& slot : frames) {
|
||||
switch (slot.phase) {
|
||||
case Frame_Phase::idle: ++idle; break;
|
||||
case Frame_Phase::rendering: ++rendering; break;
|
||||
case Frame_Phase::ready: ++ready; break;
|
||||
case Frame_Phase::sending: ++sending; break;
|
||||
}
|
||||
}
|
||||
const auto statistics = [](const Statistics_Summary& value) noexcept {
|
||||
return observation::Frame_Policy_Statistics{value.sample_count, value.average, value.p95, value.standard_deviation};
|
||||
};
|
||||
observation::trace_frame_policy_state({state.timer_ticks, state.dropped_timer_ticks, state.completed_frames, idle, rendering, ready, sending, state.effective_frames_per_second, state.render_capacity_fps.value_or(0.0), state.send_capacity_fps.value_or(0.0), statistics(state.render_time_ns), statistics(state.send_time_ns), statistics(state.end_to_end_time_ns)});
|
||||
concurrent<State_Tag>().internal.advance();
|
||||
}
|
||||
''')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,21 +0,0 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
if not new:
|
||||
return
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(new)
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one current-state match, found {count}")
|
||||
path.write_text(text.replace(new, old, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
source = root / "render_3D/render_3D/detail/Gpu_Completion_Service.cpp"
|
||||
replace_once(source, '#include "Exception.hpp"\n', '#include "Exception.hpp"\n#include "observation/GPU_Completion.hpp"\n')
|
||||
replace_once(source, ' while (count < Private::capacity && !d->in_flight.compare_exchange_weak(count, count + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) {}\n if (count >= Private::capacity) return {{}, Admission_Result::capacity_exhausted};\n', ' while (count < Private::capacity && !d->in_flight.compare_exchange_weak(count, count + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) {}\n if (count >= Private::capacity) {\n observation::trace_gpu_completion_capacity_exhausted(count, Private::capacity);\n return {{}, Admission_Result::capacity_exhausted};\n }\n')
|
||||
replace_once(source, ' if (!d->incoming.enqueue(pending)) {\n d->in_flight.fetch_sub(1, std::memory_order_release);\n throw std::bad_alloc{};\n }\n d->request_poll(std::chrono::nanoseconds{1});\n', ' if (!d->incoming.enqueue(pending)) {\n d->in_flight.fetch_sub(1, std::memory_order_release);\n throw std::bad_alloc{};\n }\n observation::trace_gpu_completion_admitted(count + 1, Private::capacity);\n d->request_poll(std::chrono::nanoseconds{1});\n')
|
||||
replace_once(source, 'void Gpu_Completion_Service::Private::poll() noexcept {\n std::shared_ptr<Gpu_Completion_Pending_Fence> incoming_value;\n while (incoming.try_dequeue(incoming_value)) {\n active.push_back(std::move(incoming_value));\n incoming_value.reset();\n }\n', 'void Gpu_Completion_Service::Private::poll() noexcept {\n const auto active_before = active.size();\n std::shared_ptr<Gpu_Completion_Pending_Fence> incoming_value;\n while (incoming.try_dequeue(incoming_value)) {\n active.push_back(std::move(incoming_value));\n incoming_value.reset();\n }\n if (active.size() != active_before) observation::trace_gpu_completion_active(in_flight.load(std::memory_order_relaxed), active.size());\n')
|
||||
replace_once(source, ' if (status == Gpu_Completion_Pending_Fence::Status::canceled) {\n iterator = active.erase(iterator);\n in_flight.fetch_sub(1, std::memory_order_release);\n continue;\n }\n', ' if (status == Gpu_Completion_Pending_Fence::Status::canceled) {\n iterator = active.erase(iterator);\n const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;\n observation::trace_gpu_completion_canceled(remaining, active.size(), capacity);\n continue;\n }\n')
|
||||
replace_once(source, ' Result result{error, static_cast<std::int32_t>(vulkan_result), pending->observe ? elapsed_nanoseconds(pending->watched_at) : 0};\n iterator = active.erase(iterator);\n in_flight.fetch_sub(1, std::memory_order_release);\n try {\n', ' const auto watched_at = pending->watched_at;\n Result result{error, static_cast<std::int32_t>(vulkan_result), pending->observe ? elapsed_nanoseconds(watched_at) : 0};\n iterator = active.erase(iterator);\n const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;\n observation::trace_gpu_completion_completed(remaining, active.size(), capacity, watched_at, static_cast<std::int32_t>(error), static_cast<std::int32_t>(vulkan_result));\n try {\n')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,51 +0,0 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
if not new:
|
||||
return
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(new)
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one current-state match, found {count}")
|
||||
path.write_text(text.replace(new, old, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
frame_header = root / "render_3D/render_3D/base/Frame_3D.hpp"
|
||||
frame = root / "render_3D/render_3D/base/Frame_3D.cpp"
|
||||
model = root / "render_3D/render_3D/scene/Render_Scene_3D_Model.ipp"
|
||||
common = root / "render_3D/render_3D/scene/detail/Datoviz_Scene_Common.ipp"
|
||||
pipeline = root / "render_3D/render_3D/scene/detail/Datoviz_Frame_Pipeline.ipp"
|
||||
scene = root / "render_3D/render_3D/scene/Render_Scene_3D.ipp"
|
||||
replace_once(frame_header, '#include <task_flow/export/Taskflow_Observation.hpp>\n', '#include <task_flow/export/export.h>\n')
|
||||
replace_once(frame_header, ' static void assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation);\n [[nodiscard]] static Taskflow_Observation taskflow_observation(Frame_3D* frame);\n', ' static void assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation);\n static Run_Taskflow_Result run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Compose_Facade>& graph, Taskflow_Completion completion);\n [[nodiscard]] static Taskflow_Observation taskflow_observation(Frame_3D* frame);\n')
|
||||
replace_once(frame, '#include "Frame_3D.hpp"\n', '#include "Frame_3D.hpp"\n#include "observation/Frame.hpp"\n#include "observation/Frame_Attention.hpp"\n#include "observation/Frame_Timing.hpp"\n#include "observation/Resource.hpp"\n#include "observation/Taskflow.hpp"\n#include "observation/Vulkan.hpp"\n')
|
||||
replace_once(frame, 'std::uint64_t encode_present_value(std::uint64_t value) noexcept {\n return value == std::numeric_limits<std::uint64_t>::max() ? value : value + 1;\n}\n', 'std::uint64_t encode_present_value(std::uint64_t value) noexcept {\n return value == std::numeric_limits<std::uint64_t>::max() ? value : value + 1;\n}\nstd::uint64_t decode_present_value(std::uint64_t value) noexcept {\n return value == std::numeric_limits<std::uint64_t>::max() ? value : value - 1;\n}\nstd::uint64_t marker_span(const std::array<std::atomic_uint64_t, marker_count>& markers, Frame_Trace_Marker begin, Frame_Trace_Marker end) noexcept {\n const auto begin_value = markers[static_cast<std::size_t>(begin)].load(std::memory_order_acquire);\n const auto end_value = markers[static_cast<std::size_t>(end)].load(std::memory_order_acquire);\n if (begin_value == 0 || end_value == 0) return 0;\n const auto begin_ns = decode_present_value(begin_value);\n const auto end_ns = decode_present_value(end_value);\n return end_ns >= begin_ns ? end_ns - begin_ns : 0;\n}\n')
|
||||
replace_once(frame, ' Frame_Request_Source source{Frame_Request_Source::unspecified};\n std::chrono::steady_clock::time_point created_at{};\n', ' Frame_Request_Source source{Frame_Request_Source::unspecified};\n observation::Frame_Context frame_observation{};\n observation::Frame_Resource_Context resource_observation{};\n observation::Vulkan_Submission_Context submission_observation{};\n std::chrono::steady_clock::time_point created_at{};\n')
|
||||
replace_once(frame, ' d->rendered_identity = {};\n d->datoviz_observation.reset();\n d->created_at = std::chrono::steady_clock::now();\n', ' d->rendered_identity = {};\n d->datoviz_observation.reset();\n d->frame_observation = observation::make_frame_context(identity.sequence, identity.generation);\n d->resource_observation = observation::make_frame_resource_context(d->frame_observation);\n d->submission_observation = observation::make_vulkan_submission_context(d->frame_observation);\n d->created_at = std::chrono::steady_clock::now();\n')
|
||||
replace_once(frame, 'void Frame_3D::mark(Frame_Trace_Marker marker) noexcept {\n const auto index = static_cast<std::size_t>(marker);\n if (index >= marker_count) return;\n const auto elapsed = std::chrono::steady_clock::now() - d->created_at;\n const auto elapsed_ns = static_cast<std::uint64_t>(std::max<std::int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()));\n std::uint64_t expected{};\n d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed);\n}\n', 'void Frame_3D::mark(Frame_Trace_Marker marker) noexcept {\n const auto index = static_cast<std::size_t>(marker);\n if (index >= marker_count) return;\n const auto elapsed = std::chrono::steady_clock::now() - d->created_at;\n const auto elapsed_ns = static_cast<std::uint64_t>(std::max<std::int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()));\n std::uint64_t expected{};\n if (!d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed)) return;\n if (marker == Frame_Trace_Marker::scene_render_entered) {\n observation::trace_frame(d->frame_observation);\n return;\n }\n if (marker == Frame_Trace_Marker::gpu_submitted) {\n observation::trace_vulkan_submitted(d->submission_observation);\n return;\n }\n if (marker == Frame_Trace_Marker::gpu_completed) {\n const auto submitted = d->markers[static_cast<std::size_t>(Frame_Trace_Marker::gpu_submitted)].load(std::memory_order_acquire);\n if (submitted == 0) return;\n const auto submitted_ns = decode_present_value(submitted);\n observation::trace_vulkan_completed(d->submission_observation, elapsed_ns >= submitted_ns ? elapsed_ns - submitted_ns : 0);\n return;\n }\n if (marker != Frame_Trace_Marker::frame_ready) return;\n const observation::Frame_Timing timing{d->frame_observation, marker_span(d->markers, Frame_Trace_Marker::scene_render_entered, Frame_Trace_Marker::frame_ready), marker_span(d->markers, Frame_Trace_Marker::scene_render_requested, Frame_Trace_Marker::scene_render_started), marker_span(d->markers, Frame_Trace_Marker::scene_render_started, Frame_Trace_Marker::gpu_submitted), marker_span(d->markers, Frame_Trace_Marker::backend_prepare_started, Frame_Trace_Marker::backend_prepare_finished), marker_span(d->markers, Frame_Trace_Marker::backend_queue_entered, Frame_Trace_Marker::gpu_submitted), marker_span(d->markers, Frame_Trace_Marker::gpu_completed, Frame_Trace_Marker::frame_ready)};\n observation::trace_frame_timing(timing);\n observation::Frame_Attention attention{timing};\n if (d->datoviz_observation) {\n const auto& datoviz = *d->datoviz_observation;\n attention.uploaded_bytes = datoviz.uploaded_bytes;\n attention.readback_bytes = datoviz.readback_bytes;\n attention.upload_ns = datoviz.drp_upload_ns;\n attention.upload_queue_wait_ns = datoviz.drp_upload_submit_queue_wait_ns;\n attention.upload_fence_wait_ns = datoviz.drp_upload_fence_wait_ns;\n attention.shader_compile_ns = datoviz.drp_shader_compile_ns;\n attention.pipeline_create_ns = datoviz.drp_pipeline_create_ns;\n attention.pipeline_create_count = datoviz.drp_pipeline_create_count;\n if (datoviz.gpu) {\n attention.gpu_render_ns = datoviz.gpu->render_ns;\n attention.gpu_total_ns = datoviz.gpu->total_ns;\n }\n }\n attention.vulkan = observation::vulkan_state();\n attention.gpu_completion = observation::gpu_completion_state();\n observation::trace_frame_attention(attention);\n}\n')
|
||||
replace_once(frame, 'void detail::Frame_3D_Access::assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation) {\n if (!frame) throw std::invalid_argument("Frame_3D diagnostic target is null");\n frame->d->datoviz_observation.emplace(std::move(observation));\n}\n', 'void detail::Frame_3D_Access::assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation) {\n if (!frame) throw std::invalid_argument("Frame_3D diagnostic target is null");\n aethera::observation::trace_frame_resources({frame->d->resource_observation, observation.uploaded_bytes, observation.readback_bytes, observation.drp_buffer_create_ns, observation.drp_texture_create_ns, observation.drp_shader_compile_ns, observation.drp_pipeline_create_ns, observation.drp_upload_ns, observation.drp_upload_vulkan_allocate_ns, observation.drp_upload_host_copy_ns, observation.drp_upload_submit_queue_wait_ns, observation.drp_upload_fence_wait_ns, observation.drp_transfer_ns, observation.drp_pipeline_create_count});\n if (observation.gpu) {\n aethera::observation::trace_vulkan_gpu_timing(frame->d->submission_observation, observation.gpu->render_ns, observation.gpu->transition_ns, observation.gpu->copy_ns, observation.gpu->total_ns);\n }\n frame->d->datoviz_observation.emplace(std::move(observation));\n}\n')
|
||||
replace_once(frame, 'Taskflow_Observation detail::Frame_3D_Access::taskflow_observation(Frame_3D* frame) {\n if (!frame || !frame->d->taskflow_observation) throw std::logic_error("Frame_3D has no Taskflow observation request");\n return *frame->d->taskflow_observation;\n}\n', 'Run_Taskflow_Result detail::Frame_3D_Access::run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Compose_Facade>& graph, Taskflow_Completion completion) {\n#ifdef TRACY_ENABLE\n if (observation::tracy_connected()) {\n const auto context = observation::make_taskflow_trace_context(frame->d->frame_observation);\n if (frame->d->taskflow_observation) return graph->run_observed(std::move(completion), taskflow_observation(frame), context);\n return graph->run(std::move(completion), context);\n }\n#endif\n if (frame->d->taskflow_observation) return graph->run_observed(std::move(completion), taskflow_observation(frame));\n return graph->run(std::move(completion));\n}\nTaskflow_Observation detail::Frame_3D_Access::taskflow_observation(Frame_3D* frame) {\n if (!frame || !frame->d->taskflow_observation) throw std::logic_error("Frame_3D has no Taskflow observation request");\n return *frame->d->taskflow_observation;\n}\n')
|
||||
replace_once(model, '#include "observation/Tracy.hpp"\n', '')
|
||||
for line in [
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.Submit.Callback", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.GPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.Frame.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});\n',
|
||||
' AETHERA_TRACE_FRAME("Render3D");\n',
|
||||
' AETHERA_TRACE_ZONE_TAGS("Render3D.CPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});\n'
|
||||
]:
|
||||
replace_once(model, line, '')
|
||||
replace_once(model, ' const auto submitted = graph->run([execution](std::exception_ptr runtime_failure) mutable {\n complete_execution(std::move(execution), std::move(runtime_failure));\n } AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(execution->frame->identity().sequence, execution->frame->identity().generation));\n', ' const auto submitted = detail::Frame_3D_Access::run_taskflow(execution->frame, graph, [execution](std::exception_ptr runtime_failure) mutable {\n complete_execution(std::move(execution), std::move(runtime_failure));\n });\n')
|
||||
replace_once(model, ' const auto submitted = frame->taskflow_trace_requested() ? graph->run_observed(std::move(completed), detail::Frame_3D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : graph->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation));\n', ' const auto submitted = detail::Frame_3D_Access::run_taskflow(frame, graph, std::move(completed));\n')
|
||||
replace_once(common, '#include <volk.h>\n', '#include <volk.h>\n#include "observation/Vulkan.hpp"\n')
|
||||
replace_once(common, ' explicit Immediate_Submission(VkDevice device_value) noexcept : device(device_value) {}\n', ' Immediate_Submission(VkDevice device_value, VkQueue queue) noexcept : device(device_value), observation(aethera::observation::make_vulkan_submission_context(reinterpret_cast<std::uintptr_t>(queue))) {}\n')
|
||||
replace_once(common, ' std::uint64_t queue_finished_ns{};\n };\n', ' std::uint64_t queue_finished_ns{};\n aethera::observation::Vulkan_Submission_Context observation{};\n };\n')
|
||||
replace_once(common, ' auto submission = std::make_shared<Immediate_Submission>(dvz_device_handle(dvz_gpu_ctx_device(gpu_context_)));\n', ' auto submission = std::make_shared<Immediate_Submission>(dvz_device_handle(dvz_gpu_ctx_device(gpu_context_)), queue);\n')
|
||||
replace_once(common, ' submission->queue_started_ns = trace_now_ns();\n const VkResult result = vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);\n submission->queue_finished_ns = trace_now_ns();\n submission->submission_result.store(result, std::memory_order_relaxed);\n', ' submission->queue_started_ns = trace_now_ns();\n const VkResult result = aethera::observation::trace_vulkan_submit([&] {\n return vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);\n });\n submission->queue_finished_ns = trace_now_ns();\n if (result == VK_SUCCESS) aethera::observation::trace_vulkan_submitted(submission->observation);\n submission->submission_result.store(result, std::memory_order_relaxed);\n')
|
||||
replace_once(common, ' if (timing != nullptr) {\n const auto queue_started = submission->queue_started_ns;\n', ' const auto completion_observed = trace_now_ns();\n if (static_cast<VkResult>(submission->submission_result.load(std::memory_order_relaxed)) == VK_SUCCESS) {\n aethera::observation::trace_vulkan_completed(submission->observation, submission->queue_finished_ns != 0 && completion_observed > submission->queue_finished_ns ? completion_observed - submission->queue_finished_ns : 0);\n }\n if (timing != nullptr) {\n const auto queue_started = submission->queue_started_ns;\n')
|
||||
replace_once(common, ' const auto completion_observed = trace_now_ns();\n timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished\n', ' timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished\n')
|
||||
replace_once(pipeline, ' target(pending).submit();\n', ' aethera::observation::trace_vulkan_submit([&] {\n target(pending).submit();\n });\n')
|
||||
replace_once(scene, '#include <mutex>\n', '#include <mutex>\n#include "synchronization/Mutex.hpp"\n')
|
||||
replace_once(scene, ' mutable std::mutex target_mutex_{}; /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */\n', ' mutable AETHERA_MUTEX(target_mutex_, "Render3D.Target"); /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */\n')
|
||||
replace_once(pipeline, ' std::mutex& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */\n', ' decltype(target_mutex_)& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */\n')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,20 +0,0 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
if not new:
|
||||
return
|
||||
text = path.read_text(encoding="utf-8")
|
||||
count = text.count(new)
|
||||
if count != 1:
|
||||
raise RuntimeError(f"{path}: expected one current-state match, found {count}")
|
||||
path.write_text(text.replace(new, old, 1), encoding="utf-8")
|
||||
def main() -> None:
|
||||
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
export = root / "kernel/kernel/module/task_flow/export/export.h"
|
||||
runtime = root / "kernel/kernel/module/task_flow/src/Task_Runtime.cpp"
|
||||
replace_once(export, 'struct Taskflow_Trace_Context {\n std::uint64_t frame{};\n std::uint64_t generation{};\n};\n', 'struct Taskflow_Trace_Context {\n std::uint64_t frame{};\n std::uint64_t generation{};\n std::uint64_t root{};\n std::uint64_t scope{};\n std::uint64_t parent{};\n std::uint64_t correlation{};\n};\n')
|
||||
replace_once(runtime, '#include "observation/Tracy.hpp"\n', '#include "observation/Taskflow.hpp"\n')
|
||||
replace_once(runtime, ' struct Frame_Task_Trace_Tags {\n std::uint64_t frame{};\n std::uint64_t generation{};\n std::string_view graph{};\n std::size_t worker{};\n std::uint64_t task{};\n };\n', '')
|
||||
replace_once(runtime, ' observation::attach_tracy_task_tags(zone, Frame_Task_Trace_Tags{context->frame, context->generation, graph, worker.id(), native_id});\n', ' observation::trace_taskflow_task(zone, *context, graph, worker.id(), native_id);\n')
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -82,7 +82,17 @@ Render_Scene_2D_Result Render_Scene_2D::Private::render(Frame_2D* frame, Complet
|
||||
AETHERA_TRACE_ZONE_TAGS("Render2D.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});
|
||||
completion(frame, std::move(failure));
|
||||
};
|
||||
const auto submitted = frame->taskflow_trace_requested() ? taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : taskflow()->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation));
|
||||
Run_Taskflow_Result submitted;
|
||||
#ifdef TRACY_ENABLE
|
||||
const Taskflow_Trace_Context trace_context{frame->identity().sequence, frame->identity().generation};
|
||||
if (frame->taskflow_trace_requested()) {
|
||||
submitted = observation::trace_capture_active() ? taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame), trace_context) : taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame));
|
||||
} else {
|
||||
submitted = observation::trace_capture_active() ? taskflow()->run(std::move(completed), trace_context) : taskflow()->run(std::move(completed));
|
||||
}
|
||||
#else
|
||||
submitted = frame->taskflow_trace_requested() ? taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame)) : taskflow()->run(std::move(completed));
|
||||
#endif
|
||||
if (submitted != Run_Taskflow_Result::submitted) return std::unexpected(Render_Scene_2D_Error{submitted});
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Frame_3D.hpp"
|
||||
#include "../detail/Trace_Adapter.hpp"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@@ -90,7 +91,8 @@ void Frame_3D::mark(Frame_Trace_Marker marker) noexcept {
|
||||
const auto elapsed = std::chrono::steady_clock::now() - d->created_at;
|
||||
const auto elapsed_ns = static_cast<std::uint64_t>(std::max<std::int64_t>(0, std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()));
|
||||
std::uint64_t expected{};
|
||||
d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed);
|
||||
if (!d->markers[index].compare_exchange_strong(expected, encode_present_value(elapsed_ns), std::memory_order_release, std::memory_order_relaxed)) return;
|
||||
aethera::trace_adapter::frame_marker(d->identity, d->markers, marker);
|
||||
}
|
||||
|
||||
void Frame_3D::record(Frame_Trace_Measurement measurement, std::uint64_t value_ns) noexcept {
|
||||
@@ -138,9 +140,15 @@ void detail::Frame_3D_Access::share_pixels(Frame_3D* source, Frame_3D* target) {
|
||||
|
||||
void detail::Frame_3D_Access::assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation) {
|
||||
if (!frame) throw std::invalid_argument("Frame_3D diagnostic target is null");
|
||||
aethera::trace_adapter::datoviz_observation(frame->d->identity, observation);
|
||||
frame->d->datoviz_observation.emplace(std::move(observation));
|
||||
}
|
||||
|
||||
Run_Taskflow_Result detail::Frame_3D_Access::run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Facade>& graph, Taskflow_Completion completion) {
|
||||
if (frame->d->taskflow_observation) return aethera::trace_adapter::run_taskflow_observed(frame->d->identity, graph, std::move(completion), taskflow_observation(frame));
|
||||
return aethera::trace_adapter::run_taskflow(frame->d->identity, graph, std::move(completion));
|
||||
}
|
||||
|
||||
Taskflow_Observation detail::Frame_3D_Access::taskflow_observation(Frame_3D* frame) {
|
||||
if (!frame || !frame->d->taskflow_observation) throw std::logic_error("Frame_3D has no Taskflow observation request");
|
||||
return *frame->d->taskflow_observation;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "Datoviz_Frame_Observation.hpp"
|
||||
#include "Types.hpp"
|
||||
#include <task_flow/export/Taskflow_Observation.hpp>
|
||||
#include <task_flow/export/export.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -125,6 +125,7 @@ struct Frame_3D_Access {
|
||||
static void assign_pixels(std::span<Frame_3D* const> frames, Extent extent, std::vector<std::byte> pixels, Frame_Identity rendered_identity);
|
||||
static void share_pixels(Frame_3D* source, Frame_3D* target);
|
||||
static void assign_datoviz_observation(Frame_3D* frame, Datoviz_Frame_Observation observation);
|
||||
static Run_Taskflow_Result run_taskflow(Frame_3D* frame, proxy<task_flow::Task_Graph_Facade>& graph, Taskflow_Completion completion);
|
||||
[[nodiscard]] static Taskflow_Observation taskflow_observation(Frame_3D* frame);
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Gpu_Completion_Service.ipp"
|
||||
#include "Exception.hpp"
|
||||
#include "Trace_Adapter.hpp"
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
@@ -14,6 +15,11 @@ std::uint64_t elapsed_nanoseconds(std::chrono::steady_clock::time_point started)
|
||||
|
||||
Gpu_Completion_Service::Private::Private() {
|
||||
active.reserve(capacity);
|
||||
timer->schedule_every(recovery_interval, [this] {
|
||||
if (in_flight.load(std::memory_order_acquire) == 0 || poll_armed.exchange(true, std::memory_order_acq_rel)) return;
|
||||
poll_armed.store(false, std::memory_order_release);
|
||||
poll();
|
||||
});
|
||||
}
|
||||
|
||||
Gpu_Completion_Service::Gpu_Completion_Service() : d(std::make_unique<Private>()) {}
|
||||
@@ -54,8 +60,18 @@ Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(Completio
|
||||
if (!on_exception) throw std::invalid_argument("GPU completion exception handler is empty");
|
||||
auto count = d->in_flight.load(std::memory_order_relaxed);
|
||||
while (count < Private::capacity && !d->in_flight.compare_exchange_weak(count, count + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) {}
|
||||
if (count >= Private::capacity) return {{}, Admission_Result::capacity_exhausted};
|
||||
auto pending = std::make_shared<Gpu_Completion_Pending_Fence>();
|
||||
if (count >= Private::capacity) {
|
||||
aethera::trace_adapter::gpu_completion_capacity_exhausted(count, Private::capacity);
|
||||
return {{}, Admission_Result::capacity_exhausted};
|
||||
}
|
||||
std::shared_ptr<Gpu_Completion_Pending_Fence> pending;
|
||||
try {
|
||||
pending = std::make_shared<Gpu_Completion_Pending_Fence>();
|
||||
}
|
||||
catch (...) {
|
||||
d->in_flight.fetch_sub(1, std::memory_order_release);
|
||||
throw;
|
||||
}
|
||||
pending->completion = std::move(completion);
|
||||
pending->on_exception = std::move(on_exception);
|
||||
pending->observe = observe;
|
||||
@@ -64,6 +80,7 @@ Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(Completio
|
||||
d->in_flight.fetch_sub(1, std::memory_order_release);
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
aethera::trace_adapter::gpu_completion_admitted(count + 1);
|
||||
d->request_poll(std::chrono::nanoseconds{1});
|
||||
return {Reservation(std::move(pending)), Admission_Result::none};
|
||||
}
|
||||
@@ -94,17 +111,22 @@ void Gpu_Completion_Service::Private::request_poll(std::chrono::nanoseconds dela
|
||||
});
|
||||
}
|
||||
catch (...) {
|
||||
/* No asynchronous failure receiver exists here; another producer must request a new poll before queued fences can progress. */
|
||||
poll_armed.store(false, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void Gpu_Completion_Service::Private::poll() noexcept {
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto trace_active_before = active.size();
|
||||
#endif
|
||||
std::shared_ptr<Gpu_Completion_Pending_Fence> incoming_value;
|
||||
while (incoming.try_dequeue(incoming_value)) {
|
||||
active.push_back(std::move(incoming_value));
|
||||
incoming_value.reset();
|
||||
}
|
||||
#ifdef TRACY_ENABLE
|
||||
if (active.size() != trace_active_before) aethera::trace_adapter::gpu_completion_active(in_flight.load(std::memory_order_relaxed), active.size());
|
||||
#endif
|
||||
bool needs_more{};
|
||||
for (auto iterator = active.begin(); iterator != active.end();) {
|
||||
auto& pending = *iterator;
|
||||
@@ -116,7 +138,12 @@ void Gpu_Completion_Service::Private::poll() noexcept {
|
||||
}
|
||||
if (status == Gpu_Completion_Pending_Fence::Status::canceled) {
|
||||
iterator = active.erase(iterator);
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;
|
||||
aethera::trace_adapter::gpu_completion_canceled(remaining, active.size(), capacity);
|
||||
#else
|
||||
in_flight.fetch_sub(1, std::memory_order_release);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
VkResult vulkan_result = VK_NOT_READY;
|
||||
@@ -137,9 +164,17 @@ void Gpu_Completion_Service::Private::poll() noexcept {
|
||||
pending->status.store(Gpu_Completion_Pending_Fence::Status::canceled, std::memory_order_release);
|
||||
auto completion = std::move(pending->completion);
|
||||
auto on_exception = std::move(pending->on_exception);
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto trace_watched_at = pending->watched_at;
|
||||
#endif
|
||||
Result result{error, static_cast<std::int32_t>(vulkan_result), pending->observe ? elapsed_nanoseconds(pending->watched_at) : 0};
|
||||
iterator = active.erase(iterator);
|
||||
#ifdef TRACY_ENABLE
|
||||
const auto remaining = in_flight.fetch_sub(1, std::memory_order_release) - 1;
|
||||
aethera::trace_adapter::gpu_completion_completed(remaining, active.size(), capacity, trace_watched_at, static_cast<std::int32_t>(error), static_cast<std::int32_t>(vulkan_result));
|
||||
#else
|
||||
in_flight.fetch_sub(1, std::memory_order_release);
|
||||
#endif
|
||||
try {
|
||||
completion(std::move(result));
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ struct Gpu_Completion_Pending_Fence final {
|
||||
struct Gpu_Completion_Service::Private final {
|
||||
static constexpr std::size_t capacity = 1024;
|
||||
static constexpr auto probe_interval = std::chrono::milliseconds(1);
|
||||
static constexpr auto recovery_interval = std::chrono::milliseconds(100);
|
||||
static constexpr std::uint64_t maximum_fence_age_ns = 30'000'000'000ULL;
|
||||
|
||||
Private();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "synchronization/Mutex.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -127,7 +128,7 @@ private:
|
||||
DvzPointerGestureHandler* gesture_handler_{}; /* 指针手势处理器所有权。 */
|
||||
std::uint64_t controller_revision_{1}; /* 已应用控制器输入版本。 */
|
||||
bool input_changed_{}; /* 当前录制周期是否消费了输入。 */
|
||||
mutable std::mutex target_mutex_{}; /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */
|
||||
mutable AETHERA_MUTEX(target_mutex_, "Render3D.Target"); /* 只保护 Datoviz 目标资源的提交与回读边界;不保护 Frame Policy 状态。 */
|
||||
std::unique_ptr<Datoviz_Frame_Target_Set> targets_{}; /* Datoviz 后端目标资源池的唯一所有权。 */
|
||||
std::uint64_t target_generation_{}; /* 目标槽重建代数。 */
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "../detail/Exception.hpp"
|
||||
#include "../detail/Gpu_Completion_Service.hpp"
|
||||
#include "Error_handling_specification/Failure_Policy.hpp"
|
||||
#include "observation/Tracy.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
@@ -238,7 +237,6 @@ inline void Render_Scene_3D::Private::render_datoviz(const Shared_Render_Executi
|
||||
frame->mark(Frame_Trace_Marker::backend_submit_queued);
|
||||
auto shared_reservation = std::make_shared<detail::Gpu_Completion_Service::Reservation>(std::move(reservation.reservation));
|
||||
submit(*execution->datoviz_frame, [this, execution, frame, shared_reservation = std::move(shared_reservation)](std::exception_ptr submission_failure) mutable {
|
||||
AETHERA_TRACE_ZONE_TAGS("Render3D.Submit.Callback", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});
|
||||
try {
|
||||
frame->mark(Frame_Trace_Marker::backend_queue_left);
|
||||
if (submission_failure) {
|
||||
@@ -274,7 +272,6 @@ inline void Render_Scene_3D::Private::render_datoviz(const Shared_Render_Executi
|
||||
}
|
||||
|
||||
inline void Render_Scene_3D::Private::observe_datoviz_completion(const Shared_Render_Execution& execution, std::optional<detail::Gpu_Completion_Service::Result> result, std::exception_ptr failure) noexcept {
|
||||
AETHERA_TRACE_ZONE_TAGS("Render3D.GPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});
|
||||
execution->frame->mark(Frame_Trace_Marker::gpu_completed);
|
||||
execution->completion_result = std::move(result);
|
||||
execution->backend_failure = std::move(failure);
|
||||
@@ -292,9 +289,9 @@ inline void Render_Scene_3D::Private::try_complete(const Shared_Render_Execution
|
||||
execution->collection_failure = collect_datoviz(*execution);
|
||||
});
|
||||
if (!task) throw std::logic_error("failed to create 3D completion task");
|
||||
const auto submitted = graph->run([execution](std::exception_ptr runtime_failure) mutable {
|
||||
const auto submitted = detail::Frame_3D_Access::run_taskflow(execution->frame, graph, [execution](std::exception_ptr runtime_failure) mutable {
|
||||
complete_execution(std::move(execution), std::move(runtime_failure));
|
||||
} AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(execution->frame->identity().sequence, execution->frame->identity().generation));
|
||||
});
|
||||
if (submitted != Run_Taskflow_Result::submitted) throw std::runtime_error("3D completion task runtime is unavailable");
|
||||
}
|
||||
catch (...) {
|
||||
@@ -333,7 +330,6 @@ inline std::exception_ptr Render_Scene_3D::Private::collect_datoviz(Render_Execu
|
||||
|
||||
inline void Render_Scene_3D::Private::complete_execution(Shared_Render_Execution execution, std::exception_ptr runtime_failure) {
|
||||
auto* frame = execution->frame;
|
||||
AETHERA_TRACE_ZONE_TAGS("Render3D.Frame.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation});
|
||||
auto callback = std::move(execution->completion);
|
||||
auto failure = execution->cpu_failure ? std::move(execution->cpu_failure) : std::move(execution->backend_failure);
|
||||
if (!failure) failure = std::move(execution->collection_failure);
|
||||
@@ -364,7 +360,6 @@ inline void Render_Scene_3D::Private::fail_datoviz(std::exception_ptr failure) n
|
||||
inline Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Frame_3D* frame, Completion completion) {
|
||||
if (!frame) return Render_Result::frame_missing;
|
||||
if (!completion) return Render_Result::completion_missing;
|
||||
AETHERA_TRACE_FRAME("Render3D");
|
||||
frame->mark(Frame_Trace_Marker::scene_render_entered);
|
||||
try {
|
||||
frame->mark(Frame_Trace_Marker::scene_advance_started);
|
||||
@@ -381,13 +376,12 @@ inline Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Frame_3D*
|
||||
auto graph = build_frame_graph(execution, parameters);
|
||||
frame->mark(Frame_Trace_Marker::scene_render_requested);
|
||||
auto completed = [this, execution](std::exception_ptr failure) {
|
||||
AETHERA_TRACE_ZONE_TAGS("Render3D.CPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation});
|
||||
execution->cpu_failure = std::move(failure);
|
||||
if (execution->cpu_failure && !execution->backend_started.load(std::memory_order_acquire)) execution->backend_finished.store(true, std::memory_order_release);
|
||||
execution->cpu_finished.store(true, std::memory_order_release);
|
||||
try_complete(execution);
|
||||
};
|
||||
const auto submitted = frame->taskflow_trace_requested() ? graph->run_observed(std::move(completed), detail::Frame_3D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : graph->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation));
|
||||
const auto submitted = detail::Frame_3D_Access::run_taskflow(frame, graph, std::move(completed));
|
||||
if (submitted != Run_Taskflow_Result::submitted) return Render_Result::backend_unavailable;
|
||||
return Render_Result::submitted;
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ std::optional<Datoviz_Pending_Frame> Scene_Datoviz_State::prepare(const Scene_3D
|
||||
}
|
||||
struct Recording_Scope {
|
||||
Datoviz_Frame_Target& target; /* 异常退出时回收尚未发布的录制槽。 */
|
||||
std::mutex& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */
|
||||
decltype(target_mutex_)& target_mutex; /* 本 Scene Frame Target 的生命周期门。 */
|
||||
bool released{}; /* finish_recording 成功后禁止回滚。 */
|
||||
~Recording_Scope() {
|
||||
if (released) return;
|
||||
@@ -372,7 +372,9 @@ void Scene_Datoviz_State::submit(Datoviz_Pending_Frame& pending, std::function<v
|
||||
pending.observation.queue_submit_wait_ns = trace_now_ns() - queued;
|
||||
std::lock_guard target_lock(target_mutex_);
|
||||
const std::uint64_t started = trace_now_ns();
|
||||
target(pending).submit();
|
||||
aethera::trace_adapter::vulkan_submit([&] {
|
||||
target(pending).submit();
|
||||
});
|
||||
pending.observation.submit_ns = trace_now_ns() - started;
|
||||
completion({});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <datoviz/vk/gpu_ctx.h>
|
||||
#include <datoviz/vklite.h>
|
||||
#include <volk.h>
|
||||
#include "../../detail/Trace_Adapter.hpp"
|
||||
#include <concurrentqueue-1.0.5/concurrentqueue.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -233,8 +234,10 @@ struct Datoviz_Render_Context final : std::enable_shared_from_this<Datoviz_Rende
|
||||
const auto enqueue_started = trace_now_ns();
|
||||
try {
|
||||
enqueue_submission([submission, queue]() noexcept {
|
||||
submission->queue_started_ns = trace_now_ns();
|
||||
const VkResult result = vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);
|
||||
submission->queue_started_ns = trace_now_ns();
|
||||
const VkResult result = aethera::trace_adapter::vulkan_submit([&] {
|
||||
return vkQueueSubmit2(queue, 1, &submission->submit, submission->fence);
|
||||
});
|
||||
submission->queue_finished_ns = trace_now_ns();
|
||||
submission->submission_result.store(result, std::memory_order_relaxed);
|
||||
submission->submitted.store(true, std::memory_order_release);
|
||||
@@ -269,19 +272,26 @@ struct Datoviz_Render_Context final : std::enable_shared_from_this<Datoviz_Rende
|
||||
/* 已入队命令的栈外资源不能提前释放;违反 Worker 前置条件时立即终止。 */
|
||||
std::terminate();
|
||||
}
|
||||
const auto queue_finished = submission->queue_finished_ns;
|
||||
std::uint64_t completion_observed{};
|
||||
#ifdef TRACY_ENABLE
|
||||
completion_observed = trace_now_ns();
|
||||
if (static_cast<VkResult>(submission->submission_result.load(std::memory_order_relaxed)) == VK_SUCCESS) aethera::trace_adapter::immediate_vulkan_completed(reinterpret_cast<std::uintptr_t>(submission.get()), queue_finished != 0 && completion_observed > queue_finished ? completion_observed - queue_finished : 0);
|
||||
#endif
|
||||
if (timing != nullptr) {
|
||||
const auto queue_started = submission->queue_started_ns;
|
||||
const auto queue_finished = submission->queue_finished_ns;
|
||||
timing->queue_wait_ns = queue_started > enqueue_finished
|
||||
? queue_started - enqueue_finished
|
||||
: 0;
|
||||
#ifndef TRACY_ENABLE
|
||||
completion_observed = trace_now_ns();
|
||||
#endif
|
||||
const auto queue_started = submission->queue_started_ns;
|
||||
timing->queue_wait_ns = queue_started > enqueue_finished
|
||||
? queue_started - enqueue_finished
|
||||
: 0;
|
||||
timing->queue_submit_ns = queue_finished > queue_started
|
||||
? queue_finished - queue_started
|
||||
: 0;
|
||||
const auto completion_observed = trace_now_ns();
|
||||
timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished
|
||||
? completion_observed - queue_finished
|
||||
: 0;
|
||||
timing->fence_wait_ns = queue_finished != 0 && completion_observed > queue_finished
|
||||
? completion_observed - queue_finished
|
||||
: 0;
|
||||
}
|
||||
return submission->completion_result.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
def main() -> None:
|
||||
package = Path(__file__).resolve().parent
|
||||
repository = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
||||
for script in [
|
||||
"revert_text_guardrail_frame_policy_observation.py",
|
||||
"revert_text_guardrail_gpu_completion_observation.py",
|
||||
"revert_text_guardrail_render_3D_observation.py",
|
||||
"revert_text_guardrail_taskflow_observation_context.py"
|
||||
]:
|
||||
subprocess.run([sys.executable, str(package / "patches" / script), str(repository)], check=True)
|
||||
environment = os.environ.copy()
|
||||
environment["AETHERA_TEXT_GUARDRAIL_UPGRADE"] = "1"
|
||||
subprocess.run([sys.executable, str(package / "apply_all.py"), str(repository)], check=True, env=environment)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user