ai自主改之前

This commit is contained in:
2026-08-24 13:12:57 +08:00
parent cb9822074b
commit ca6d8f8e79
45 changed files with 996 additions and 613 deletions
+2 -2
View File
@@ -244,8 +244,8 @@ private:
data().buffer_storage.advance();
data().dependency_graph_storage.advance();
after_advance();
// after_advance 只修改已提交的 current;由状态缓冲统一刷新下一次编辑基线,具体机制不得自行同步两份状态。
*data().state.pending = *data().state.current;
// Commit_Double_Buffer::advance() 已为 pending 建立 current 基线;after_advance
// 只向 pending 写本轮派生状态,禁止回写正在供外部查询的 current。
}
public:
template <detail::Buffer_Tag_In<Buffers> Tag>
+46 -21
View File
@@ -3,6 +3,7 @@
#include <chrono>
#include <limits>
#include <mutex>
#include <stdexcept>
#include <taskflow/observer/interface.hpp>
namespace aethera {
namespace {
@@ -45,11 +46,9 @@ private:
std::atomic_uint64_t worker_busy_time_ns{};
std::atomic_uint64_t first_task_time_ns{};
std::atomic_uint64_t last_task_time_ns{};
mutable std::mutex longest_mutex;
std::uint64_t longest_task_time_ns{};
std::size_t longest_task_hash{};
std::string longest_task_name;
tf::TaskType longest_task_type{tf::TaskType::UNDEFINED};
std::atomic_uint64_t longest_task_time_ns{};
std::atomic_size_t longest_task_hash{};
std::atomic<tf::TaskType> longest_task_type{tf::TaskType::UNDEFINED};
static std::uint64_t clock_ns(Clock::time_point value) noexcept {
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(value.time_since_epoch()).count());
}
@@ -79,7 +78,6 @@ public:
}
void on_entry(tf::WorkerView worker, tf::TaskView task) override {
auto now = Clock::now();
detail::observe_stage_entry(task.hash_value(), clock_ns(now));
auto& worker_starts = starts[worker.id()];
if (worker_starts.empty()) {
worker_busy_starts[worker.id()] = now;
@@ -103,7 +101,6 @@ public:
}
void on_exit(tf::WorkerView worker, tf::TaskView task) override {
auto now = Clock::now();
detail::observe_stage_exit(task.hash_value(), clock_ns(now));
auto& worker_starts = starts[worker.id()];
auto start = worker_starts.back();
worker_starts.pop_back();
@@ -123,14 +120,11 @@ public:
update_min(type.min_time_ns, elapsed);
update_max(type.max_time_ns, elapsed);
}
{
std::lock_guard guard(longest_mutex);
if (longest_task_time_ns < elapsed) {
longest_task_time_ns = elapsed;
longest_task_hash = task.hash_value();
longest_task_name = task.name();
longest_task_type = task.type();
}
auto longest = longest_task_time_ns.load(std::memory_order_relaxed);
if (longest < elapsed && longest_task_time_ns.compare_exchange_strong(
longest, elapsed, std::memory_order_relaxed)) {
longest_task_hash.store(task.hash_value(), std::memory_order_relaxed);
longest_task_type.store(task.type(), std::memory_order_relaxed);
}
active_tasks.fetch_sub(1, std::memory_order_relaxed);
if (worker_starts.empty()) {
@@ -187,11 +181,10 @@ public:
target.max_task_time_ns = source.max_task_time_ns.load(std::memory_order_relaxed);
target.utilization = state.observed_wall_time_ns ? static_cast<double>(target.busy_time_ns) * 100.0 / static_cast<double>(state.observed_wall_time_ns) : 0.0;
}
std::lock_guard guard(longest_mutex);
state.longest_task_time_ns = longest_task_time_ns;
state.longest_task_hash = longest_task_hash;
state.longest_task_name = longest_task_name;
state.longest_task_type = longest_task_type;
state.longest_task_time_ns = longest_task_time_ns.load(std::memory_order_relaxed);
state.longest_task_hash = longest_task_hash.load(std::memory_order_relaxed);
state.longest_task_name.clear();
state.longest_task_type = longest_task_type.load(std::memory_order_relaxed);
}
};
class Task_Resource : Pinned {
@@ -206,6 +199,7 @@ private:
Task_Runtime_State state;
double_buffer::detail::State_Callback_Storage<Task_Runtime_State> state_callbacks;
std::recursive_mutex state_mutex;
std::atomic_bool state_callback_enabled{};
void create_executor(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface) {
executor = std::make_unique<tf::Executor>(workers, std::move(worker_interface));
observer = executor->make_observer<Task_Observer>();
@@ -218,6 +212,7 @@ private:
observer = executor->make_observer<Task_Observer>();
}
void publish_state() {
if (!state_callback_enabled.load(std::memory_order_acquire)) return;
std::lock_guard guard(state_mutex);
observer->write_state(state, executor->num_workers(), executor->num_topologies());
state.active_taskflow_count = active_taskflows.load(std::memory_order_relaxed);
@@ -248,7 +243,10 @@ public:
while (peak < active && !peak_active_taskflows.compare_exchange_weak(peak, active, std::memory_order_relaxed)) {}
auto start = std::chrono::steady_clock::now();
try {
executor->run(taskflow).get();
if (executor->this_worker())
executor->corun(taskflow);
else
executor->run(taskflow).get();
}
catch (...) {
active_taskflows.fetch_sub(1, std::memory_order_relaxed);
@@ -262,22 +260,46 @@ public:
publish_state();
return elapsed;
}
void run(tf::Taskflow& taskflow, std::function<void()> completion) {
if (!completion) throw std::invalid_argument("Taskflow completion is empty");
ensure_executor();
auto active = active_taskflows.fetch_add(1, std::memory_order_relaxed) + 1;
auto peak = peak_active_taskflows.load(std::memory_order_relaxed);
while (peak < active && !peak_active_taskflows.compare_exchange_weak(
peak, active, std::memory_order_relaxed)) {}
executor->run(taskflow, [this, completion = std::move(completion)]() mutable {
active_taskflows.fetch_sub(1, std::memory_order_relaxed);
completed_taskflows.fetch_add(1, std::memory_order_relaxed);
publish_state();
completion();
});
}
void schedule(std::function<void()> task) {
if (!task) throw std::invalid_argument("Taskflow scheduled task is empty");
ensure_executor();
executor->silent_async(std::move(task));
}
std::pmr::memory_resource* memory_resource() const noexcept {
return memory;
}
void set_state_callback(std::function<void(const Task_Runtime_State&)> callback) {
std::lock_guard guard(state_mutex);
state_callbacks.template set<Task_Runtime_State_Tag>(std::move(callback));
state_callback_enabled.store(true, std::memory_order_release);
}
void clear_state_callback() {
std::lock_guard guard(state_mutex);
state_callbacks.template clear<Task_Runtime_State_Tag>();
state_callback_enabled.store(false, std::memory_order_release);
}
};
}
void initialize_runtime(std::size_t workers, std::shared_ptr<tf::WorkerInterface> worker_interface, Pmr pmr) {
Task_Resource::instance().initialize(workers, std::move(worker_interface), pmr);
}
void schedule_task(std::function<void()> task) {
Task_Resource::instance().schedule(std::move(task));
}
namespace detail {
void set_runtime_state_callback_impl(std::function<void(const Task_Runtime_State&)> callback) {
Task_Resource::instance().set_state_callback(std::move(callback));
@@ -288,6 +310,9 @@ void clear_runtime_state_callback_impl() {
std::uint64_t run_taskflow(tf::Taskflow& taskflow) {
return Task_Resource::instance().run(taskflow);
}
void run_taskflow(tf::Taskflow& taskflow, std::function<void()> completion) {
Task_Resource::instance().run(taskflow, std::move(completion));
}
std::pmr::memory_resource* task_memory_resource() noexcept {
return Task_Resource::instance().memory_resource();
}
+2
View File
@@ -95,6 +95,8 @@ struct Task_Runtime_State : State_Type<Task_Runtime_State_Tag> {
void initialize_runtime(std::size_t workers = std::thread::hardware_concurrency(),
std::shared_ptr<tf::WorkerInterface> worker_interface = nullptr,
Pmr pmr = {});
/* 把独立业务任务提交给全局 Taskflow worker;任务不得执行阻塞式设备等待。 */
void schedule_task(std::function<void()> task);
/* 为全局 Taskflow 运行时状态注册回调;Tag 目前只接受 Task_Runtime_State_Tag。 */
template <std::same_as<Task_Runtime_State_Tag> Tag, std::invocable<const Task_Runtime_State&> Callback>
void set_runtime_state_callback(Callback&& callback);
+1 -2
View File
@@ -3,9 +3,8 @@ namespace aethera::detail {
void set_runtime_state_callback_impl(std::function<void(const Task_Runtime_State&)> callback);
void clear_runtime_state_callback_impl();
std::uint64_t run_taskflow(tf::Taskflow& taskflow);
void run_taskflow(tf::Taskflow& taskflow, std::function<void()> completion);
std::pmr::memory_resource* task_memory_resource() noexcept;
void observe_stage_entry(std::size_t task_hash, std::uint64_t now);
void observe_stage_exit(std::size_t task_hash, std::uint64_t now);
}
namespace aethera {
template <std::same_as<Task_Runtime_State_Tag> Tag, std::invocable<const Task_Runtime_State&> Callback>
+5 -73
View File
@@ -1,81 +1,13 @@
#include "renderable.hpp"
#include <mutex>
#include <unordered_map>
namespace aethera {
std::optional<double> Renderable::event_routing_distance(const Event& event) const {
const auto& data = static_cast<const Private&>(*d);
return data.event_routing_distance_run ? data.event_routing_distance_run(this, event) : std::nullopt;
}
namespace {
class Stage_Registry : Pinned {
private:
struct Binding {
const tf::Taskflow* owner;
Root* object;
Renderable::Private* data;
detail::Renderable_Stage stage;
detail::Stage_Observer_Point point;
};
std::unordered_map<std::size_t, Binding> bindings;
std::mutex mutex;
public:
void bind(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) {
std::lock_guard guard(mutex);
bindings.insert_or_assign(task_hash, Binding{owner, object, data, stage, point});
}
void clear(const tf::Taskflow* owner) {
std::lock_guard guard(mutex);
std::erase_if(
bindings,
[owner](const auto& value) {
return value.second.owner == owner;
}
);
}
void on_entry(std::size_t task_hash, std::uint64_t now) {
std::lock_guard guard(mutex);
auto current = bindings.find(task_hash);
if (current == bindings.end() || current->second.point != detail::Stage_Observer_Point::End) return;
auto& binding = current->second;
auto& state = *binding.data->dispatch->state.get(binding.object);
if (binding.stage == detail::Renderable_Stage::Prepare) {
if (state.prepare_executed) state.prepare_execution_time_ns = now - state.prepare_execution_time_ns;
}
else if (state.paint_executed) {
state.paint_execution_time_ns = now - state.paint_execution_time_ns;
}
}
void on_exit(std::size_t task_hash, std::uint64_t now) {
std::lock_guard guard(mutex);
auto current = bindings.find(task_hash);
if (current == bindings.end() || current->second.point != detail::Stage_Observer_Point::Begin) return;
auto& binding = current->second;
auto& state = *binding.data->dispatch->state.get(binding.object);
if (binding.stage == detail::Renderable_Stage::Prepare) {
state.prepare_execution_time_ns = state.prepare_executed ? now : 0;
}
else {
state.paint_execution_time_ns = state.paint_executed ? now : 0;
}
}
};
Stage_Registry& stage_registry() {
static Stage_Registry value;
return value;
}
}
namespace detail {
void observe_stage_entry(std::size_t task_hash, std::uint64_t now) {
stage_registry().on_entry(task_hash, now);
}
void observe_stage_exit(std::size_t task_hash, std::uint64_t now) {
stage_registry().on_exit(task_hash, now);
}
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point) {
stage_registry().bind(owner, task_hash, object, data, stage, point);
}
void clear_stage_observers(const tf::Taskflow* owner) {
stage_registry().clear(owner);
}
tf::Taskflow& Renderable::prepare_taskflow() {
return static_cast<Private&>(*d).prepare_extension;
}
tf::Taskflow& Renderable::paint_taskflow() {
return static_cast<Private&>(*d).paint_extension;
}
}
+10
View File
@@ -88,6 +88,16 @@ struct Renderable : Def<Renderable, Root> {
struct Private;
/* 返回该对象参与当前事件竞争时的几何距离;无值表示沿用普通绘制层级路由。 */
[[nodiscard]] std::optional<double> event_routing_distance(const Event& event) const;
/*
* 返回 Prepare 阶段完成后执行的直接 Taskflow 扩展端口。
* tf::Taskflow 只能在该 Renderable 所属 Scene 没有运行时修改;禁止在图执行期间 emplace/erase/clear。
*/
[[nodiscard]] tf::Taskflow& prepare_taskflow();
/*
* 返回 Paint 阶段完成后执行的直接 Taskflow 扩展端口。
* tf::Taskflow 只能在该 Renderable 所属 Scene 没有运行时修改;禁止在图执行期间 emplace/erase/clear。
*/
[[nodiscard]] tf::Taskflow& paint_taskflow();
private:
/* 数据模式的内部调度入口:执行最终对象 prepare_data(...),再触发各 CRTP 层 after_prepare_data(...)。 */
template <Prepare_Data_Renderable Object>
+12 -14
View File
@@ -25,8 +25,9 @@ struct Renderable::Private : Prev_Private {
Graph_Builder builder; /* 子图模式构建入口;数据模式为空。 */
};
struct State_Dispatch {
State_Get get; /* 获取最终对象的 Renderable 状态。 */
State_Notify notify; /* 发布最终对象的 Renderable 状态。 */
State_Get current; /* 读取已经发布的 Renderable 状态。 */
State_Get pending; /* 写入本阶段诊断,由完成节点统一交换发布。 */
State_Notify publish; /* 阶段完成后交换 State 双缓冲并发布稳定 current。 */
};
struct Dispatch {
Stage_Dispatch prepare; /* Prepare 阶段分派。 */
@@ -39,6 +40,8 @@ struct Renderable::Private : Prev_Private {
Color_Cache_Visit color_cache_visit{}; /* 最终对象存在 Color_Cache Buffer 时访问本轮写入结果。 */
std::unique_ptr<tf::Taskflow> prepare_graph; /* Prepare 子图模式的当前构建产物。 */
std::unique_ptr<tf::Taskflow> paint_graph; /* Paint 子图模式的当前构建产物。 */
tf::Taskflow prepare_extension{}; /* 外部直接续写的 Prepare 完成图;不参与内部子图重建。 */
tf::Taskflow paint_extension{}; /* 外部直接续写的 Paint 完成图;不参与内部子图重建。 */
bool prepare_graph_built{}; /* Prepare 子图是否至少成功构建过一次。 */
bool paint_graph_built{}; /* Paint 子图是否至少成功构建过一次。 */
/* CRTP 可覆盖:决定已选中子图模式的 Prepare 子图是否重建;object 为最终对象,state 为当前发布状态;默认返回 false。 */
@@ -190,6 +193,13 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
},
[](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
return static_cast<State*>(private_data.state.pending);
},
[](Root* root) {
auto* value = static_cast<Object*>(root);
auto& private_data = static_cast<typename Object::Private&>(*value->d);
private_data.state.advance();
value->template notify_state<Renderable::Base_Tag>();
}
}
@@ -197,16 +207,4 @@ inline void Renderable::bind_dependency_graph_object(Attached auto* object) {
data.dispatch = &dispatch;
object->template mark_dirty<Prepare_Data_Tag>();
}
namespace detail {
enum class Renderable_Stage {
Prepare,
Paint
};
enum class Stage_Observer_Point {
Begin,
End
};
void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point);
void clear_stage_observers(const tf::Taskflow* owner);
}
}
+1 -3
View File
@@ -1,7 +1,5 @@
#include "scene.hpp" /* 后端共有 Prepare Scene 实现。 */
namespace aethera {
Scene::Private::Private() = default;
Scene::Private::~Private() {
if (runtime && runtime->taskflow) detail::clear_stage_observers(runtime->taskflow.get());
}
Scene::Private::~Private() = default;
}
+27 -12
View File
@@ -1,5 +1,6 @@
#pragma once
#include <algorithm>
#include <chrono>
#include <span>
#include <unordered_map>
#include <unordered_set>
@@ -63,11 +64,12 @@ void Scene::Private::process(Object* object, Callback&& callback) requires std::
template <Attached Object, typename Callback>
void Scene::Private::process(Object* object, Render_Frame* frame, Callback&& callback) requires std::invocable<Callback, const Result&> {
auto& private_data = static_cast<typename Object::Private&>(*this);
auto& state = static_cast<State&>(*private_data.state.current);
auto& state = static_cast<State&>(*private_data.state.pending);
state.taskflow_execution_time_ns = 0;
if (frame) frame->mark(Frame_Trace_Marker::prepare_started);
if (runtime->taskflow && !runtime->taskflow->empty()) state.taskflow_execution_time_ns = detail::run_taskflow(*runtime->taskflow);
if (frame) frame->mark(Frame_Trace_Marker::prepare_finished);
private_data.state.advance();
object->template notify_state<Scene::Base_Tag>();
Result result;
std::invoke(std::forward<Callback>(callback), std::as_const(result));
@@ -79,7 +81,7 @@ void Scene::Private::after_advance(Object* object,
const Prop* current_prop,
State_Access<State> current_states) {
auto* resource = detail::task_memory_resource();
auto& scene_state = current_states.get<Scene::Base_Tag>();
auto& scene_state = pending_states.get<Scene::Base_Tag>();
scene_state.taskflow_rebuilt = false;
std::pmr::unordered_set<Root*> advanced_objects{resource};
advanced_objects.insert(object);
@@ -87,18 +89,20 @@ void Scene::Private::after_advance(Object* object,
[&](const Dependency_Graph& dependency_graph) {
dependency_graph.for_each(
[&](const Dependency_Graph::Node& node) {
if (advanced_objects.insert(node.object).second) node.object->advance_object();
if (advanced_objects.insert(node.object).second) {
node.object->advance_object();
}
}
);
}
);
auto prepare_dependencies = object->template current_dependency_graph<Prepare_Data_Tag>();
bool taskflow_dirty = !runtime->taskflow;
object->template access_pending_dependency_graph<Prepare_Data_Tag>(
[&](auto& prepare_state) { taskflow_dirty = taskflow_dirty || prepare_state.dirty(); });
if (!taskflow_dirty) return;
if (!runtime->taskflow) runtime->taskflow = std::make_unique<tf::Taskflow>();
auto& taskflow = *runtime->taskflow;
auto prepare_dependencies = object->template current_dependency_graph<Prepare_Data_Tag>();
std::pmr::unordered_set<Renderable*> renderables{resource};
prepare_dependencies.for_each_bound(
[&](Renderable* renderable, Renderable::Private&) {
@@ -106,7 +110,6 @@ void Scene::Private::after_advance(Object* object,
}
);
scene_state.renderable_count = renderables.size();
detail::clear_stage_observers(&taskflow);
taskflow.clear();
struct Stage_Tasks {
tf::Task prepare_entry; /* Prepare 条件任务,作为该阶段依赖入口。 */
@@ -119,7 +122,7 @@ void Scene::Private::after_advance(Object* object,
if (!data) continue;
auto* dispatch = data->dispatch;
auto prepare_if = taskflow.emplace([data, dispatch, root] {
auto& state = *dispatch->state.get(root);
auto& state = *dispatch->state.pending(root);
state.prepare_graph_rebuilt = false;
state.prepare_execution_time_ns = 0;
if (dispatch->prepare.builder) {
@@ -138,6 +141,11 @@ void Scene::Private::after_advance(Object* object,
bool dirty = root->template dirty<Prepare_Data_Tag>();
state.prepare_dirty = dirty;
state.prepare_executed = dispatch->prepare.predicate(root, dirty);
if (state.prepare_executed) {
state.prepare_execution_time_ns = static_cast<std::uint64_t>(
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count());
}
return state.prepare_executed ? 0 : 1;
}).name("renderable.prepare.condition");
tf::Task prepare_run;
@@ -150,15 +158,22 @@ void Scene::Private::after_advance(Object* object,
if (dispatch->prepare.run) dispatch->prepare.run(root);
}).name("renderable.prepare.data");
}
auto prepare_extension = taskflow.composed_of(data->prepare_extension)
.name("renderable.prepare.extension");
auto prepare_done = taskflow.emplace([dispatch, root] {
auto& state = *dispatch->state.get(root);
if (state.prepare_executed) root->template take_dirty<Prepare_Data_Tag>();
dispatch->state.notify(root);
auto& state = *dispatch->state.pending(root);
if (state.prepare_executed) {
root->template take_dirty<Prepare_Data_Tag>();
const auto finished = static_cast<std::uint64_t>(
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count());
state.prepare_execution_time_ns = finished - state.prepare_execution_time_ns;
}
dispatch->state.publish(root);
}).name("renderable.prepare.complete");
prepare_if.precede(prepare_run, prepare_done);
prepare_run.precede(prepare_done);
detail::bind_stage_observer(&taskflow, prepare_if.hash_value(), root, data, detail::Renderable_Stage::Prepare, detail::Stage_Observer_Point::Begin);
detail::bind_stage_observer(&taskflow, prepare_done.hash_value(), root, data, detail::Renderable_Stage::Prepare, detail::Stage_Observer_Point::End);
prepare_run.precede(prepare_extension);
prepare_extension.precede(prepare_done);
stage_tasks.emplace(root, Stage_Tasks{prepare_if, prepare_done});
}
auto connect_dependencies = [&](const auto& dependency_graph) {
+5
View File
@@ -93,16 +93,21 @@ TEST(renderable_capability, direct_stages_do_not_allocate_subgraphs) {
auto renderable = build_object<Direct>();
auto scene = build_object<Scene>();
add_renderable(*scene, renderable.get());
int prepare_extension_calls{};
renderable->prepare_taskflow().emplace(
[&] { ++prepare_extension_calls; }).name("test.prepare.extension");
scene->process([](const auto&) {});
auto& data = renderable->data_for_test();
auto& base = static_cast<aethera::Renderable::Private&>(data);
EXPECT_EQ(data.prepare_calls, 1);
EXPECT_EQ(data.paint_calls, 0);
EXPECT_EQ(prepare_extension_calls, 1);
EXPECT_EQ(base.prepare_graph, nullptr);
EXPECT_EQ(base.paint_graph, nullptr);
scene->process([](const auto&) {});
EXPECT_EQ(data.prepare_calls, 1);
EXPECT_EQ(data.paint_calls, 0);
EXPECT_EQ(prepare_extension_calls, 1);
}
TEST(renderable_capability, graph_stage_builds_lazily_and_rebuilds_inside_condition) {
aethera::initialize_runtime(2);