Remove USS sampling from the benchmark memory recorder - #7837
Conversation
MemoryInfoRecorder called psutil.Process.memory_full_info() on every update. That call walks the process page tables, so its cost scales with resident size: measured at 71.4 ms per update on an 8 GB process (psutil 5.9.8, Linux 6.8). BenchmarkMonitor drives this recorder once per second from a background thread that is started inside the timed region of all nine benchmark entry points, so the sample perturbed the workload the run was measuring. USS had no consumer. capture.py maps only RSS into the typed bundle, the typed schema has no USS field, the console summary cannot print it, and no in-repo formatter or fixture reads it. RSS and VMS come from memory_info(), a cheap counter read, and are unchanged. Removes the USS state, sampling and the four "System Memory USS*" measurements rather than retaining stale or partial values. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
There was a problem hiding this comment.
Isaac Lab Review Bot
The recorder-local change removes expensive USS sampling while preserving RSS/VMS behavior, but it also removes established runtime keys and four serialized measurement rows without the repository-required deprecation bridge. The test additions include ineffective, duplicated, source-grep, and private-state assertions, and the implementation adds an overlong comment with a cost claim inconsistent with the supplied measurement.
- Design and architecture: Keeping the performance fix inside
MemoryInfoRecorderavoids disturbing the nine benchmark monitor call sites and preserves the existing monitoring architecture. However, outright removal of USS must be replaced with a compatibility path that keeps the old behavior available during a documented deprecation period with a targeted warning and transition coverage. - API:
MemoryInfoRecorder.get_runtime_data()no longer providesuss_mean,uss_std,uss_peak, oruss_n, andget_data()no longer emits the four correspondingSystem Memory USSmeasurements. RSS and VMS names, units, statistics, and conversion behavior remain unchanged, but the removed producer outputs are established externally observable API. - Compatibility and deprecation: Breaking changes: the
System Memory USS,System Memory USS std,System Memory USS peak, andSystem Memory USS nserialized measurements, together with theuss_*runtime keys, are removed without an opt-in compatibility path, targeted deprecation warning, migration guidance, removal schedule, or transition tests. The changelog announces the removal but does not satisfy the required deprecation cycle. - Implementation: The USS Welford state, peak tracking,
memory_full_info()call, and emitted rows are consistently removed, while the RSS/VMS paths remain intact. Before merge, the implementation needs a deprecation bridge rather than immediate removal. The explanatory block at_get_runtime_info()should also be shortened and its unsupported “hundreds of milliseconds” claim corrected. - Style consistency: The surrounding recorder structure remains consistent, but the new eight-line USS comment is disproportionate to adjacent section comments and duplicates release-note rationale. Its claim of hundreds of milliseconds at a few GB conflicts with the supplied 71.42 ms measurement at 8 GB; retain only the concise invariant that page-table walking must not occur in the timed region.
- Test quality: The direct recorder tests for avoiding
memory_full_info(), excluding USS runtime/output keys, and preserving RSS/VMS statistics cover the core behavior. Cleanup is needed: the first monitor test can still pass after USS sampling returns because the exception is swallowed after RSS is recorded; it should be consolidated with the monitor exception test. The entrypoint test greps unchanged source using unrelated substring assertions, the finalized omniperf case duplicates the parametrized formatter case, and thehasattrchecks pin private storage despite existing public-boundary coverage.
Significant concerns. Posted 6 actionable findings inline.
Automated review; human maintainers own approval decisions.
…o.py Co-authored-by: Antoine RICHARD <antoiner@nvidia.com> Signed-off-by: fanes <74020209+fatimaanes@users.noreply.github.com>
Remove the regression tests added for the USS removal, per review: * delete source/isaaclab/test/benchmark/test_memory_recorder_no_uss.py * drop the _uss_mean / _uss_n hasattr assertions from test_initialization * drop test_memory_full_info_is_never_called, test_no_uss_keys_in_runtime_data and test_rss_and_vms_means_are_tracked The recorder change and the changelog fragment are unchanged.
Resolves the conflict in source/isaaclab/test/benchmark/test_recorders.py. develop pruned TestMemoryInfoRecorder (isaac-sim#7986, isaac-sim#8022), deleting the tests this branch had edited, so the resolution takes develop's deletions. Since USS is no longer collected, the surviving measurement-count assertion is tightened from 8 <= len(...) <= 12 to == 8.
The changelog gate expects the entry type in the file name and a body of bullets, so move benchmark-drop-uss-sampling.rst to benchmark-drop-uss-sampling.removed.rst and drop the now-redundant Removed section heading. The entry text is unchanged.
|
run-ci |
Description
MemoryInfoRecordersampled Unique Set Size on every update viapsutil.Process.memory_full_info(). That call walks the process page tables, so its costscales with resident size rather than being a constant counter read.
BenchmarkMonitordrives this recorder once per second from a background thread, and thatthread is started inside the timed region in all nine benchmark entry points
(
entrypoints/runtime.py:186plus the eight rl_games / rsl_rl / sb3 / skrl train and playentry points). USS collection therefore ran concurrently with the workload each benchmark
was measuring.
Measured on this host (AMD EPYC 9124, Linux 6.8.0-87, psutil 5.9.8 per
uv.lock), oneMemoryInfoRecorder.update()at 8 GB resident:update()medianRSS and VMS are read from
memory_info(), which is a cheap counter read and is unaffected.Why remove rather than budget or sample less often
An earlier proposal timed each sample against a budget and latched USS collection off once
it exceeded it. That keeps the metric nominally present while making it unreliable:
fires, so the reported mean/peak becomes an early-run prefix of a growing process rather
than a run statistic.
re-acquisition latency as much as query cost and can latch off on a small process under
thread contention.
so runs stop being comparable across machines.
Reducing the sampling interval has the same problem in weaker form: it lowers the duty cycle
but keeps an unbounded-cost call inside the timed region.
Because USS has no consumer (below), removing it avoids all of this and leaves no stale or
partial values behind.
The change is also deliberately confined to the recorder. The nine
with ... BenchmarkMonitor(benchmark, interval=1.0):lines are left byte-identical, becausedownstream benchmark tooling pattern-matches the literal shape of those lines to inject
profiler capture anchors into Isaac Lab's entry points. Remedies that restructure the
withstatement, rename thebenchmarkargument, or move sampling out of the monitor wouldsilently break that tooling; fixing the cost at its source does not.
Output change
These four measurements are no longer emitted:
System Memory USSSystem Memory USS stdSystem Memory USS peakSystem Memory USS nMemoryInfoRecordernow always emits exactly 8 measurements (RSS and VMS, each with mean,std, peak and n), so the emitted set is no longer platform-dependent.
I searched the repository, its history, docs, test fixtures and serialized output
expectations for consumers before removing anything:
capture.py:346-348reads onlySystem Memory RSS,RSS stdandRSS peak.benchmark/schema.py) has no USS field.formatters.pypasses measurements through generically, so a removed row cannot raise.Min/Max/Mean/Std.The only in-repo references were the producer itself and assertions/comments in
test_recorders.py, both updated here.System Memory USS peakappears in a historicalCHANGELOG.rstentry, which is left untouched as a record of the past release.On the downstream side: the benchmark harness that runs these workloads collects its own USS
figure directly from
psutilrather than reading Isaac Lab's measurement, so removing thisfield does not deprive it of the metric. Previously recorded
System Memory USSseries remainin historical dashboard data; because they were produced while the sampler was perturbing the
run, they are not comparable with post-change runs and should be treated as a separate
baseline rather than a continuous series.
Type of change
Tests
Run with the repo
.venv(Python 3.12.13, torch 2.11.0+cu128, psutil 5.9.8), pytest 9.1.1:The failing set is byte-identical on both, so this branch introduces no regression. The 11
pre-existing failures are in
test_api.py(10) andtest_asset_suite_runtime_semantics.py(1) and are unrelated to this change.New regression coverage:
test_memory_full_info_is_never_called— monkeypatchespsutil.Process.memory_full_infoto raise, so reintroducing the call fails the suite.
test_no_uss_keys_in_runtime_data,test_get_data_measurement_names— no USS key or rowis emitted.
test_rss_and_vms_means_are_tracked— scripted RSS/VMS values, asserting mean, peak and n.test_benchmark_monitor_never_queries_uss,test_monitor_reports_no_recorder_exception—a live
BenchmarkMonitorover a real benchmark, asserting the recorder still updates, themonitor records no exception, and its thread is joined.
test_finalized_output_contains_no_uss,test_supported_formatters_still_serialize—omniperf,json,osmoandsummaryall still write output containing no USS field.test_entrypoints_keep_monitor_and_recorder_configuration— guards that each of the nineentry points still constructs a
BenchmarkMonitorwithuse_recorders=True.Lint and hooks:
Checklist
pre-commitchecks with./isaaclab.sh --formatsource/isaaclab/changelog.d/CONTRIBUTORS.mdor my name already exists there🤖 Generated with Claude Code