Skip to content

[Data oriented] Add template_primitives parameter default True#789

Merged
hughperkins merged 23 commits into
mainfrom
hp/data-oriented-template-primitives
Jul 21, 2026
Merged

[Data oriented] Add template_primitives parameter default True#789
hughperkins merged 23 commits into
mainfrom
hp/data-oriented-template-primitives

Conversation

@hughperkins

Copy link
Copy Markdown
Collaborator

Issue: #

Brief Summary

copilot:summary

Walkthrough

copilot:walkthrough

Make @qd.data_oriented a dual-form decorator that accepts a
template_primitives keyword (default True, unchanged behaviour). When set
False on a class, its primitive members reached through a kernel template
arg should be lifted to runtime kernel args rather than baked. Adds the
wants_runtime_primitives() metaclass-safe MRO helper that reads the flag.
…ntime args

Implement the runtime lifting for @qd.data_oriented(template_primitives=False)
template args, mirroring the existing ndarray-member path:

- _predeclare_struct_primitives walks the reachable attribute graph of a
  flagged template arg, builds a provenance map keyed by (id(parent), attr),
  and (in the enforcing pass) declares a scalar kernel arg per primitive the
  body actually accesses, inferring dtype from default_ip / default_fp.
- build_Attribute returns the arg-load Expr for a lifted primitive instead of
  baking getattr; in the discovery pass it marks the access used (pruning), and
  it raises QuadrantsSyntaxError if a lifted primitive is used inside qd.static.
- Pruning rides the existing two-pass __qd_-name used-set machinery (tracked
  under KERNEL_FUNC_ID so it also serialises through fastcache), so only
  accessed primitives become kernel args (avoids MAX_ARG_NUM blowup).
- launch_kernel binds live primitive values via _set_struct_primitive_args and
  marks the launch context non-cacheable (values change between launches).

The spec key is unchanged (weakref.ref per instance), so mutating a lifted
primitive never triggers recompilation.
…mitives

Cover int/float/bool mutation without recompile, signed ints, nested
dataclass / data_oriented members, self-method kernels, pruning (600 unused
members compile fine), the qd.static hard error, the opt-in boundary (default
still bakes), fastcache/pure, and distinct instances.
…tives

Add a "Runtime primitives" subsection to the compound-types user guide
covering the opt-in flag, dtype defaults, pruning, the qd.static restriction,
and no-recompile-on-mutation semantics.
…e in fastcache

The fastcache args hasher walked every @qd.data_oriented child as a baked
template primitive, folding the value into the cache key. For a class declared
template_primitives=False the primitives are lifted to runtime scalar args, so
baking the value made fastcache recompile/restore a new entry on every value
change — defeating the feature. Walk such objects' children with a non-Template
arg_meta so primitive members contribute type only (field children still warn
and disable fastcache). Add regression tests and document the exception.
The template_primitives=False feature stored a (possibly empty) launch-info
entry for every materialized kernel and unconditionally did a tuple-keyed
``self._struct_primitive_launch_info_by_key.get(key)`` on every cache-missing
launch. That hashed the kernel key on the launch hot path for ALL kernels, even
the overwhelming majority that don't lift primitives, costing ~0.5us/launch.
For CPU / unbatched genesis steps -- which are dominated by many tiny
cache-missing kernel launches -- this showed up as a ~2-3% runtime regression.

Only record an entry when a kernel actually lifts primitives (keeping the dict
empty otherwise) and guard the launch-path block with a cheap empty-dict check,
so kernels without lifted primitives skip the work entirely. Verified on a
dedicated node: orig was +3.3%/launch over main, fixed is back to main within
noise. template_primitives correctness unchanged (tests + engine E/F mirrors).
@hughperkins
hughperkins marked this pull request as ready for review July 17, 2026 15:42
@hughperkins

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: ee7076ad8b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@hughperkins

Copy link
Copy Markdown
Collaborator Author

Genesis benchmarks look ok:

20260717_templprim_1143

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@hughperkins hughperkins removed the awaiting-ci-to-pass awaiting-ci-to-pass label Jul 20, 2026
@hughperkins

Copy link
Copy Markdown
Collaborator Author

Genesis benchmarks at this point looking ok:

20260720_template_prim_0903

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@alanray-tech

alanray-tech commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

The documents LGTM. Agents can figure out what I need easily.

It's good to have a precise and mathematical definition of "pure kernel" and "capture behaviour" in the future, because auto-passing data_oriented class member parameters look like capture behaviour(though not) it achieves from the compound types of the class member tree. So I will get a little bit stuck when I read this part

Fastcache requires the kernel to be pure: all data it operates on must be passed as explicit parameters, with nothing captured from the enclosing Python scope

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@hughperkins

Copy link
Copy Markdown
Collaborator Author

Genesis unit tests passing:

Screenshot 2026-07-20 at 11 27 12

@github-actions

Copy link
Copy Markdown

@hughperkins hughperkins added awaiting review pass New PR or review comments addressed and removed need-genesis-unit-tests labels Jul 20, 2026
@github-actions

Copy link
Copy Markdown

@alanray-tech

Copy link
Copy Markdown
Collaborator

The new document looks perfect to me now

@duburcqa

Copy link
Copy Markdown
Contributor

ok to merge

@duburcqa duburcqa removed the awaiting review pass New PR or review comments addressed label Jul 21, 2026
@hughperkins
hughperkins merged commit b1847ea into main Jul 21, 2026
58 checks passed
@hughperkins
hughperkins deleted the hp/data-oriented-template-primitives branch July 21, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants