Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rules/common/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ legacy tradeoff, a reference path, or a known migration target.
- GPU reductions must not hide unbounded serial work in one thread. Use a
documented strategy and threshold where a unit-thread fallback is allowed.
- CPU threading policy has one source of truth per repository or runtime
object.
object. For Rust crates the placement design and its audit items are in
[`../rust/performance.md`](../rust/performance.md), "CPU Parallelism".

## Evidence

Expand Down
3 changes: 2 additions & 1 deletion rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ applicable workflow and language rules.
- [`rust/index.md`](rust/index.md): entry point; unsafe boundary, unit-test
organization, debug/enum hygiene.
- [`rust/performance.md`](rust/performance.md): allocation, slicing, linalg,
GPU kernels, uninitialized/scratch acquisition, build profiles, threading.
GPU kernels, uninitialized/scratch acquisition, build profiles, CPU
parallelism (the placement token and the spindle boundary, as audit items).
- [`rust/numerical.md`](rust/numerical.md): numerical correctness, AD
validation, typed-error classification.
- [`rust/build-artifacts.md`](rust/build-artifacts.md): where Cargo and compiler
Expand Down
62 changes: 50 additions & 12 deletions rules/rust/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,53 @@
- Add regression coverage for both contracts: the uninitialized path stays
unsafe or `MaybeUninit`-typed, and the zeroed path is safe.

## Threading Principles

- One repository source of truth for parallel thresholds (a declared policy
mechanism), not per-op copies of the same decision.
- Short-circuit to the serial kernel when the effective thread count is one.
- Library kernels must not reach for an ambient global thread pool outside the
declared policy mechanism. Non-provider parallel work executes within the
repository/runtime-owned execution context, so thread policy (including
one-thread serial execution) is decided at that single source of truth.
- Provider-owned threading (BLAS/OpenMP-style) is controlled by provider
variables documented per repository; library code must not derive its own
pool policy from an ambient runtime.
## CPU Parallelism

The design is
[`tensor4all-meta/docs/design/core-boundary-and-execution-ownership.md`](https://github.com/tensor4all/tensor4all-meta/blob/main/docs/design/core-boundary-and-execution-ownership.md),
section "Where placement is decided" (its rules 1 to 13 and "faer and spindle"),
with the walkthroughs
[`cpu-placement-token.md`](https://github.com/tensor4all/tensor4all-meta/blob/main/docs/design/cpu-placement-token.md)
and [`spindle.md`](https://github.com/tensor4all/tensor4all-meta/blob/main/docs/design/spindle.md).
The design is the source of truth; the items below are what an audit checks.
They apply to code that runs on `strided_exec::Exec`. In a repository not yet
migrated to it, report each departure as a migration gap with its location,
not as a defect.

- **Fan-out only through the token.** Outside `strided-exec`, no crate calls
`rayon::scope`, `join`, `spawn`, `par_iter` / `par_chunks`,
`ThreadPool::install`, or, in kernel crates, `std::thread::spawn` /
`scope`. Check: `cargo deny` bans `rayon` except through the listed
wrappers, and clippy `disallowed-methods` lists the thread calls.
- **No ambient pool.** A serial token runs on the calling thread and nothing
falls back to the global Rayon pool. Check: each consumer keeps a
`strided_exec::ledger::global_pool_unstarted()` test in its own process.
- **Decide before entering.** Choose `jobs` and `grain` from `budget()` and
run a budget of one inline; never enter a pool to find out whether
parallelism pays.
- **Budgets only shrink.** A token is not cloned or stored in plans and caches,
a callee does not re-derive or raise a budget, and a split hands each child
a token whose budgets add up to the parent's (`fork`, `for_ranges`,
narrowing with `limit`, sequential phases with `reborrow`).
- **One source of truth for policy.** Parallel thresholds, `WorkModel` and
`BatchPolicy` live once, in the provider crate; per-op copies of the same
decision are a finding, and policy code starts no tasks.
- **Vendor libraries through `Exec::external`.** faer and vendor BLAS receive a
plain width from `external`; no adapter derives a pool or thread count from
an ambient runtime. BLAS/OpenMP worker teams stay provider-controlled and
are documented per repository.
- **spindle stays inside t4a-faer.** No other crate depends on spindle or opens
a `with_lock` region (check: `cargo deny` with `wrappers` listing only
`t4a-faer`). A batched caller such as tlinalg gives every slot to the batch
with `Par::Seq` items when the batch is at least the budget, and otherwise
forks the token with one `external` per item. Inside t4a-faer, every
parallel kernel reachable from a region dispatches through spindle; plain
Rayon code there runs on one thread.
- **No Rayon type in a public signature.** Check: `cargo public-api` of
`strided-exec`, `tcontract-exec` and `tenferro-cpu` contains no `rayon::`.
- **Barrier-bearing kernels use `broadcast`.** A refusal takes the
barrier-free path; the participant count is never clamped silently.
- **Concurrency claims need the ledger.** A claim that work stays within a
budget is shown with the `strided-exec` ledger's peak at the root token, or,
inside faer or a vendor library, measured at the kernel boundary. A worker
index or a pool size is not evidence.
2 changes: 2 additions & 0 deletions skills/tensor4all-rules-audit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ An audit request does not by itself authorize implementation, issues or PRs.
files. Read applicable rules and referenced decisions, not the entire workspace
by default. A local or uncommitted target is valid; describe it accurately.
Do not require a push or a GitHub-visible commit to inspect local work.
Code that fans out on the CPU (Rayon, `strided-exec`, faer, spindle) is
audited against `rules/rust/performance.md`, "CPU Parallelism".
2. **Inspect the real path.** Read enough source to understand the contract,
callers and existing checks. Use existing API documentation when helpful;
do not build release-mode documentation as a default audit prerequisite.
Expand Down
Loading