pragma.core
pragma.core is a pure-Rust, solid and high-performance multithreaded core for razed.production's game engines and frameworks.
It is the layer under an engine: it owns the threads, schedules the work of a frame and runs background I/O, so that ECS, rendering, physics and audio can be written on top of it without each inventing their own thread pool.
Status
0.6.0 — feature-complete for 1.0, public API reviewed. Milestones M0–M5 are done: the work-stealing job system, the per-frame task graph, async tasks, observability, tuning and the hardening pass (determinism suite, benchmark gate and semver checks in CI). M6 is in progress: the 1.0 API review, the move of all documentation to English and the MSRV and versioning policy, and complete rustdoc with examples and an embedding checklist are done; the crates.io release is next. Until 1.0, minor versions may break the API; every break is listed in the changelog. See the roadmap.
Features
| Area | Crate | Facade |
|---|---|---|
Typed errors, generational handles (Handle, HandlePool), simulation ticks |
pragma_base |
base |
| Sync primitives: latches, counters, task labels (plus the scheduler's internal building blocks) | pragma_sync |
sync |
| Platform layer: thread names, priorities, core affinity (Windows/Linux) | pragma_sys |
sys |
Work-stealing pool: join, scope, spawn, parallel_for, parallel_reduce, priorities |
pragma_jobs |
jobs |
| Per-frame task graph with declared resource access, validated before the first frame | pragma_graph |
graph |
| Async tasks on the pool, bounded blocking pool for synchronous I/O | pragma_async |
tasks |
| Vertical slice: 100k entities, 9-system graph, background load, per-tick state hash | examples/frame_sim |
— |
Highlights:
- Help-while-wait. Every wait (
join,scope,JobHandle::join) runs other jobs, so nested parallelism never deadlocks, even on a single worker. - Panics are errors. A panicking job, graph task or future returns
JobError::Panicked/AsyncError::Panicked; the worker survives and nothing hangs. - Conflicts are caught at build time. A graph whose tasks touch the same resource
without an explicit order fails in
build()withGraphError::AmbiguousOrder. It cannot become a data race in frame 10 000. - Allocation-free frames. After the warm-up frame, a 50-task graph runs with zero heap
allocations, with or without a
tracingsubscriber. - Deterministic. Results do not depend on which thread ran what:
frame_simproduces the same per-tick hash on 1, 2 and N workers, and CI checks this on every PR. - Observable.
PoolStatssnapshots,tracingspans, optionalpuffinscopes, a debug-only watchdog for stuck jobs, and an allocation-free "which task is running here" query for panic hooks and crash reports. - Bounded memory. Input-sized allocations go through
try_reserveor a hard limit: you getGraphError::TooLarge/BaseError::OutOfMemoryinstead of an abort.
Quick look
use *;
;
;
More examples are in the crate docs (cargo doc --open -p pragma_core) and in
examples/frame_sim.
Using it
pragma.core is not on crates.io yet (planned for 1.0). Depend on it via git:
[]
= { = "https://github.com/razedproduction/pragma.core" }
| Feature | Default | Enables |
|---|---|---|
jobs |
✅ | ThreadPool and the platform layer (sys) |
graph |
✅ | FrameGraph, Resources (implies jobs) |
async |
✅ | Executor, AsyncHandle (implies jobs) |
puffin |
— | Profiler scopes for pool operations and graph tasks; re-exports puffin |
base and sync are always available. Each feature builds and passes clippy on its own
(cargo hack --each-feature in CI).
MSRV policy
The minimum supported Rust version is 1.88 (rust-version in [workspace.package],
DECISIONS #10), the minimum required by proptest.
- Checked in CI. The
MSRV (1.88)job runscargo +1.88 check --workspace --all-featureson every PR and every push tomain. Development itself uses the toolchain pinned inrust-toolchain.toml(1.99.0), so lints are identical locally and in CI. - Raised only in a minor release. A higher MSRV is not treated as a breaking change, but
it never ships in a patch release: it goes into the next minor version (
1.x.0;0.x.0before 1.0), with its own line in the changelog and a decision record explaining why (DECISIONS #44). - One change, three places.
rust-version, the CImsrvjob and the badge above move together in the same PR.
Versioning
pragma.core follows SemVer; the rules are in docs/reliability.md §8.
- Lockstep. All crates share one version (
versionin[workspace.package], currently 0.6.0): thepragma_corefacade exposes all of them, so separate versions would give users nothing (DECISIONS #33). A breaking change in any crate is a breaking release of all of them. - Exact internal dependencies. The crates depend on each other with
=X.Y.Z, sopragma_jobs1.0.0 never builds against apragma_sync1.0.1 whose internals have moved (DECISIONS #42). Depend onpragma_core, or keep allpragma_*crates at the same version. - Outside semver. No compatibility guarantees cover:
pragma_sync::__private(hidden from the docs): the scheduler's building blocks, which change with every optimization ofjoin/scope;- the
puffinfeature and thepragma_core::puffinre-export:puffinis not 1.0 yet, and moving to a newpuffinversion is a minor release.
- Breaking changes. Before 1.0, a minor version (
0.x.0) may break the API, and every break is listed in the changelog. After 1.0, breaks happen only in a major release; an item is first marked#[deprecated(since, note)]for at least one minor release. - Checked in CI.
cargo semver-checks --workspaceruns on every PR against the PR's base onmain(not against crates.io or a tag): a breaking change that comes without a version bump fails the PR that introduces it.
Performance
Windows 10, AMD FX-8350 (8 logical cores), cargo bench. Ranges are min…max across A/B
rounds. Full method and numbers are in docs/perf.md.
| Benchmark | pragma.core | rayon |
|---|---|---|
single join |
284…288 ns | 1.47…1.51 µs |
fib(20), ~11k nested join |
197…200 µs | 99…108 µs |
parallel_for, 10⁶ elements |
454…478 µs | 477…508 µs |
parallel_reduce, 10⁶ elements |
198…214 µs | 230…282 µs |
| frame graph, 50 near-empty tasks | 8.3…8.4 µs per frame | — |
frame_sim, 100k entities |
~5 ms/tick on 1 worker, ~2 ms on 11 | — |
Nested fork-join is the one place where rayon is still ahead (about 2×). A CI gate fails any PR that regresses a benchmark by more than 10% beyond runner noise.
Reliability
Reliability here is a set of properties that CI checks on every PR. Details are in docs/reliability.md.
- Pure Rust. No C/C++ compiled into the dependency tree; enforced by
cargo denyandtools/audit_workspace.py. System FFI (windows-sys,libc) only. - No panics in the runtime.
unwrap/expect/panic!/unchecked indexing are denied by lints; failures are#[non_exhaustive]typed errors with context. - Contained
unsafe. Only inpragma_sync(lifetime erasure, on-stack jobs, task labels) andpragma_sys(OS calls). Every occurrence has a budget inlayers.toml; any growth needs a new decision record. All of it is reviewed in docs/unsafe.md. - Verified concurrency. Every atomic protocol has a loom model.
pragma_syncruns under Miri, and a one-worker pool runs under Miri with Tree Borrows. - Tested in depth. Unit, property (
proptest) and stress tests, plus fuzzing of the graph builder against an independent oracle. Nightly CI runs 30-minute fuzzing and soak tests. - Layered. Each crate depends only on lower layers (
layers.toml):
L4 pragma_core facade: re-exports, prelude, features
L3 pragma_graph frame graph pragma_async async tasks
L2 pragma_jobs work-stealing pool
L1 pragma_sync sync primitives pragma_sys platform layer
L0 pragma_base errors, handles, ticks
Platforms
Windows and Linux (x86_64) are first-class and tested in CI. Other targets are not supported yet; the API does not rule out a single-threaded mode for wasm later. See DECISIONS.md.
Building
The toolchain is pinned in rust-toolchain.toml (1.99.0); the minimum supported Rust version
is 1.88 (MSRV policy). See CONTRIBUTING.md for the full check list (Miri, loom, fuzz, benches).
Documentation
- API reference:
cargo doc --open -p pragma_core(docs.rs after the crates.io release). Every public type and free function has an example; the crate page ofpragma_corehas the section "Integrating into an engine": pool ownership, the graph in the game loop, async results, priorities, panics, shutdown order and determinism - Architecture: layers and the execution model
- Reliability rules
- Performance methodology and results
unsafereview- Roadmap
- Decision log
- Changelog
- Contributing
License
MIT © 2026 razed