Skip to content

[Caspar] Scope expr_map across parameter output blocks to prevent cross-barrier CSE leakage - #474

Closed
sarlinpe wants to merge 1 commit into
symforce-org:mainfrom
sarlinpe:caspar-scope-expr-map-per-group
Closed

sarlinpe wants to merge 1 commit into
symforce-org:mainfrom
sarlinpe:caspar-scope-expr-map-per-group

Conversation

@sarlinpe

@sarlinpe sarlinpe commented Oct 2, 2026

Copy link
Copy Markdown

Summary

Caspar factor kernels generate outputs in distinct mathematical blocks separated by shared-memory reductions (FlushSumShared) and warp synchronizations:

  1. Residuals (out_res, out_rTr)
  2. Pose block (out_pose_jac, out_pose_njtr, out_pose_precond_*)
  3. Calibration block (out_calib_jac, out_calib_njtr, out_calib_precond_*)
  4. Point block (out_point_jac, out_point_njtr, out_point_precond_*)

Currently, a single flat expr_map is shared across all outputs. Common subexpressions are reused globally without barrier awareness. For example, in a SimpleRadial factor, calib_factor = -1.0 * (1 + k*r^2) was first computed during out_pose_jac into r54 and reused 350 lines later during out_calib_njtr across 12 FlushSumShared calls.

Under __launch_bounds__(1024, 1) in double precision, this 350-line cross-barrier live range triggered massive register spilling and stack slot clobbering in NVCC, causing calibration derivatives to diverge in COLMAP (see colmap/colmap#4799).

This PR scopes expr_map per output parameter group:

  • base_expr_map stores read input symbols (camera pose, calibration parameters, 3D points, 2D pixels).
  • When transitioning across output parameter blocks (e.g. pose -> calib -> point), expr_map is reset to base_expr_map.

This preserves full CSE within each parameter block while preventing intermediate derivative expressions from leaking across reduction barriers into subsequent parameter blocks.

Test Plan

@sarlinpe

sarlinpe commented Oct 2, 2026 •

Copy link
Copy Markdown
Author

Closing this PR: string-matching output name suffixes in dabseg_from_accessors.py is overly specific to factor output naming conventions, and furthermore do_cpse in the DAG optimizer undoes the scoping by deduplicating identical expressions globally across the entire DAG. A proper upstream solution should make the DAG optimizer / register scheduler barrier-aware.

@sarlinpe sarlinpe closed this Oct 2, 2026
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