Skip to content

Add operation-scoped RAM statistics across supported backends - #144

Merged
den-sq merged 12 commits into
mainfrom
codex/issue-139-ram-statistics
Oct 17, 2026
Merged

den-sq merged 12 commits into
mainfrom
codex/issue-139-ram-statistics

Conversation

@den-sq

@den-sq den-sq commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Adds operation-scoped memory measurements to the existing run-statistics reports for #139. Slicing and backprojection report a sampled peak, coverage and collection cost through the same --verbose files and server/Docker delivery paths as timing statistics.

The collector now uses process counters plus one contribution per live manager-owned shared buffer. It no longer tracks worker mappings or TIFF mappings, enumerates Windows working-set pages, or adds resident TIFF backing absent from process counters.

Implementation

Backend Measurement
Linux, including Docker Process-tree Pss − Pss_Shmem, plus each live managed segment's resident bytes from mincore
Native Windows Process-tree PrivateWorkingSetSize, plus each live managed segment's allocated size
Native macOS Process-tree libproc private residency, excluding the manager's owned mappings, plus managed segment residency from mincore

Linux's subtraction avoids double counting shared pages even with one reader; the managed residency term includes queued resident buffers after their producer closes. Windows uses the fast PROCESS_MEMORY_COUNTERS_EX2 counter and explicitly labels its managed term allocated, not resident: unused or paged-out managed pages remain included. It requires 64-bit Windows 10/11 22H2 with September 2023 updates or later. macOS retains a region walk; excluding the manager's own ranges prevents sole-owner double counting.

  • A separate observer samples the backend parent and discovered descendants around Pipeline.process(), excluding itself. The default interval is one second. Disabled reporting starts no collector.
  • _OwnedSharedMemoryTracker publishes derived allocation snapshots at its existing allocation/registration/release boundaries. Manager initialization receives the shared observation session; workers and array attachments need no reporting hooks.
  • The peak is the maximum complete sampled tree total, with explicit partial/unavailable results, incomplete-sweep errors, intervals and collection cost. Publication revisions use a counter rather than clock timestamps, so even rapid allocation/release cycles are detected. Process or allocation changes invalidate a sweep; publication failure invalidates memory coverage without failing scientific allocation.
  • Removed the weak mapping registry, all worker-context plumbing, six TIFF wrappers, Windows page unions and macOS TIFF residency queries. Preserved the merged owner-handle/handoff and early-worker-start fixes.
  • Existing entry points/frozen observer dispatch, report delivery and bounded Windows file-IPC retries remain in use. Updated native CI test paths and metric documentation.

There is no extra resident file-cache accounting. Ordinary mapped-file pages can still contribute through the OS process counter. Platform metrics have different shared-memory semantics and are named accordingly; they are not interchangeable measurements of exactly the same RAM. Only live manager-owned segments are added. Overlapping operations share a process-tree scope, not isolated per-job accounting; managers created before an observation session are not retroactively enrolled. Production pipelines create their managers inside that window.

Shared-basis audit

  • Task owns run identity/outcome; RunStatistics owns reporting and the collector window. Memory extends that record and its existing output paths, with no parallel run/report authority. Pipeline and PipelineStep retain execution, dispatch and timing ownership; their observation-context fields and executor initializer forwarding were removed.
  • _OwnedSharedMemoryTracker._segments exclusively owns managed identities, live handles and release policy. Snapshots derive names/sizes and, on macOS only, owner addresses directly under that owner's lock. The previous attachment/TIFF weak registry, cached address records, constructor/close hooks and per-worker manifests were removed. Snapshot JSON is a one-way observation boundary; execution never reads it and no persistent allocation mirror is maintained. Native residency queries take temporary read-only views without unlink authority.
  • OS adapters own the definitions of their readings; the collector owns only sampled values and coverage reduction. The old Windows page enumeration/backing unions and macOS file-backing calculations were removed. Linux replaces plain PSS with non-shmem PSS plus managed residency. No per-process lifetime maxima are summed, and no TIFF-cache estimate is substituted.
  • memory_ipc.observation_file_io remains the single bounded retry facility for snapshots and collector control/result files. The existing shared-session seam now serves only manager observations on all supported backends.
  • Load-bearing decisions discussed with the owner during implementation and now recorded retrospectively on #139: manager-only observations; explicit Windows allocated-versus-resident semantics; Linux shared-PSS subtraction; macOS sole-owner range exclusion; no extra TIFF-cache accounting. Existing one-second sampling, separate observer process, shared-tree concurrency scope and explicit incomplete coverage remain.

Validation

  • Review follow-up 3e91580: committed the current 10145cd Linux/Windows raw results, provenance and all per-run process counts; historical artifacts remain linked at their original revision. Evidence and methods. Removed formatting-only changes from mem.py and the two data pipelines; all 46 production Python ASTs still match the benchmarked revision.

  • Short Docker delivery check: Short 2 slicing then backprojection through the existing Windows/WSL2 development container and real Electron-hosted volume server. Both tasks completed and both reports reached the host as readable UID 1000 / mode 0600 files. Slicing: 1,448.38 MiB, partial (29 complete / 1 incomplete sweep); backprojection: 1,751.84 MiB, sampled (10 complete). Both use the final Linux metric; source digests match the host, scientific scratch/report staging cleared, and no managed shared segments remained. This is a delivery check, not an overhead comparison or a newly built release-image test.

  • Final full Linux CI suite: 352 passed, 2 platform skips in 23.23 s; the configured helper coverage check passed at 99%. Includes reporting lifecycle and the actual fork-pool regression for released slice buffers. The existing Python 3.12 threaded-fork deprecation warning from that retained Fix fork-inherited shared-buffer retention during slicing #148 regression remains visible; this change does not introduce it. Local validation before the added clock regression was 351 passed, 2 skipped.

  • Native Windows focused suite: 115 passed, 6 platform skips in 36.36 s, with ResourceWarning treated as an error. Covers the native private counter, managed owner lifecycle, snapshot publication, collector subprocess and pipeline statistics; server HTTP tests are covered by the Linux suite (the isolated Windows runtime lacks their httpx test dependency).

  • After CI exposed coarse Windows clock timestamps, snapshot publication now uses a strictly advancing counter. The deterministic allocation/release regression and collector checks passed on Linux (42 passed) and native Windows (39 passed, 3 platform skips). The control-file test also permits additional native Windows sharing retries within the existing half-second bound.

  • Focused ownership tests verify that attachments/views/serialization create no extra allocation observations, buffers remain observable after producer closure, release removes them, and POSIX residency queries do not fault untouched pages. Native Windows private/shared allocation checks verify that shared mappings do not enter the private counter.

  • Final native CI and coverage passed: Linux and macOS each returned 111 passed, 2 skipped on both Python 3.11 and 3.12; Windows returned 92 passed, 5 skipped on each version. Native macOS pipeline cost remains unmeasured; no cross-platform 1% overhead bound is claimed.

Current-implementation Linux and native Windows benchmarks cover all three Salivary Duct paths, two off/on pairs each, with actual data-step timings, MAD, memory peaks, partial coverage and collector cost. All 48 measured operations completed. The results show repeatable short-path slowdowns. The owner acceptance decision scopes the combined 1% engineering target to longer runs, with inter-run variability and fixed startup/shutdown costs considered. The measured long path is accepted (Linux −1.764% slicing / −6.737% backprojection; Windows −7.260% / +0.288%). Short costs remain disclosed; this is neither a blanket negligible-overhead claim nor a statistical 1% bound. The comment also distinguishes sampling/lifecycle omissions from OS-controlled TIFF cache.

Full historical Linux and Windows benchmark results and raw reports remain available. Those overhead figures describe the former collectors, not this replacement. The subsequent Linux simple-versus-complete probes informed the chosen accounting; isolated query costs are not pipeline overhead. The benchmark guide now marks that distinction explicitly.

Advances #139. Per the owner decision, native macOS workflow/performance and macOS-host Docker delivery are deferred. A separate native-Linux-host Docker check also remains unperformed. #139 stays open for those named follow-up checks; the Windows/WSL2 Docker test is not presented as a complete three-host matrix.

@tavateva tavateva left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Early, non-final review of f732917 (draft), graded against #139. Requested by the owner as a COMMENT review. Explicitly out of scope: all performance results, including the native Windows +4.10% diagnostic, which await the real-data runs and an owner decision. Nothing below evaluates those numbers.

Verification so far

  • Ran: the full Linux Python suite, 327 passed and 3 platform skips. A focused Linux shared-memory probe (below).
  • Not run: Windows/macOS readers (relied on CI and the body), and a Docker run.
  • Read in full: memory_statistics.py, memory_observer.py, memory_mappings.py, and the lifecycle wiring in run_statistics.py/server_handlers.py.

The lifecycle integration looks right:

  • Collection starts and stops around Pipeline.process() inside _process, before capture_volumes.
  • Startup failure degrades to explicit unavailability.
  • KeyboardInterrupt during startup cleans up and propagates.
  • Disabled reporting starts no collector.
  • mem_monitor is retired.

Blocking (as of this draft)

1. Linux/Docker headline misses resident shared segments that no sampled process has touched

process_tree_pss_bytes sums each process's PSS. PSS only counts pages a process has faulted into its own page tables. A shared segment that is resident in /dev/shm but not currently touched by any sampled process contributes nothing.

  • Probe: a child fills a 32 MiB SharedMemory segment and exits, while the parent keeps the segment mapped but never touches it.
    • /dev/shm usage: 32 MiB.
    • Process-tree PSS delta: about 4 MiB (noise).
  • Where slicing creates this state:
    1. download_volume allocates each chunk with TermedNPArray and fills it in the download worker. That worker's handle closes once the result is pickled back.
    2. dl_completed stores the unpickled SharedNPArray in volume_cache.volumes[index]. The coordinator maps it but does not touch it.
    3. The pages are attributed only once a slice worker starts reading.
    4. Every downloaded chunk waiting for a free slice worker is therefore resident workload memory that the headline does not see. That queue is a main contributor to slicing's peak.
  • Not covered by the tests: test_linux_tree_pss_counts_a_live_shared_mapping_once covers a mapping that is touched in both processes, but not this state.
  • Not covered by the docs: nothing in run-statistics.md declares the exclusion.
  • I did not measure the in-pipeline magnitude. This reviewer's container has a 64 MB /dev/shm, which cannot run the 384³ slice.
  • Other backends, unverified:
    • Windows working-set accounting likely has the same blind spot by the same mechanism.
    • macOS backing-residency (mincore) appears to cover it by construction.

This is the default deployment's metric, and #139 requires measuring the workload, including shared-memory state, without silently partial coverage.

  • Closure condition: the Linux headline either covers operation-owned shared segments that are resident while untouched, or the record and docs name this exclusion explicitly as a coverage limitation and the owner accepts it against #139.
  • Narrowest known option: per-process USS (memory_full_info().uss, from the same read) plus the allocated bytes (st_blocks × 512) of the operation's live /dev/shm segments.
    • SharedNPManager already enumerates those segments through its termed-segment list.
    • USS excludes shared pages, so nothing is counted twice.
    • It is a different quantity from PSS and needs its own metric name.

2. Outstanding #139 validation (already acknowledged in the body)

Not new findings; listed so the draft's remaining acceptance is in one place:

  • Default Docker deployment validated on a Linux host and a macOS host (only Windows/WSL so far, and only CLI-in-container rather than volume-server delivery).
  • A real native macOS collector/pipeline run beyond the focused CI tests.

Non-blocking

  • Pre-implementation disclosure is not on the record. #139 requires the backend matrix, headline metrics, sampling strategy, lifecycle, reset/concurrency assumptions and expected cost to be documented before implementation. The body says these were "disclosed before implementation", but #139 has no comments and its only body edit is the overhead amendment. Minimum response: link where they were disclosed, or post them on #139.
  • Shape question for the owner's Windows decision, independent of any numbers. The page-level union on Windows/macOS is the largest and most complex part of the change: per-process address manifests, a process-global weakref registry, JSON IPC, ctypes address derivation, and full working-set snapshots. It is also the part tied to the unresolved Windows question. A segment-level metric is materially leaner: per-process private bytes plus the size or residency of the operation's live shared segments, which the manager already knows. With its own name, it would also close finding 1 on all backends. Minimum response: none for this draft. Worth weighing before the Windows decision commits the PR to the page-union design.
  • No closing keyword. The body says "for #139" rather than "Fixes #139", so the merge will not close the issue. Ignore this if that is intentional.

@den-sq

den-sq commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

Full real-data benchmark results for all three annotation paths, including both short paths and the long path, on Linux and native Windows.

Revision and comparison scope: Linux was measured at f732917, before the manager-ownership rebase. Windows was rerun at be87951, after merged PR #146 and the manager-observer/manifest-retry integration. I verified both recorded production digests against those Git revisions. Linux has not been rerun after the rebase. Each batch kept production code fixed; these are within-platform reporting off/on comparisons, not a controlled Linux-versus-Windows speed comparison.

Method

  • Original PosteriorSalivaryDuct_cut_ng.json, PSU Octo9 uint16 source at mip 0; 120 × 120 slices; adaptive spacing 1 / ratio 0.5; 128 target slices per box. Backprojection uses 160³ chunks, zlib, minimum bounding box and separate output planes.
  • “Short 2” = Posterior Salivary Duct 2: 10 annotation points, 875 slices. “Short 3” = Posterior Salivary Duct 3: 16 points, 887 slices. “Long” = Posterior Salivary Duct: 50 points, 4,901 slices.
  • Two pairs per path: pair 1 off → on, pair 2 on → off, after one off-mode slicing cache warmup per path. Each treatment slices and then backprojects its own sliced intensity output; no binarization or pixel hashing.
  • Twelve workers, one BLAS/OpenMP thread, shared cached chunks. Linux used Python 3.11.13 under WSL2; native Windows used Python 3.11.9 with Windows-local source/cache/output directories. The shared development host was not isolated; Linux and Windows benchmarks did not run concurrently.
  • Times below are the existing SliceParallelPipelineStep / BackprojectPipelineStep durations. Parsing, geometry, source/cache setup before data operations, sampler startup/shutdown, and final formatting/persistence/delivery are excluded. Raw artifacts retain the external Pipeline.process() timer separately.
  • “On” includes reporting and RAM collection; “off” disables both. Overhead = (on median / off median − 1) × 100. MAD is median absolute deviation within each treatment. No additional trials were selected or repeated to improve results.
  • Both batches completed all 12 slicing → backprojection workflows (24 operations per platform) and all three warmups. All 12 enabled operations per platform returned usable peaks. Native Windows required the already-disclosed isolated CloudFiles 5.8.2 zero-width-interval workaround, identical in both treatments; it is not a shipped repository dependency fix.

Linux / WSL2: all path medians (f732917)

Path Operation Off median (s) On median (s) Difference (s) Overhead MAD off / on (s)
Short 2 Slicing 4.776743 4.937809 +0.161066 +3.372% 0.360739 / 0.146882
Short 2 Backprojection 4.317144 3.875092 -0.442052 -10.239% 0.756395 / 0.020286
Short 3 Slicing 4.425853 4.471380 +0.045526 +1.029% 0.071063 / 0.130346
Short 3 Backprojection 3.889799 3.841992 -0.047807 -1.229% 0.412733 / 0.177347
Long Slicing 19.442347 20.999911 +1.557565 +8.011% 0.117172 / 1.606434
Long Backprojection 23.300999 23.828389 +0.527390 +2.263% 0.361705 / 0.567634

Full raw results, including external pipeline times, output headers and all memory summaries

Native Windows: all path medians (be87951)

Path Operation Off median (s) On median (s) Difference (s) Overhead MAD off / on (s)
Short 2 Slicing 23.073508 23.576249 +0.502741 +2.179% 0.684345 / 0.099444
Short 2 Backprojection 18.122470 18.202131 +0.079661 +0.440% 0.086043 / 0.261774
Short 3 Slicing 22.707309 23.814665 +1.107356 +4.877% 0.270171 / 1.342440
Short 3 Backprojection 18.782255 18.589627 -0.192628 -1.026% 0.216100 / 0.406218
Long Slicing 35.535106 37.844008 +2.308902 +6.498% 1.305884 / 1.203964
Long Backprojection 72.287309 75.070813 +2.783504 +3.851% 0.455517 / 0.957966

Full raw results, including external pipeline times, output headers and all memory summaries

Interpretation

  • Linux: no operation was slower in both pairs. Every positive median difference is smaller than at least one treatment's MAD. This is consistent with variation dominating the measured cost in that batch; two pairs do not establish a 1% upper bound, and this is not evidence for the rebased Linux implementation.
  • Windows, short paths: positive median differences are smaller than at least one treatment's MAD. Short 3 slicing was slower in both pairs, but one pair differed by only +0.156%; the median increase is smaller than its enabled-run MAD.
  • Windows, long path: slicing and backprojection were slower in both pairs. Their median increases exceed both treatment MADs: slicing +2.308902 s (+6.498%), backprojection +2.783504 s (+3.851%). This remains an unresolved finding against the combined 1% in-operation target; it does not support a negligible-overhead claim. Two pairs on a shared host do not isolate the cause or establish a strict statistical bound.
  • Negative differences describe variation, not a claimed reporting-induced speedup.
Every paired data-operation timing, including both short paths (seconds)

Pair numbers identify matched trials. Actual chronological order was off/on for pair 1 and on/off for pair 2.

Platform Path Operation Pair 1 off Pair 1 on Pair 1 change Pair 2 off Pair 2 on Pair 2 change
Linux / WSL2 Short 2 Slicing 5.137482 5.084691 -1.028% 4.416004 4.790927 +8.490%
Linux / WSL2 Short 2 Backprojection 5.073539 3.895379 -23.222% 3.560749 3.854806 +8.258%
Linux / WSL2 Short 3 Slicing 4.354790 4.341033 -0.316% 4.496916 4.601726 +2.331%
Linux / WSL2 Short 3 Backprojection 4.302532 4.019340 -6.582% 3.477066 3.664645 +5.395%
Linux / WSL2 Long Slicing 19.325175 22.606345 +16.979% 19.559519 19.393478 -0.849%
Linux / WSL2 Long Backprojection 22.939294 24.396023 +6.350% 23.662704 23.260755 -1.699%
Native Windows Short 2 Slicing 22.389163 23.675692 +5.746% 23.757854 23.476805 -1.183%
Native Windows Short 2 Backprojection 18.208513 17.940357 -1.473% 18.036427 18.463904 +2.370%
Native Windows Short 3 Slicing 22.977481 25.157104 +9.486% 22.437138 22.472225 +0.156%
Native Windows Short 3 Backprojection 18.566155 18.183408 -2.062% 18.998355 18.995845 -0.013%
Native Windows Long Slicing 36.840989 39.047972 +5.991% 34.229222 36.640044 +7.043%
Native Windows Long Backprojection 71.831792 76.028779 +5.843% 72.742826 74.112846 +1.883%
All enabled-operation RAM peaks, coverage and collector costs

Requested interval: 1 second. Peaks below are integer bytes. C/I/D = complete/incomplete/discarded sweep counts; incomplete sweeps do not contribute to a peak. CPU time is collector CPU, not additive wall-time overhead. Observed interval and maximum sweep are seconds.

Linux reports process_tree_pss_bytes; Windows reports process_tree_private_plus_tracked_shared_resident_bytes. These metrics have different semantics and must not be compared as equivalent RAM totals.

Linux / WSL2

Path Operation Pair Status Peak bytes C/I/D Max processes Interval min–max (s) Max sweep (s) CPU (s)
Short 2 Slicing 1 sampled 1,293,188,096 21/0/0 15 1.000004–1.002687 0.257998 1.300033
Short 2 Backprojection 1 partial 1,270,284,288 19/1/0 13 1.000076–1.003468 0.188123 1.043723
Short 2 Slicing 2 sampled 1,218,664,448 20/0/0 15 1.000289–1.000758 0.260997 1.105366
Short 2 Backprojection 2 sampled 1,186,801,664 19/0/0 13 1.000336–1.002650 0.132654 0.895295
Short 3 Slicing 1 sampled 975,772,672 20/0/0 15 1.000266–1.003507 0.226735 1.156992
Short 3 Backprojection 1 sampled 1,266,824,192 20/0/0 13 1.000311–1.006021 0.126517 0.908930
Short 3 Slicing 2 partial 959,497,216 19/1/0 15 1.000303–1.003770 0.189887 1.091917
Short 3 Backprojection 2 sampled 1,229,508,608 19/0/0 13 1.000233–1.004669 0.126205 0.817042
Long Slicing 1 sampled 1,426,011,136 39/0/0 15 1.000304–1.004805 0.518635 5.554739
Long Backprojection 1 partial 1,907,635,200 40/1/0 13 1.000232–1.009037 0.360353 4.887346
Long Slicing 2 partial 1,199,066,112 35/1/0 15 1.000128–1.014650 0.297180 4.270191
Long Backprojection 2 sampled 2,006,608,896 39/0/0 13 1.000216–1.018588 0.460845 4.604758

Native Windows

Path Operation Pair Status Peak bytes C/I/D Max processes Interval min–max (s) Max sweep (s) CPU (s)
Short 2 Slicing 1 partial 1,186,975,744 17/8/0 14 1.000431–1.031384 0.615868 2.796875
Short 2 Backprojection 1 partial 1,514,643,456 16/3/0 10 1.000623–1.043665 0.456005 1.343750
Short 2 Slicing 2 partial 1,155,846,144 16/9/0 14 1.000640–1.013503 0.683083 2.328125
Short 2 Backprojection 2 partial 1,702,633,472 17/3/0 10 1.000587–1.011098 0.532262 1.109375
Short 3 Slicing 1 partial 1,798,139,904 19/7/1 14 1.000583–1.024096 0.642003 2.515625
Short 3 Backprojection 1 partial 1,643,286,528 16/3/1 10 1.000545–1.007961 0.561840 1.312500
Short 3 Slicing 2 partial 1,237,409,792 18/6/0 14 1.000247–1.014465 0.573132 2.218750
Short 3 Backprojection 2 partial 878,329,856 17/3/0 10 1.000699–1.022021 0.639273 1.515625
Long Slicing 1 partial 1,613,201,408 21/19/0 14 1.000064–1.337276 1.336898 4.234375
Long Backprojection 1 partial 2,250,768,384 68/6/0 13 1.000076–2.146619 2.144380 7.156250
Long Slicing 2 partial 1,412,042,752 17/21/0 14 1.000466–1.086031 1.085229 4.171875
Long Backprojection 2 partial 2,300,710,912 63/10/0 13 1.000409–1.940273 1.940107 6.578125

All 12 Windows reports are partial; Linux includes both sampled and partial reports. Recorded incomplete sweeps reflect process exits or changes during collection; Windows additionally invalidates sweeps whose mapping manifests changed. No shared-memory handoff or manifest-publication failure recurred in the new Windows batch. Full error examples, last complete sample, sampling windows and offsets are in the linked raw artifacts.

Coverage limitation remains open: queued resident shared backing can be absent from Linux PSS and Windows working-set scans after the producer closes when no remaining process has touched the pages. An untouched manager mapping keeps the allocation alive but does not fix that accounting gap. Successful sampling does not establish complete backing-residency coverage.

Warmups (excluded from paired overhead calculations)

Each is the one planned off-mode slicing warmup for its path; all succeeded. Times are the data-operation step, not the whole warmup process.

Platform Path Warmup slice (s)
Linux / WSL2 Short 2 5.352138
Linux / WSL2 Short 3 4.799497
Linux / WSL2 Long 176.594914
Native Windows Short 2 24.328004
Native Windows Short 3 23.007805
Native Windows Long 65.059130

Provenance and preserved earlier attempts

The new Windows batch is a fresh complete batch, not a selection of successful retries from the old one. The original Windows batch completed 5 workflows, failed 7 slicing trials and skipped their 7 dependent backprojections; 2 of its 4 completed enabled operations had unavailable RAM. Those outcomes remain recorded separately. The preliminary Linux attempt used a broader timing boundary and was stopped; it is not included in the Linux table above.

Benchmark method and interpretation. Remaining native macOS pipeline / Docker host-delivery validation and the post-rebase Linux rerun are not supplied by these results.

@den-sq
den-sq force-pushed the codex/issue-139-ram-statistics branch from 14078d1 to 60e0dd9 Compare October 17, 2026 19:06
@den-sq
den-sq marked this pull request as ready for review October 17, 2026 22:06
@den-sq

den-sq commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator Author

Fresh real-data benchmarks for the current simplified implementation at 10145cd, on Linux and native Windows. This supersedes the performance interpretation of the earlier working-set/page-tracking benchmark, which does not measure this implementation.

Method: all three original Salivary Duct annotation paths; 120 × 120 uint16 slices at mip 0; adaptive spacing 1 / ratio 0.5; 128 target slices per box; backprojection uses 160³ chunks, zlib and separate output planes. Short 2 = Posterior Salivary Duct 2 (875 slices), Short 3 = Posterior Salivary Duct 3 (887), Long = Posterior Salivary Duct (4,901).

Linux and Windows ran sequentially on the same host. Each platform ran two off/on pairs per path after one off-mode slicing warmup: pair 1 off → on, pair 2 on → off. Each treatment backprojects its own sliced output. Twelve workers, one BLAS/OpenMP thread, shared cached chunks; no pixel hashing/comparison. On enables reporting and memory collection together; off disables both. The Windows runtime retains the previously disclosed temporary CloudFiles zero-width-interval workaround identically in both treatments; it is not a shipped dependency change.

Timing boundary: the tables use the existing slicing/backprojection data-processing step, excluding earlier parsing, geometry and source/cache setup, sampler startup/shutdown, and final statistics-report formatting/writing/delivery. The timed step includes its worker/manager startup and shutdown, scientific downloads, computation, output writes and intermediate cleanup. RAM collection covers the broader Pipeline.process() window, so its sample counts and CPU costs must not be divided by the data-step duration and called overhead. The raw results retain the external pipeline timer separately. CPU cost below is sampler CPU time, including polling and completion of discarded in-flight sweeps; it is not additive wall-time overhead.

Median change is 100 × (on median / off median − 1); MAD is median absolute deviation within each treatment. Both come from the benchmark's existing summary fields; Δ seconds is on median minus off median. Two pairs on a shared development host do not establish a 1% upper bound or identical behavior across platforms. Negative differences indicate measurement variation, not an instrumentation-induced speedup.

Linux / WSL2 — Python 3.11.13, Linux-6.18.54.1-microsoft-standard-WSL2-x86_64-with-glibc2.39. Measurement: sum of process-tree Pss − Pss_Shmem, plus managed resident bytes (process_tree_nonshmem_pss_plus_managed_resident_bytes).

Path Operation Off median s On median s Δ s Median change MAD off / on s
Short 2 Slicing 4.598 4.976 +0.379 +8.237% 0.235 / 0.339
Short 2 Backprojection 4.011 4.318 +0.306 +7.634% 0.250 / 0.297
Short 3 Slicing 4.261 4.759 +0.498 +11.686% 0.019 / 0.176
Short 3 Backprojection 4.286 4.230 -0.056 -1.299% 0.543 / 0.065
Long Slicing 19.528 19.183 -0.344 -1.764% 0.398 / 0.732
Long Backprojection 26.198 24.433 -1.765 -6.737% 1.123 / 0.617

Native Windows — Python 3.11.9, Windows-10-10.0.22631-SP0. Measurement: sum of process-tree PrivateWorkingSetSize, plus managed allocated bytes (process_tree_private_resident_plus_managed_allocated_bytes).

Path Operation Off median s On median s Δ s Median change MAD off / on s
Short 2 Slicing 21.450 21.597 +0.147 +0.684% 0.433 / 0.625
Short 2 Backprojection 18.895 18.547 -0.348 -1.844% 0.347 / 0.017
Short 3 Slicing 21.461 22.781 +1.320 +6.151% 1.010 / 0.092
Short 3 Backprojection 18.447 19.135 +0.688 +3.729% 0.901 / 1.052
Long Slicing 38.122 35.355 -2.768 -7.260% 4.843 / 2.052
Long Backprojection 72.310 72.518 +0.208 +0.288% 1.806 / 0.769

Acceptance update after review: the owner decision on #139 limits 1% engineering acceptance to the measured longer runs; the short-run costs and qualifications below remain unchanged.

Interpretation

  • Linux: Short 2 slicing/backprojection and Short 3 slicing were slower in both pairs. Their median differences (+0.379 s, +0.306 s and +0.498 s) exceed both treatment MADs. The other three median changes were negative. These results do not support a blanket negligible-overhead claim.
  • Windows: Short 3 slicing was slower in both pairs, with a +1.320 s median difference exceeding both MADs. Short 3 backprojection was also slower in both pairs, although its +0.688 s median difference is smaller than both MADs. The remaining positive median changes—Short 2 slicing and long backprojection—were smaller than both MADs and changed sign between pairs.

What memory can be missed:

  • Within Ouroboros' control: one-second sampling can miss brief peaks/children; allocation changes invalidate sweeps (reported as partial coverage below). Named shared-memory segments released by, or allocated outside, SharedNPManager can also be missed while still attached elsewhere. A deliberately retained-buffer Linux fixture demonstrated a 32 MiB omission, but after Fix resident shared-buffer retention from fork-inherited slicing-worker attachments #147's worker-startup fix, the real-data probes attributed the observed large gaps to TIFF backing, not retained shared buffers. The normal pipeline uses manager-owned buffers; these probes do not prove retention is impossible.

  • OS-controlled cache: TIFF pages can remain resident after their process mappings disappear; there is no separate file-cache count or guaranteed eviction. Earlier Linux diagnostics observed additional TIFF residency of 262–263 MiB slicing / 95.05 MiB backprojection for long Salivary, and 240–256 MiB / 35.12 MiB for corrected Daphnia. These are sparse diagnostic observations, not bounds on peak error or current Windows accuracy measurements.

  • Platform definitions: Linux includes other mapped/shared pages proportionally through PSS. Windows excludes other shared pages and adds managed allocated, rather than resident, bytes, potentially overcounting untouched/paged-out managed memory. These named metrics are useful workload estimates, not identical cross-platform totals of physical RAM.

Every pair: data-operation timings in seconds
Platform Path Operation P1 off P1 on P1 change P2 off P2 on P2 change
Linux / WSL2 Short 2 Slicing 4.832 5.316 +10.004% 4.363 4.637 +6.281%
Linux / WSL2 Short 2 Backprojection 4.261 4.614 +8.281% 3.761 4.021 +6.902%
Linux / WSL2 Short 3 Slicing 4.243 4.935 +16.323% 4.280 4.584 +7.090%
Linux / WSL2 Short 3 Backprojection 3.743 4.295 +14.738% 4.829 4.166 -13.730%
Linux / WSL2 Long Slicing 19.925 18.451 -7.397% 19.130 19.915 +4.104%
Linux / WSL2 Long Backprojection 27.322 25.050 -8.313% 25.075 23.816 -5.021%
Native Windows Short 2 Slicing 21.883 22.221 +1.545% 21.017 20.972 -0.213%
Native Windows Short 2 Backprojection 19.242 18.530 -3.703% 18.548 18.563 +0.085%
Native Windows Short 3 Slicing 22.471 22.874 +1.791% 20.451 22.689 +10.942%
Native Windows Short 3 Backprojection 17.546 18.083 +3.060% 19.348 20.187 +4.336%
Native Windows Long Slicing 42.966 37.407 -12.938% 33.279 33.303 +0.071%
Native Windows Long Backprojection 70.504 73.287 +3.947% 74.116 71.749 -3.194%
All 24 enabled-operation memory reports, coverage and collector cost

C/I/D = complete/incomplete/discarded sweeps. Only complete in-window samples contribute to the peak; partial/unavailable reports are shown explicitly. Peak MiB uses 2²⁰ bytes. Window is the broader pipeline window, not the data-step timing above. Each requested interval is one second. Complete-sample counts include setup: a non-null peak does not prove coverage of a short operation's maximum.

Platform Path Operation Pair Status Peak MiB Max processes C/I/D Interval min–max s Window s Max sweep ms CPU s
Linux / WSL2 Short 2 Slicing 1 partial 1203.50 15 19/2/0 1.000279–1.004157 20.564 193.137 1.237
Linux / WSL2 Short 2 Backprojection 1 sampled 1174.27 14 20/0/0 1.000251–1.012764 19.806 249.948 1.219
Linux / WSL2 Short 2 Slicing 2 partial 1140.77 15 18/2/0 1.000280–1.006879 19.830 312.985 1.318
Linux / WSL2 Short 2 Backprojection 2 sampled 1155.16 14 20/0/0 1.000240–1.022885 19.207 181.110 1.148
Linux / WSL2 Short 3 Slicing 1 partial 655.05 15 17/4/0 1.000325–1.002956 20.158 233.689 1.375
Linux / WSL2 Short 3 Backprojection 1 sampled 1233.23 14 20/0/0 1.000269–1.000847 19.500 189.160 1.089
Linux / WSL2 Short 3 Slicing 2 partial 610.39 15 17/3/0 1.000001–1.006081 19.801 338.074 1.235
Linux / WSL2 Short 3 Backprojection 2 sampled 1230.33 14 20/0/0 1.000253–1.002359 19.366 237.971 1.209
Linux / WSL2 Long Slicing 1 partial 1173.04 15 22/13/0 1.000248–1.007752 34.433 271.326 3.466
Linux / WSL2 Long Backprojection 1 sampled 2141.53 14 41/0/0 1.000032–1.006049 40.794 517.144 5.270
Linux / WSL2 Long Slicing 2 partial 1124.07 15 20/16/0 1.000252–1.008294 35.651 400.087 4.297
Linux / WSL2 Long Backprojection 2 sampled 2093.96 14 40/0/0 1.000155–1.011166 39.569 512.914 4.687
Native Windows Short 2 Slicing 1 partial 1667.56 14 21/3/0 1.000071–1.008466 23.223 190.308 1.359
Native Windows Short 2 Backprojection 1 partial 1189.23 10 17/3/0 1.000105–1.003808 19.458 163.151 0.906
Native Windows Short 2 Slicing 2 partial 1793.07 14 20/2/0 1.000480–1.029645 21.930 149.340 0.953
Native Windows Short 2 Backprojection 2 partial 1641.47 10 19/1/0 1.000087–1.026800 19.589 205.263 0.953
Native Windows Short 3 Slicing 1 partial 1739.83 14 22/2/0 1.000518–1.020197 23.792 172.136 1.359
Native Windows Short 3 Backprojection 1 partial 1635.38 10 18/1/0 1.000596–1.004549 19.035 119.063 0.734
Native Windows Short 3 Slicing 2 partial 1689.23 14 21/3/0 1.000059–1.020943 23.655 215.457 1.453
Native Windows Short 3 Backprojection 2 partial 1591.86 10 20/1/1 1.000727–1.014065 21.182 192.728 1.359
Native Windows Long Slicing 1 partial 1926.03 14 31/8/0 1.000624–1.027193 39.093 256.975 2.906
Native Windows Long Backprojection 1 partial 2527.54 13 73/2/0 1.000323–1.046522 74.775 472.958 3.625
Native Windows Long Slicing 2 partial 1823.94 15 31/4/0 1.000199–1.010571 35.016 192.024 2.141
Native Windows Long Backprojection 2 partial 2581.66 13 72/1/0 1.000516–1.108259 73.336 646.981 4.562

Pipeline failures or unavailable reports: none recorded; all 48 measured operations have timing records and all 24 enabled operations have non-null sampled memory peaks.

Recorded incomplete-sweep errors by kind (examples are representative; each occurrence remains represented in C/I/D above):

  • FileNotFoundError: 27 occurrences across 6 reports. Representative examples: [Errno 2] No such file or directory: '/psm_<segment>'.
  • OSError: 39 occurrences across 16 reports. Representative examples: Manager observations changed during memory sweep; Process tree changed during memory sweep.
  • NoSuchProcess: 5 occurrences across 5 reports. Representative examples: process no longer exists (pid=<exited>).

Provenance: both batches require production SHA-256 66ec3675faf7554d423c6b8a6b3b0da98dc43fa1f119e90a0a6611b0520df634, original annotation SHA-256 415049492ae667e2467ac575cc28d51a6254e699c4631e233971e46d4b7a001e, and production_code_unchanged=true. Each includes all 24 operations (12 enabled), plus three excluded warmups. The tables above retain every measured pair and enabled memory report. Canonical benchmark SHA-256: e0dbe2830828c194ca635a181daeef9d11b825936b11ffe358f9ad785f5f2d2d. Native macOS pipeline overhead is not measured here.

Committed raw evidence: Linux, native Windows, and methods/provenance. The table now includes each run's maximum process count and observed interval. Separate short Docker delivery test; native macOS workflow validation is deferred on #139.

@tavateva tavateva left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of 10145cd, graded against #139 (body last edited 2026-10-17 15:28) together with the PR body and both benchmark comments. This supersedes my early review of f732917.

Verdict: changes requested. The verdict rests on two acceptance items that Closes #139 would close while they are unmet: the overhead criterion and deployment validation. Neither is a code defect. Each closes with either evidence or an owner decision recorded on #139.

The redesign itself is a substantial improvement:

  • Measurement now uses process counters plus one contribution per live manager-owned segment, derived from _OwnedSharedMemoryTracker under its own lock.
  • The weak mapping registry, worker-context plumbing, TIFF wrappers and Windows page unions are gone.
  • The production diff is now mostly the collector itself.

Verification

  • Full Linux suite: 352 passed, 2 skipped. CI: 10/10 green.
  • The early-review blocker is closed. I repeated the probe against the live manager and TreeSampler: a pool worker fills a 32 MiB TermedNPArray, then closes it, while the parent holds an untouched attachment.
    • The sampled total rose about 32 MiB above the baseline once the segment was queued: +35.3 MiB, less the 3.6 MiB of worker growth that remains after release.
    • It dropped back after remove_termed, and /dev/shm was empty afterwards.
    • So Pss − Pss_Shmem plus managed mincore residency counts a queued, untouched buffer once, with no double count from the readers.
  • Relied on: the Windows/macOS readers (CI) and the author's real-data benchmark comment.

Blocking

1. The combined overhead criterion is not met, and no owner decision is recorded

#139 applies "the same combined 1% in-operation engineering target, interpreted alongside median absolute deviation and the owner-approved variability-aware assessment". Its last criterion says that if the collector cannot meet both scope and overhead, the PR should "revise the design or obtain an explicit scope decision". The current-implementation benchmark (comment) reports:

  • Linux:
    • Short 2 slicing: +8.24%, Δ +0.379 s.
    • Short 2 backprojection: +7.63%, Δ +0.306 s.
    • Short 3 slicing: +11.69%, Δ +0.498 s.
    • All three were slower in both pairs, with median differences larger than both treatment MADs.
  • Native Windows: Short 3 slicing, +6.15% (Δ +1.320 s), was slower in both pairs and exceeded both MADs.

Under the #138 rule ("an apparent increase smaller than the observed MAD … is accepted"), these do not qualify. The PR body states this itself ("they do not support a blanket negligible-overhead claim"), but still closes #139. #139 has no comments, and its body has not been amended to accept the result.

  • Closure condition: either an owner decision on #139 that accepts these costs (or scopes the target, for example to the long path or to a duration threshold), or a rerun that meets the criterion as written.
  • Narrowest known option: the owner decision. The data-step Δ on the short paths is a roughly fixed 0.3–0.5 s against a 4–5 s step, so the percentage falls as data size grows. That has the same shape as the #138 fixed-cost discussion.
  • Note: two pairs give a weak MAD. That argues for more pairs or an owner judgement, but it does not satisfy the criterion as written.

2. Deployment validation required by #139 is absent for this head

#139: "Validate the default Docker deployment on Linux, Windows, and macOS hosts and the supported native backends." For 10145cd:

  • There is no Docker run on any host. The body does not claim one, and the earlier WSL CLI-in-container run predates the redesign.
  • There is no native macOS pipeline run; the body says "Native macOS pipeline cost remains unmeasured".

The Linux metric now depends on smaps_rollup carrying Pss_Shmem and on mincore of /dev/shm segments. Inside the default container both are plausible but unexercised. A missing Pss_Shmem raises NotImplementedError, so the failure would be explicit, but it is still untested on the default deployment.

  • Closure condition: for this head, a Docker slice and backprojection on each host OS with memory reports present and delivered, plus one native macOS slice and backprojection. Alternatively, an owner decision on #139 that defers named items to a follow-up, with Closes changed to match.

Non-blocking

  • The current-implementation raw results are not committed, while superseded ones are.
    • None of the 11 files in benchmarks/results/ carries the production digest 66ec3675… that the comment cites. The README's #139 sections describe former collectors.
    • The data for the measurement this PR relies on exists only in a comment table. That table also omits per-run process counts, which #139 asks for and which the previous table included.
    • Minimum response: commit the 10145cd artifact and point the README at it. Delete the superseded artifacts, or link them at their original revisions as was done for #140.
  • Pre-implementation disclosure is still not on #139. The body again says the load-bearing decisions were "disclosed before implementation", but #139 has no comments. Minimum response: link where they were disclosed.
  • Leftover diff noise from the removed plumbing:
    • helpers/mem.py gains two blank-line-only additions.
    • backproject_pipeline.py (+6 −2) and slice_parallel_pipeline.py (+2 −2) change only formatting, such as trailing commas and line splits around executor construction. Neither pipeline file has a functional change any more.
    • Minimum response: revert those hunks.
  • The Windows managed term is "allocated", so untouched pages can be overcounted. This is declared, and named distinctly. No action is needed; it is noted because the Windows peaks (1.6–2.6 GiB) are above Linux on the same paths, and readers should not take the gap as a real difference.

@den-sq

den-sq commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

In response to the review of 10145cd, addressed in 3e91580 and the owner decision recorded on #139:

  • Overhead acceptance: Add portable, operation-scoped RAM accounting to shared run statistics #139 and the docs now limit the combined 1% engineering criterion to longer runs, assessed alongside inter-run variation and fixed startup/shutdown costs. The measured long Salivary runs are accepted; the short-path slowdowns remain reported. Timers still include worker/manager lifecycle within the data step, and no statistical upper bound or isolated cause is claimed.
  • Docker delivery: one short real-data slice→backprojection pair passed through the existing Windows/WSL2 container and actual Electron volume server. Both reports reached the host with the final Linux metric, UID 1000 and mode 0600. Slicing: 1,448.38 MiB, partial (29 complete / 1 incomplete); backprojection: 1,751.84 MiB, sampled (10 complete). Host/container source digests match; scratch and report staging cleared, with no managed shared segments left. Raw evidence. This tests development compose with the current source, not a newly built release image or GUI interaction.
  • Deferral: native macOS workflow/performance and macOS-host Docker delivery are explicitly deferred. A separate native-Linux-host Docker run remains unperformed. Removed Closes #139; the issue retains those follow-up checks rather than claiming all hosts were exercised.
  • Non-blocking notes: committed current Linux/Windows raw results and provenance, added process counts/intervals to the benchmark comment, and pointed the README to current evidence. Superseded artifacts are linked at their historical revision. The design decisions are now disclosed on Add portable, operation-scoped RAM accounting to shared run statistics #139, honestly identified as a retrospective record of the implementation conversation. Removed the two blank lines and executor-formatting noise; both pipeline files now match the base branch, and all 46 production Python ASTs match 10145cd.

@tavateva tavateva left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review of 3e91580, diffed against the previously reviewed 10145cd, together with the new PR comment and the #139 body edit and comment (2026-10-17 23:23–23:24).

Verdict: approve. Both blockers are closed on the record.

  1. Overhead criterion: closed by owner decision.
    • The #139 body now limits the combined 1% engineering acceptance to longer runs and accepts the long Salivary Duct results (checked item).
    • The short-path slowdowns remain disclosed, and the issue explicitly says no blanket negligible-overhead claim follows from them.
    • The issue and the PR now describe the same acceptance, which was the closure condition.
  2. Deployment validation: closed by evidence plus a recorded deferral.
    • A Windows/WSL2 Docker slice → backprojection through the real volume server delivered both reports. The raw evidence is in issue-139-docker-review.json.
    • Native-Linux-host Docker, macOS-host Docker and native macOS remain open as named checklist items on #139.
    • Closes #139 has been removed, so the merge leaves those items open, which matches the second closure option.

All four non-blocking notes are resolved:

  • Current results committed: the 10145cd Linux/Windows raw results and provenance are in the repo and carry production digest 66ec3675…. The README now points to them, superseded artifacts are linked at their historical revision, and the benchmark comment includes process counts and intervals.
  • Design disclosure: recorded on #139, and explicitly labelled as a retrospective record.
  • Churn removed: both pipeline files now match main exactly, and the two blank lines in mem.py are gone. 10145cd..3e91580 makes no other production-code change.
  • Windows "allocated" term: documented on #139.

Verification on 3e91580: full Linux suite 352 passed, 2 skipped. CI is green (10/10). The runtime evidence carried forward from the previous review still applies, because the production code is unchanged apart from the reverted formatting: the queued, untouched 32 MiB segment counted once and released cleanly.

@den-sq
den-sq merged commit 6f2df49 into main Oct 17, 2026
10 checks passed
@den-sq
den-sq deleted the codex/issue-139-ram-statistics branch October 17, 2026 23:30
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.

2 participants