Fixed-rate graphs: timer, Versioned history, yield points, default priority - #2
Merged
Merged
Conversation
…iority A subsystem on its own clock becomes a second compiled graph beside the frame graph, bounded by a Deferred for inputs and a Versioned for outputs. The library supplies the mechanisms; the composition stays in samples. - ts/timer.h, src/timer.cpp: ts::sleep, ts::sleep_until and ts::Periodic. One lazily created timer thread with a min-heap delivers each wakeup as a task at the sleep's priority, never inline. Cancellation settles promptly. An armed sleep holds an External_wait. On Windows the thread waits on a high-resolution waitable timer. Worker-less mode is fatal, and destroy_scheduler stops the thread first (a live sleep is fatal under TS_SAFETY_CHECKS). - Versioned<T, History::current_and_previous>: a third replica rotated at the swap, publish stamps, copy resync by default (replay is a construction fatal). read_last_versions() returns a Version_view, the read grant, lent when the context already grants the front; co_await ts::read_last_versions(v) is the awaitable form. Access_awaiter's resume bookkeeping is factored into finish_acquire(). - ts::yield(): when a high task is queued, runs it inline on the yielding worker's stack under a scope that resets the thread's task state, then returns. One relaxed load otherwise. parallel_for yields at every chunk claim, and the trace excludes the nested span from the yielding body's time. - Static_task_graph::set_default_priority. - sample/fixed_rate.cpp (--fixed-rate [n]) and game_frame's fixed_rate variant: physics on a 60 Hz graph and networking on a 30 Hz graph beside the frame, with a third --trace SVG and --bench rows. Tests: a timer group, plus versioned, yield, parallel_for, graph and integration additions, and a death scenario for each new fatal. Negative checks were done for the yield path, the rotation and the External_wait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QTtvN1mH7K6MWzpYiyJ88w
- guide.md: 6.6 fixed-rate graphs, 10.6 timers, yield points in 10.1 and 7, the previous-version history in 9.2, set_default_priority, tool-table rows, and two limitations. - design.md: yield points and the timer thread in 3, the history rotation in 6, and 6.1 on fixed-rate graphs as the logical-execution-time model. - example-frame-optimization.md 5.1: the fixed-rate variant measured against the baseline and optimised frames. It is neutral on frame time because the optimised frame is already core-bound. - Status updates in TODO 2.11, the timer design study, pattern-farming 2.2, the two read_pair mentions, CLAUDE.md and show_graph.bat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QTtvN1mH7K6MWzpYiyJ88w
…ation timer Yield points - `detail::yield_signal`: the queued `high` and global-`normal` counts, alone on one cache line; incremented before a global push, decremented after every global pop. Local-deque pushes stay uncounted. - `yield_to_higher` runs one entry of a higher class: `normal` -> `high`; `low` -> `high`, then the global `normal` queue; `high` never yields. - The nested dispatch detaches the resume and inline-dispatch trampolines (by value, out of line, a spare buffer keeps the nested drain allocation-free) and reattaches them afterwards, so a coroutine or inline node the nested task releases runs at the yield point, also inside a resumed segment or an inline drain. `Yield_nesting` makes yield points inside the nested task no-ops (one level deep). Timer - A wait is one `Timed_executable` block: `Executable` plus the timer bookkeeping. A fire or a cancel submits that block itself; a passed deadline or a requested token runs it in the call. `Periodic::next` is no longer a coroutine. - mem_profile rows for sleep and `Periodic::next`; TODO 4.9 for allocation-free ticks. Versioned - Document `Version_view`'s access-context contribution (one or two entries). Samples and tests - fixed_rate checks the version stamps and that the clock kept up with the grid. - The engine fixed-rate test runs 60 frames and checks both clocks ticked. - New tests: low yields to normal, normal does not yield to normal, a resume caused at a yield point runs there, an inline node released at a yield point runs there, no nested yielding; TSan stage `yield resumes`. Docs: guide 7, 9.2, 10.1, 10.6, 13; design 3 (yield points, timer thread); the timer design status; TODO; CLAUDE.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QTtvN1mH7K6MWzpYiyJ88w
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A subsystem on its own clock becomes a second compiled graph beside the frame graph, bounded by a
Deferredfor inputs and aVersionedfor outputs. The library supplies the mechanisms; the composition lives in samples (guide §6.6, design §6.1).ts/timer.h):ts::sleep,ts::sleep_until,ts::Periodic. One timer thread; wakeups are delivered as tasks, never inline; high-resolution waitable timer on Windows.Versioned<T, History::current_and_previous>: keeps the previous version;auto [previous, current, stamps] = v.read_last_versions(), orco_await ts::read_last_versions(v).ts::yield(): runs a queuedhightask inline on the yielding worker's stack;parallel_foryields between chunks.Static_task_graph::set_default_priority.sample/fixed_rate.cpp(--fixed-rate), andgame_frame'sfixed_ratevariant (physics at 60 Hz, networking at 30 Hz), with a third--traceSVG and--benchrows.Local verification: Release suite 3/3 clean on 2 workers; CMake
windows-msvc913 checks andwindows-shipping720 checks, 0 failures; pre-push TSan clean; negative checks for the yield path, the history rotation, and the timer's deadlock-net registration.The fixed-rate variant is neutral on frame time (17.12 ms vs 16.93 ms optimised, 8 workers), because the optimised frame is already core-bound; its gain there is structural.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QTtvN1mH7K6MWzpYiyJ88w