Skip to content

perf: scale FabricFrameView selections to the view, not the stage - #6805

Open
pv-nvidia wants to merge 22 commits into
isaac-sim:developfrom
pv-nvidia:pv/fix-fabric-frameview-stall
Open

perf: scale FabricFrameView selections to the view, not the stage#6805
pv-nvidia wants to merge 22 commits into
isaac-sim:developfrom
pv-nvidia:pv/fix-fabric-frameview-stall

Conversation

@pv-nvidia

@pv-nvidia pv-nvidia commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description

Camera world-pose resolution stalled at high environment counts on the PhysX backend, badly enough to time out benchmarks. There are two independent bottlenecks; the PR also adds a lifecycle hook that came out of review.

1. FabricFrameView resolved prim paths on the host, against the whole stage

Cameras read their poses from Fabric. To do that the frame view needs to know where each camera's data sits in Fabric memory, so it builds a lookup table from "camera number" to "Fabric slot".

Building that table was very slow. The view selected prims by requiring the Fabric world and local matrix attributes — but every xformable in the stage carries those, so the selection matched the entire stage (~1.1M prims at 8192 environments), not the view's handful of cameras. Finding its own prims in that list then meant building a Python dictionary over all of it, on the host:

path_to_idx = {str(p): i for i, p in enumerate(selection.GetPaths())}

That ran twice per rebuild (once for the children, once for their parents), and rebuilt whenever PrepareForReuse() reported a bucket change — in practice on every environment reset.

The cost of that dictionary scales with the size of the whole scene, not with the number of cameras: it converts every path in the stage to a Python string and inserts it. Measured directly, one full rebuild takes 10 ms on a bare stage but 556 ms once 100k unrelated prims are present (table below), and it grows linearly from there — seconds of host work per reset at the ~1.1M prims of an 8192-environment scene.

Fix: author a private per-view uint index attribute on each managed prim (and on each unique parent), holding that prim's view index. Every selection requires the matching index attribute, so selections resolve to exactly the view's prims. The view-to-Fabric slot mapping is then rebuilt by inverting that attribute in a single Warp kernel launch:

fabric_slots[view_indices[fabric_slot]] = fabric_slot

That is O(view) device work with no host-side path resolution and no Python objects created per frame.

There is also no cache, so there is nothing to invalidate. The table is rebuilt from live Fabric data on every access, which means a bucket reorder can never leave a stale mapping behind. Selections are still checked with GetCount(), which is exact here: the index attribute belongs to one view, so the count can only change if one of that view's prims actually disappeared — and then the view raises a clear error instead of silently reading the wrong prim.

Attribute names embed a process-wide monotonic uid, so a dead view's leftover attributes can never satisfy a live view's selection — and since review, they are removed outright when the view is released (section 3). Parent reads get their own read-only selection, keeping the child RO/RW flip semantics from #5677 intact.

2. SceneDataProvider.create_mapping did a linear scan per item

for i, path in enumerate(input_paths):
    mapping[i] = paths.index(path)   # O(N) scan, per path

Fix: build the reverse dict once (first occurrence wins, matching list.index semantics), then resolve each path in O(1). Measured over 200k paths, preserving first-occurrence semantics costs nothing versus an unguarded dict comprehension, so the fix carries no behaviour change.

3. Index attributes are removed when a view is released (from review)

The per-view index attributes from fix 1 were initially never removed, so views recreated over the same prims on a long-lived stage accumulated attribute pairs, widening those prims' Fabric buckets. Measured over 8 successive views on one stage (512 prims), attributes on a single prim went 1 → 8 and first-access rose monotonically from 120 ms to 173 ms.

Fix: FabricFrameView.close() removes the view's tags (measured at 4.7 µs per prim, ~77 ms for an 8192-env view) and is safe to call more than once. BaseFrameView gains a no-op close() so callers can close any backend uniformly. Every in-repo callsite now closes its view: Camera when invalidated and when dropped (__del__), prim_world_positions after each per-env view it creates in a loop, and SceneAsset before replacing its cached view. Views dropped without close() are cleaned up best-effort from __del__, following the shutdown-safe idiom the env classes already use (sys bound as a default argument; nothing runs during interpreter finalization, where Fabric dies with the process anyway), and a warning names the view so the missing close() call can be fixed.

How the problem was found

The stall was invisible in Tracy. Comparing captures before and after the commit that introduced it, Kit's own per-frame work is unchanged — App Update totals 65.1 s before and 62.3 s after, over ~120 frames. All the lost time sits in the gaps between frames, where the main thread is blocked in Python and Kit records nothing.

A py-spy capture found the cause: _compute_fabric_indices_for accounted for 11.86% of samples (23.2 s of a 195 s run), reached through camera.reset()get_world_poses() → the selection rebuild. Every frame on that chain carries essentially the same share, so the whole cost is that one function.

Fixes nvbug 6535498.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality) — FrameView.close()

Benchmarks

End-to-end symptom

Task Isaac-Lift-KukaAllegro-Camera, 8192 environments, presets=physx,isaacsim_rtx_renderer,duo_camera. Commit 69888c34e471 (which introduced the problem) against its parent e5f99d320338:

Parent With the problem
Mean environment step 699 ms 7193 ms
Slow steps (over 3 s) 1 of 100 28 of 100, averaging 18.9 s
GPU utilization 23.4% 4.7%

GPU and CPU utilization both drop during the slow steps, which is what a stall looks like — the pipeline is waiting, not doing extra work.

With this PR, the same task at 8192 environments steps at mean 1.554 s, peak 1.663 s — peak within 7% of mean, i.e. the stalls are gone. (Measured on an RTX A6000, so the absolute step time is not comparable to the table above, which was captured on different hardware; the stall signature is the comparison that matters.)

Selection size — the actual fix

L40, cuda:0, 1024-prim view (1024 children + 1024 parents). "Filler" is xformable prims not in the view but carrying Fabric matrices — i.e. the rest of a real scene.

filler prims develop selection this PR
0 2,048 1,024
10,000 12,048 1,024
100,000 102,048 1,024

develop scales with the stage; this PR is pinned to the view.

Slot-mapping rebuild (mean ms, the path hit on every reset)

filler prims develop child develop parent develop full RO rebuild PR child PR parent
0 4.67 5.40 10.24 0.137 0.191
10,000 24.05 24.69 62.47 0.139 0.193
100,000 274.21 270.47 556.41 0.137 0.190

develop grows linearly with stage size — 556 ms per rebuild at 100k filler prims. This PR is flat at ~0.14 ms, a ~2000× reduction, and unchanged from 0 to 100k filler prims. First access at 100k filler: 1824 ms → 383 ms.

create_mapping (pure Python, reversed path order)

N develop this PR speedup
1,000 0.0038 s 0.0001 s 27×
5,000 0.0862 s 0.0007 s 120×
20,000 1.3241 s 0.0030 s 434×
50,000 8.5507 s 0.0092 s 929×
200,000 (not run) 0.0467 s

Outputs verified identical at every N. At the ~200k rigid bodies of an 8192-environment scene the old path takes minutes.

Tests

Suite Result
isaaclab_physx/test/sim/test_views_xform_prim_fabric.py 79 passed, 4 skipped (cpu + cuda:0 on an L40)
isaaclab/test/sim/test_views_xform_prim.py (USD contract) 63 passed
isaaclab_newton/test/sim/test_views_xform_prim_newton.py 58 passed
isaaclab/test/sensors/test_camera.py (main consumer, incl. the new close() call) 35 passed, 0 missing-close() warnings
isaaclab/test/utils/warp/test_proxy_array.py 81 passed

New tests:

  • test_selections_match_only_the_view_prims asserts each selection matches exactly the prims the view manages. Verified to fail without the fix — with the selections unscoped it reports matched 8 prims, expected 4, because the child selections pick up the parents too.
  • test_close_removes_index_attributes asserts the tag-scoped selection drops to zero after close() and that a second close() is a no-op.
  • test_garbage_collection_removes_index_attributes_and_warns asserts a view dropped without close() still removes its tags on collection and logs the warning.

test_fabric_rebuild_after_topology_change was updated to drive the new refresh paths instead of the removed _rebuild_{ro,rw}_arrays.

The 4 skips are environmental: empty device parameter sets, and Fabric hierarchy bindings that are unavailable in a headless experience.

Coverage gap: test_physx_scene_data_backend.py and test_ovphysx_scene_data_backend.py both skip at collection on the machine used here, so the create_mapping change is exercised only by the standalone benchmark above, not by the test suite. Worth a look in CI, where those backends are available.

Screenshots

Not applicable — no visual change. The benchmarks above cover the behaviour change.

Notes for reviewers

Review feedback addressed so far: the index-attribute accumulation is fixed by close() (section 3); the opposite-space recompute no longer refreshes the same selection twice on writer-scope exit; create_mapping keeps list.index's first-occurrence semantics for duplicate paths (measured free at 200k paths); and docstrings/changelogs were trimmed to the observable contract.

The isaaclab/isaaclab_physx changelog fragments are still named fix-physx-newton-camera-pose-scaling.rst, inherited from #6554 — nothing here touches Newton or scaling. The new isaaclab_mimic fragment uses the branch slug. Happy to rename if reviewers prefer.

A handful of tests still drop views without close() and now log the new warning during runs; harmless, cleanup to follow.

EDIT: fixed — the only remaining warning is the one test_garbage_collection_removes_index_attributes_and_warns asserts on. Camera previously closed its view only on invalidation, so a dropped camera still went through __del__; it now closes in Camera.__del__ too. test_camera.py went from 3 warnings to 0.

Relationship to #6554

#6554 found the same two slow paths. This PR takes its SceneDataProvider fix unchanged (credited with a Co-authored-by line) and replaces its Fabric frame view fix.

#6554 kept the whole-stage selection and the Python dictionary, and cached the result, reusing it while the number of selected prims stayed the same. Two problems with that. The cache key is unsafe: an equal prim count does not mean the prims or their order stayed the same, so after a bucket reorder or a same-count membership change the cached indices point at the wrong prims and cameras silently read another prim's transform. And it treats the symptom — the underlying operation is still proportional to the size of the whole scene, just performed less often.

Making the selection small removes the need for a cache at all, so both problems go away.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump extension.toml — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added bug Something isn't working isaac-lab Related to Isaac Lab team labels Jul 30, 2026
@pv-nvidia
pv-nvidia force-pushed the pv/fix-fabric-frameview-stall branch from 1bd05de to 6787d38 Compare July 30, 2026 13:55
@pv-nvidia pv-nvidia changed the title Pv/fix fabric frameview stall perf: Bring back per-frame-view Fabric index attributes Jul 30, 2026
@pv-nvidia
pv-nvidia force-pushed the pv/fix-fabric-frameview-stall branch from deaadf7 to 21d3d22 Compare July 30, 2026 14:28
@pv-nvidia pv-nvidia changed the title perf: Bring back per-frame-view Fabric index attributes fix: scale FabricFrameView selections to the view, not the stage Jul 30, 2026
@pv-nvidia
pv-nvidia force-pushed the pv/fix-fabric-frameview-stall branch 2 times, most recently from 91ba6fe to 10d4ff1 Compare August 1, 2026 11:27
pv-nvidia and others added 5 commits August 2, 2026 15:45
create_mapping resolved every input path with list.index, an O(N^2)
scan that takes minutes at the ~200k rigid bodies of an 8192-env
scene. Build a path -> output-index dict once (first occurrence wins,
matching list.index semantics) and resolve each path in O(1).

Adopted unchanged from PR isaac-sim#6554.

Co-authored-by: yts-nv <yts-nv@users.noreply.github.com>
FabricFrameView selected prims by requiring only the Fabric world and
local matrix attributes, which every xformable in the stage carries.
Resolving the view's prims against that selection built a python
path-to-index dict over ~1.1M prims on every environment reset. The
allocation churn drove multi-second cyclic-GC stalls between rendered
frames at high environment counts (nvbug 6535498); Kit-side per-frame
work was unaffected, which is why the stall was invisible to Tracy.

Tag each view's prims (and their parents) with per-view uint index
attributes and require the tag in every selection, so selections match
O(view) prims instead of O(stage). Rebuild the view-to-fabric slot
mapping in a Warp kernel over the index attribute on each access:
values travel with rows across bucket moves, so the mapping can never
go stale and no cache or invalidation key is needed. Selections are
guarded with GetCount(), which is exact because the per-view tag makes
membership unambiguous. Attribute names embed a process-wide monotonic
uid so a dead view's leftovers can never satisfy a live selection.

Supersedes the fabric_frame_view half of PR isaac-sim#6554, whose cache keyed
on selection length could silently serve stale indices after a
same-count membership change or bucket reorder.
The view index attributes are authored as Fabric UInt and flow through
the kernels as uint32, so the int32 slot arrays read as an unexplained
inconsistency. They are not a style choice: Warp's check_index_array
rejects any dtype other than int32 for indexed-array indices, so
anything handed to wp.indexedfabricarray must be int32.

Record that constraint where a reader meets it: the ArrayInt32_1d
alias, both kernels that cross the boundary, and the buffer
declarations in FabricFrameView.
Assert each selection matches exactly the prims the view manages
rather than every prim on the stage. Without the per-view index
attribute in the selection predicate the child selections pick up the
parents too, so this fails with "matched 8 prims, expected 4".
@pv-nvidia
pv-nvidia force-pushed the pv/fix-fabric-frameview-stall branch from 10d4ff1 to fa139eb Compare August 2, 2026 15:45
@pv-nvidia
pv-nvidia marked this pull request as ready for review August 2, 2026 20:35
@pv-nvidia
pv-nvidia requested a review from a team August 2, 2026 20:35
@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces stage-wide host path resolution with per-view Fabric index attributes and GPU-built slot mappings, while also making scene-data path mapping linear rather than quadratic.

  • Scopes child and parent Fabric selections using private per-view index attributes.
  • Reconstructs view-to-Fabric slot mappings from live selection data on each access.
  • Optimizes SceneDataProvider.create_mapping with a first-occurrence reverse dictionary.
  • Adds focused selection-size and topology-refresh coverage plus changelog entries.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The new mappings preserve existing path semantics, and the Fabric access paths rebuild scoped slot maps before use without exposing retained indexed arrays to subsequent buffer refreshes.

Important Files Changed

Filename Overview
source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Replaces whole-stage path lookup with tagged child and parent selections whose slot mappings are rebuilt on-device.
source/isaaclab/isaaclab/utils/warp/fabric.py Adds kernels that invert per-view indices and gather parent Fabric slots.
source/isaaclab/isaaclab/scene_data/scene_data_provider.py Preserves first-occurrence lookup semantics while reducing mapping construction from quadratic to linear time.
source/isaaclab_physx/test/sim/test_views_xform_prim_fabric.py Updates topology-refresh coverage and verifies that selections contain only the view’s managed prims.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  V[FabricFrameView prim paths] --> T[Author per-view child and parent indices]
  T --> S[Scoped Fabric selections]
  S --> K[Warp kernels invert indices into Fabric slots]
  K --> I[Indexed Fabric matrix arrays]
  I --> P[Camera and frame pose reads]
  B[Backend transform paths] --> D[First-occurrence reverse dictionary]
  O[Requested output paths] --> D
  D --> M[Linear transform mapping]
Loading

Reviews (1): Last reviewed commit: "Removed comment" | Re-trigger Greptile

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The scoped Fabric selections and device-side slot mapping remove the whole-stage lookup bottleneck, while SceneDataProvider.create_mapping preserves first-occurrence semantics with linear-time construction. One maintainability and performance issue remains: each recreated view permanently leaves uniquely named Fabric index attributes on its prims.

  • Design and architecture: Per-view tagged selections avoid host-side path resolution and stale mapping caches, but they introduce persistent per-view stage state without a lifecycle or reclamation mechanism. Repeated view creation therefore accumulates attributes and progressively increases initialization cost.
  • API: create_mapping retains its documented behavior: first occurrence wins, unmatched paths map to -1, and identity mappings return None. Removed FabricFrameView helpers and fields are private, and the in-repository test consumer was migrated. A cleanup API or an explicitly documented one-view-per-stage lifetime contract is needed for the new authored attributes.
  • Implementation: The child and parent tagging, scoped selections, count checks, and Warp mapping refresh paths are internally consistent. However, _initialize_fabric creates UID-suffixed attributes on managed prims and parents without any teardown path, so recreating views on a long-lived stage permanently widens Fabric state and measurably slows later initialization.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.

Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab/isaaclab/scene_data/scene_data_provider.py
Address review feedback on isaac-sim#6805:

- _parent_path sliced the path with rsplit, which allocates a list and
  the unused tail; slice at rfind("/") instead. View prim paths are
  absolute, so rfind always hits at least the leading separator.
- _initialize_fabric derived every child's parent path twice (once for
  the unique-parent list, again for the child->parent ordinal map);
  compute the list once and reuse it.
Address review feedback on isaac-sim#6805: the first-occurrence-wins guard only
preserved list.index semantics for duplicate paths, but duplicates are
invalid input and yield a wrong mapping under either occurrence choice,
so keep the fastest form. Last occurrence now wins for a duplicate.
The nvbug 6535498 stall was invisible in Tracy and Nsight because the
FrameView work happens in Python between Kit zones, and sampling
profilers kept missing it (py-spy nonblocking drops samples in long C
calls; nsys Python sampling is fragile behind launcher processes).
Named zones make the getter, selection-refresh, opposite-space
recompute, and one-time init phases show up explicitly on whichever
backend the carb profiler targets: Tracy zones in tracy captures, NVTX
ranges under Nsight Systems.

carb.profiler.begin() returns immediately when no profiler is active,
so the decorators cost nothing outside profiling sessions.
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
Comment thread source/isaaclab_physx/test/sim/test_views_xform_prim_fabric.py
Comment thread source/isaaclab_physx/test/sim/test_views_xform_prim_fabric.py
Comment thread source/isaaclab/changelog.d/fix-physx-newton-camera-pose-scaling.rst Outdated
Comment thread source/isaaclab_physx/changelog.d/fix-physx-newton-camera-pose-scaling.rst Outdated

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated review (Codex) — Requesting changes.

Two merge blockers remain:

  • The existing unresolved inline finding on per-view Fabric index attributes documents a measured per-stage leak: recreated views permanently add attributes and progressively slow later initialization. A lifecycle cleanup or design that avoids permanent per-view stage state is needed; a documentation-only workaround is not sufficient for a normal recreation path. See #6805 (comment).
  • SceneDataProvider.create_mapping now silently changes duplicate-path behavior from first occurrence to last occurrence without validation or deprecation. Preserve the public behavior or reject duplicates through a compatibility-managed change, with focused unit coverage.

I also left inline requests to remove a duplicated child-selection refresh from the writer hot path, replace or remove a topology test that never changes topology, and reduce implementation-history prose duplicated across comments, docstrings, tests, and changelog fragments.

Verification performed on head dc22f1b97018d99be36223d50a374456a5b87c9f:

  • ./isaaclab.sh -f: passed all hooks.
  • PhysX Fabric FrameView test file on CPU: 35 passed, 43 skipped; CUDA was unavailable.
  • New selection-scope regression test: passed on the PR implementation and failed against the pre-fix installed implementation.
  • Scene-data geometry tests: 5 passed.
  • Direct duplicate-path probe confirmed the semantic change: one /A input maps to index 1 for paths=["/A", "/A"], versus index 0 previously.

Both _recompute_local_from_world_all and _recompute_world_from_local_all
need the world and local child arrays, and reached them through
_get_world_ifa and _get_local_ifa. Each accessor refreshes the active
child selection independently, so every writer-scope exit ran
PrepareForReuse, the count check and the slot-mapping kernel twice
against the same selection.

Add _get_child_ifas, which refreshes once and builds both indexed
arrays from that refresh, and use it in both recomputes.

Also trims the class docstring to the externally observable contract:
the private selection names, kernel launches and error mechanics
belong beside the helpers that implement them, and would go stale
here. The tag-accumulation caveat moves in, since that one is a
lifetime constraint callers need to know about.
The dict comprehension introduced earlier in this PR resolved a
duplicate path to its last occurrence, where the list.index scan it
replaced resolved to the first. That is a silent behaviour change on a
public method for input the signature does not reject.

It was taken on the assumption that the guard costs performance. It
does not at the size that motivated the fix: over 200k paths the
guarded loop measures 19.21 ms against 19.28 ms for the unguarded
comprehension. The comprehension only wins below ~20k paths, by a
fraction of a millisecond.

Restore the guard, so the O(N^2) fix carries no semantic change.
Review feedback: several comments added while iterating on this PR
explain rejected alternatives or restate mechanics the code already
shows, and both changelog entries described the implementation rather
than the user-visible outcome.

- Kernel docstrings state their contract; the int32 index-array
  constraint is explained once, at the ArrayInt32_1d alias where it
  originates, instead of three times.
- _parent_path documents its absolute-path precondition as an Args
  entry rather than narrating why it does not use rsplit.
- The topology test no longer claims to cover topology recovery. It
  does not provoke a bucket change, so it is a smoke test of the
  refresh paths; the selection-scope test is the regression coverage.
- Changelog entries state the outcome (stalls at high environment and
  rigid-body counts) and drop the algorithm description, which also
  removes an inaccurate O(N) claim about dictionary lookup.
Reverts the zone decorators added in 75b159f. A survey of the
source tree found no other carb.profiler usage and no zone
instrumentation of any kind, so these were a one-off style. They also
made the module require Kit's paths at import time, where carb was
previously only imported lazily.

The zones remain useful for profiling sessions; re-apply 75b159f
locally when needed.
The per-view index attributes FabricFrameView authors were never
removed, so views recreated over the same prims on a long-lived stage
accumulated attribute pairs, widening those prims' Fabric buckets and
slowing later view initialization (measured: first access grew from
120 ms to 173 ms over 8 recreations at 512 prims).

Add close(), which removes the view's tags and is safe to call more
than once. BaseFrameView gains a no-op close() so callers can close
any backend uniformly; Camera closes its view when invalidated.

Views dropped without close() are cleaned up from __del__, following
the shutdown-safe idiom used by the env classes: sys is bound as a
default argument, nothing runs during interpreter finalization (Kit
may be torn down, and Fabric dies with the process anyway), and a
warning names the view so the missing close() call can be fixed.
Removal is cheap (measured 4.7 us per prim) and proceeds past
individual failed handles.
The missing-close() warning fired six times per suite run: the
view_factory bundles were only torn down by the shared contract
wrappers, and several tests build views directly and drop them.

Register view.close as a pytest finalizer in the factory (idempotent,
so tests that already close or tear down are unaffected) and close the
directly-built views at the end of their tests. The garbage-collection
test now builds its view inline: the fixture's finalizer is a bound
method that would keep the view alive past the del it depends on.

The one remaining warning per run comes from that test, which asserts
the warning is emitted.
@pv-nvidia pv-nvidia self-assigned this Aug 3, 2026
@pbarejko pbarejko self-assigned this Aug 3, 2026

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a high level POV.

Comment thread source/isaaclab/isaaclab/scene_data/scene_data_provider.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
The lazily created views in prim_world_positions and SceneAsset were
dropped without close(), so their Fabric index attributes were removed
from __del__ with a warning naming the view.

Trim the create_mapping comment to the mapping's contract.
@pv-nvidia
pv-nvidia requested a review from peterd-NV as a code owner August 4, 2026 12:24
@github-actions github-actions Bot added the isaac-mimic Related to Isaac Mimic team label Aug 4, 2026
pv-nvidia and others added 3 commits August 4, 2026 12:29
Camera only closed its view on invalidation, so a dropped camera left the
view to __del__ and logged the missing-close() warning.
@pv-nvidia pv-nvidia changed the title fix: scale FabricFrameView selections to the view, not the stage perf: scale FabricFrameView selections to the view, not the stage Aug 4, 2026
Added
^^^^^

* Added :meth:`~isaaclab.sim.views.BaseFrameView.close` to release backend state

@pbarejko pbarejko Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How releasing the backend state helps the performance?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each FabricFrameView assigns index attributes to the selected prims, these need to be removed when the frame view is deleted. Otherwise a newly created frame view would again create new attributes, and so on.

In general, a frame view must be able to do cleanup, hence the close method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

3 participants