Skip to content

Callback-array parallel safety: remaining exposures after #376 (swarm.points callback, delayed-callback replay, central guard) #379

Description

@lmoresi

Follow-up to #376 (fixed in #378). The root cause there — NDArray_With_Callback.__array_finalize__ hands the sync callbacks to every array derived by indexing, so callbacks written for the canonical storage fire on views and temporary copies — is more general than the two canonical callbacks that were fixed. The historical disable_inplace_operators=True blocking on swarm.points ("disabled for parallel safety", af308d8, Sept 2025) was a symptom-level mitigation of the same disease. Four remaining items, none blocking #378:

1. swarm.points / swarm_update_callback still has the disease, plus a worse one

  • The callback calls collective migrate() from inside a per-write callback — the exact pattern the swarm variable canonical callback was rewritten to avoid (SWARM-03 deferred migration) — and raises RuntimeError rank-locally on a size mismatch. Ranks that write unevenly diverge on collectives.
  • The in-place blocking only covers the i-operators; __setitem__ on a derived fancy-indexed copy still fires the callback.
  • The documented example in migration_control()'s own docstring raises today (verified):
with swarm.migration_control():
    swarm.points[mask1] += delta1
# RuntimeError: In-place addition (+=) is disabled for parallel safety.

The disable_inplace_operators flag propagates to the fancy copy via __array_finalize__, so the advertised pattern is simply broken. .points is already deprecated in favour of swarm variables — either port it to the guarded-callback + deferred-migration pattern (after which the blocking flag can be dropped and the docstring becomes true), or accelerate its retirement.

2. Delayed-callback replay is rank-asymmetric by construction

delay_callback / uw.delay_callbacks_global queue (callback, array, context) per rank and replay them between blanket barriers at context exit. Queue lengths and contents are rank-dependent (each rank queues what it locally triggered) while the callbacks contain collectives — the barriers around the batch cannot fix mismatched collectives inside it. Per-item exceptions are swallowed with logger.warning (the same swallow that hid #376 for ten months). The robust shape already exists in the codebase: the swarm canonical callback's _pending_petsc_sync marks variables dirty by NAME and flushes collectively at context exit. The delay machinery should do the same — flush dirty variables canonically, not replay rank-local event queues.

3. The #376 guard lives in two closures, not the class

Any future add_callback user re-inherits the trap. Add e.g. add_canonical_callback() on NDArray_With_Callback that applies the base-chain identity guard (view → sync canonical; copy → skip, the parent __setitem__ does the real sync) once, centrally, so the safe pattern is the default. Migrate the three existing registration sites (mesh variable, swarm variable, swarm.points) onto it.

4. Adjacent, lower severity

  • Silent-bypass writes: np.add(x, 1, out=x), .fill(), np.copyto mutate without any callback → values land (the canonical wraps the vec memory) but ghost sync and the state increment don't happen — stale ghosts/caches rather than hangs.
  • Every in-place op copies the entire array as old_value for callbacks that never read it — pure memory/bandwidth waste on large variables.

Context and verification details: PR #378 review discussion; the guard semantics (identity in numpy's base chain, NOT np.may_share_memory, which is False for any zero-size array and re-creates the rank asymmetry on empty ranks) are documented in the fixed callbacks in discretisation_mesh_variables.py and swarm.py.

Underworld development team with AI support from Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions