68 static_assert(Policy == WritePolicy::ReadOnly ||
69 Policy == WritePolicy::UniquePerChunk,
70 "auto-exec supports the parallel-phase write policies only");
73 using ResultHook = void (*)(
void* ctx,
OpHandle handle,
75 const Ack* ack)
noexcept;
78 : world_(&world), ops_(&ops), fn_(
static_cast<ChunkFn&&
>(fn)) {}
80 void reserve_operations(std::size_t count) {
81 channel_.reserve_operations(count);
82 scratch_.reserve_operations(count);
88 std::size_t threshold = 2)
noexcept {
90 parallel_threshold_ = threshold == 0 ? 1 : threshold;
93 void set_result_hook(
void* ctx, ResultHook hook)
noexcept {
108 return run_nonempty();
122 for (
const auto& operation : ops_->operations()) {
123 if (operation.write_policy != Policy) {
124 TESS_ASSERT_MSG(
false,
125 "auto-exec queue contains a mismatched write policy");
126 last_run_.status = AutoExecStatus::PolicyMismatch;
133 const auto& report = plan_operations(*world_, *ops_, plan_report_);
134 (void)record_plan_completions(report, channel_);
135 last_run_.planned_ops = report.planned_count();
136 last_run_.rejected_ops = report.failed_count();
138 auto produced_dirty = std::uint32_t{0};
139 if (!report.plan().empty()) {
140 const auto phases = plan_parallel_execution_phases(report.plan());
143 TESS_ASSERT(phases.ok());
144 last_run_.phases = phases.phases().size();
145 for (
const auto& phase : phases.phases()) {
146 const auto use_pool =
147 pool_ !=
nullptr && phase.operation_count() >= parallel_threshold_;
151 ++last_run_.pool_phases;
152 result = execute_phase_partitioned_dirty_with_results<Policy>(
153 *pool_, *world_, report.plan(), phase, scratch_, channel_,
154 [
this](
auto view, Ack& ack) { fn_(view, ack); });
157 result = execute_phase_partitioned_dirty_with_results<Policy>(
158 serial, *world_, report.plan(), phase, scratch_, channel_,
159 [
this](
auto view, Ack& ack) { fn_(view, ack); });
167 detail::merge_planned_dirty_after_exception(*world_, scratch_);
168 TESS_ASSERT(merged.status == PlannedDirtyMergeStatus::Merged);
169 last_run_.merged_dirty_chunks += merged.merged_chunk_count;
172 TESS_ASSERT(result.status == PlannedExecutionStatus::Executed);
173 last_run_.executed_chunks += result.chunk_count;
179 merged = merge_planned_dirty(*world_, scratch_);
184 const auto fallback =
185 detail::merge_planned_dirty_after_exception(*world_, scratch_);
186 TESS_ASSERT(fallback.status == PlannedDirtyMergeStatus::Merged);
187 last_run_.merged_dirty_chunks += fallback.merged_chunk_count;
190 TESS_ASSERT(merged.status == PlannedDirtyMergeStatus::Merged);
191 last_run_.merged_dirty_chunks += merged.merged_chunk_count;
193 for (
const auto& operation : report.plan().operations()) {
194 produced_dirty |= operation.field_access.dirty_mask;
196 last_run_.status = AutoExecStatus::Executed;
198 last_run_.status = report.operations().empty() ? AutoExecStatus::Idle
199 : AutoExecStatus::Executed;
206 if (hook_ !=
nullptr) {
207 last_run_.drained += channel_.drain_results(
209 const Ack* ack)
noexcept {
210 hook_(hook_ctx_, handle, completion, ack);
221 std::size_t parallel_threshold_ = 2;
224 ResultHook hook_ =
nullptr;
225 void* hook_ctx_ =
nullptr;
Supplies a task with the current tick, trigger bits, and work allowance.
Definition schedule.h:107