Skip to content

feat: add JET/BenchmarkTools performance verification#373

Merged
ocots merged 1 commit into
mainfrom
feat/performance-verification
Jul 13, 2026
Merged

feat: add JET/BenchmarkTools performance verification#373
ocots merged 1 commit into
mainfrom
feat/performance-verification

Conversation

@ocots

@ocots ocots commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Brings CTModels.jl's performance-verification setup in line with the control-toolbox Handbook's practice (hot path vs. setup path), already deployed in CTBase.

  • test/suite/meta/test_code_quality.jl (renamed from test_aqua.jl): keeps Aqua checks, adds JET.@test_opt guards on hot-path calls — time-function functors (ConstantInTime, CoercedTrajectory), dual-by-label functors (DualSlice, BoxDualDiff), the box-projection functor (BoxProjection), and component accessors.
  • test/suite/meta/test_performance.jl (new): BenchmarkTools.@ballocated allocation guards — zero-overhead wrapper checks (wrapper allocation == raw allocation) and zero-allocation reads.
  • Test.@inferred guards added next to their existing fixtures in test_components.jl, test_dual_model.jl, and test_model.jl.
  • docs/src/guide/performance.md (new): guide page with live JET.@report_opt checks executed at doc-build time, wired into the nav.
  • Project.toml/docs/Project.toml: JET and BenchmarkTools added test-only (never [deps]).

Design note: no whole-package JET.test_package gate

A one-off JET.report_package scan found 46 "possible errors," all originating from the mutable PreModel builder, whose fields are Union{T,Nothing} by design (filled in incrementally, validated with precondition checks before being read). JET's union-split analysis flags these as unreachable-in-practice branches — setup-path noise per the Handbook's own guidance, not hot-path regressions. Rather than hardening working setup-path code purely to satisfy the analyzer, or gating CI on known false positives, JET is applied precisely where it matters: @test_opt on concrete hot-path calls. report_package remains available as a documented, manual diagnostic.

Side fix

Triaging the scan surfaced one real (if unreachable-via-the-public-API) gap: PreModel was missing control_dimension/variable_dimension methods — only state_dimension existed. Added both, mirroring state_dimension's pattern, so Init code dispatching on Models.AbstractModel doesn't hit a stray MethodError if ever called with a PreModel.

Test plan

  • JET.report_package(CTModels) scan run and triaged by hand (46 findings, all setup-path false positives, zero in the hot path)
  • test/suite/meta/test_code_quality.jl — 20/20 passing (Aqua + JET.@test_opt)
  • test/suite/meta/test_performance.jl — 12/12 passing (@ballocated guards)
  • Full test suite — 4036/4036 passing
  • julia --project=docs docs/make.jl — build succeeds; all 4 JET.@report_opt blocks in performance.md render No errors detected

🤖 Generated with Claude Code

Mirrors the control-toolbox Handbook's performance-verification practice
(hot path vs. setup path) already deployed in CTBase:

- test/suite/meta/test_code_quality.jl (renamed from test_aqua.jl): keeps
  Aqua checks and adds JET.@test_opt guards on hot-path calls (time-function
  functors, dual-by-label functors, box-projection functor, component
  accessors). A whole-package JET.test_package scan was deliberately not
  wired in as a gate: CTModels' mutable PreModel builder has Union{T,Nothing}
  fields by design, and report_package's union-split analysis flags ~40
  unreachable branches there — setup-path noise, not hot-path regressions.
- test/suite/meta/test_performance.jl (new): BenchmarkTools.@ballocated
  allocation guards — zero-overhead wrapper checks and zero-allocation reads.
- Test.@inferred guards added next to their fixtures in
  test_components.jl, test_dual_model.jl and test_model.jl.
- docs/src/guide/performance.md (new): guide with live JET.@report_opt
  checks executed at doc-build time, wired into the nav.

Also fixes a real gap surfaced while triaging the JET scan: PreModel was
missing control_dimension/variable_dimension methods (only state_dimension
existed), so Init code dispatching generically on Models.AbstractModel could
hit a MethodError if ever called with a PreModel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ocots
ocots merged commit d418f5a into main Jul 13, 2026
6 checks passed
@ocots
ocots deleted the feat/performance-verification branch July 13, 2026 16:15
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.

1 participant