{ "kind": "orisys-scene-soak-report", "version": 1, "stage": "docs/architecture/studio-3d-stages.md 阶段 5(长时)", "host": { "os": "Windows 10", "os_family": "windows", "machine": "amd64", "python": "3.10.19", "note": "developer workstation; the release gate is the same command with --minutes 120, on the target machine" }, "method": { "tool": "tools/scene_assets/soak_scene.py", "pipeline": "the real one: a producer thread builds packets, the finger adapter copies them into read-only field frames, a capacity-one mailbox drops the older frame, the composer runs on its own executor, and the coordinator (GUI mode) or the loop (headless mode) consumes the newest. Only the sensor is synthetic.", "sampling": "resident memory is read once per second (GetProcessMemoryInfo on Windows, /proc on Linux) and every sample is kept in the report", "criteria": [ "growth between the first and last quarter under 64 MB", "the rate over the last quarter under --late-rate-limit (default 1.0 MB/min, set from the measurement below)", "the mailbox capacity is 1 and at most one compose is in flight" ], "quarter_rates": "the report keeps the rate of each quarter, because the question is whether the climb is still going when the run stops: a rate that falls quarter by quarter is an allocator settling, a rate that repeats is a leak" }, "runs": { "gui_4min_30fps": { "kind": "orisys-scene-soak-report", "minutes_requested": 4.0, "fps_requested": 30.0, "profile": "desktop33", "window": true, "adapter": "finger", "scene": "synthetic-poc", "rss_available": true, "context": { "renderer": "NVIDIA GeForce RTX 4080 SUPER/PCIe/SSE2", "software_renderer": false }, "mesh": { "sensing_vertices": 9, "field_domain_hw": [ 3, 3 ] }, "ticks": 15579, "frames": { "produced": 7200, "producer_ms": { "p50": 0.0988, "p95": 0.1458, "max": 0.6856, "n": 7200 }, "producer_ms_sampled": 7200, "producer_ms_total": 7200 }, "queue": { "mailbox_capacity": 1, "superseded_by_mailbox": 19, "max_inflight_composes": 1, "superseded_display_frames": 19, "stale_frames": 0, "invalid_frames": 0 }, "rss_mb": { "available": true, "samples": 240, "seconds_per_sample": 1.0, "max_mb": 199.67, "min_mb": 185.79, "first_quarter_mean_mb": 196.28, "last_quarter_mean_mb": 199.11, "growth_mb": 2.83, "after_warmup_growth_mb": 3.05, "late_rate_mb_per_min": 0.8086, "series_mb": [ 185.79, 192.57, 196.74, 196.89, 197.14, 197.36, 196.88, 195.85, 195.92, 196.07, 196.13, 196.2, 196.27, 196.34, 196.34, 196.34, 196.34, 196.36, 196.36, 196.36, 196.41, 196.41, 196.42, 196.43, 196.44, 196.44, 196.5, 196.5, 196.5, 196.5, 196.52, 196.53, 196.53, 196.53, 196.55, 196.55, 196.57, 196.58, 196.58, 196.59, 196.6, 196.61, 196.61, 196.61, 196.61, 196.61, 196.62, 196.62, 196.62, 196.63, 196.64, 196.65, 196.66, 196.66, 196.66, 196.66, 196.67, 196.67, 196.67, 196.62, 196.63, 196.63, 196.64, 196.65, 196.66, 196.67, 196.67, 196.67, 196.67, 196.68, 196.68, 196.68, 196.69, 196.69, 196.7, 196.7, 196.74, 196.75, 196.75, 196.77, 196.77, 196.77, 196.78, 196.78, 196.79, 196.79, 196.79, 196.82, 196.83, 196.84, 196.84, 196.86, 196.86, 196.86, 196.86, 196.88, 196.88, 196.89, 196.89, 196.89, 196.91, 197.17, 197.18, 197.19, 197.2, 197.2, 197.2, 197.2, 197.2, 197.2, 197.21, 197.21, 197.22, 197.23, 197.24, 197.25, 197.26, 197.26, 197.26, 197.27, 197.27, 197.27, 197.29, 197.3, 197.3, 197.3, 197.31, 197.32, 197.32, 197.33, 197.34, 198.59, 198.59, 198.6, 198.6, 198.61, 198.61, 198.61, 198.62, 198.62, 198.64, 198.65, 198.65, 198.66, 198.66, 198.66, 198.67, 198.67, 198.67, 198.68, 198.69, 198.69, 198.7, 198.71, 198.72, 198.72, 198.72, 198.73, 198.73, 198.73, 198.73, 198.74, 198.74, 198.74, 198.75, 198.75, 198.77, 198.78, 198.79, 198.79, 198.79, 198.79, 198.79, 198.8, 198.8, 198.8, 198.83, 198.83, 198.84, 198.85, 198.86, 198.86, 198.86, 198.86, 198.87, 198.88, 198.88, 198.88, 198.89, 198.89, 198.89, 198.91, 198.92, 198.93, 198.94, 198.94, 198.94, 198.94, 198.95, 198.95, 198.95, 198.96, 198.96, 198.97, 198.98, 198.98, 199.0, 199.0, 199.0, 199.0, 199.01, 199.01, 199.02, 199.02, 199.02, 199.03, 199.29, 199.3, 199.31, 199.31, 199.32, 199.32, 199.33, 199.33, 199.33, 199.33, 199.34, 199.35, 199.36, 199.36, 199.38, 199.39, 199.39, 199.39, 199.39, 199.39, 199.4, 199.4, 199.41, 199.67 ] }, "late_rate_limit_mb_per_min": 1.0, "verdict": "ok", "exit_code": 0 }, "headless_10min_60fps": { "kind": "orisys-scene-soak-report", "minutes_requested": 10.0, "fps_requested": 60.0, "profile": "desktop33", "window": false, "adapter": "finger", "scene": "synthetic-poc", "rss_available": true, "mesh": { "sensing_vertices": 9, "field_domain_hw": [ 3, 3 ] }, "ticks": 38665, "frames": { "produced": 35980, "producer_ms": { "p50": 0.0932, "p95": 0.1575, "max": 1.717, "n": 15980 }, "producer_ms_sampled": 15980, "producer_ms_total": 35980 }, "queue": { "mailbox_capacity": 1, "superseded_by_mailbox": 5647, "max_inflight_composes": 1 }, "rss_mb": { "available": true, "samples": 597, "seconds_per_sample": 1.0, "max_mb": 42.33, "min_mb": 36.46, "first_quarter_mean_mb": 40.41, "last_quarter_mean_mb": 41.77, "growth_mb": 1.35, "after_warmup_growth_mb": 1.91, "late_rate_mb_per_min": 0.3539, "series_mb": [ 36.46, 36.46, 36.46, 36.46, 39.9, 39.9, 39.9, 39.91, 39.92, 39.92, 39.93, 39.94, 39.95, 39.96, 39.96, 39.98, 39.98, 39.99, 40.0, 40.01, 40.01, 40.01, 40.02, 40.03, 40.03, 40.04, 40.05, 40.05, 40.06, 40.07, 40.08, 40.09, 40.09, 40.09, 40.08, 40.08, 40.09, 40.1, 40.11, 40.12, 40.37, 40.38, 40.39, 40.4, 40.4, 40.41, 40.41, 40.41, 40.42, 40.42, 40.43, 40.43, 40.44, 40.45, 40.46, 40.46, 40.46, 40.48, 40.48, 40.43, 40.43, 40.43, 40.44, 40.44, 40.45, 40.46, 40.46, 40.48, 40.48, 40.5, 40.5, 40.5, 40.51, 40.52, 40.52, 40.52, 40.53, 40.54, 40.54, 40.55, 40.55, 40.57, 40.57, 40.58, 40.58, 40.58, 40.59, 40.62, 40.63, 40.63, 40.64, 40.65, 40.66, 40.67, 40.67, 40.69, 40.69, 40.69, 40.7, 40.71, 40.71, 40.71, 40.72, 40.72, 40.73, 40.73, 40.75, 40.75, 40.76, 40.77, 40.78, 40.79, 40.79, 40.79, 40.8, 40.8, 40.81, 40.82, 40.82, 40.82, 40.84, 40.85, 40.85, 40.85, 40.92, 40.92, 40.93, 40.94, 40.94, 40.94, 40.96, 40.96, 40.96, 40.98, 40.98, 41.0, 41.0, 41.0, 41.01, 41.08, 41.09, 41.09, 41.1, 41.1, 41.11, 41.12, 41.12, 41.13, 41.14, 41.15, 41.15, 41.15, 41.16, 41.17, 41.17, 41.17, 41.18, 38.82, 38.83, 38.83, 38.84, 38.86, 38.86, 38.86, 38.87, 38.87, 38.88, 38.88, 38.88, 38.89, 38.9, 38.9, 38.91, 38.92, 39.07, 39.07, 39.07, 39.07, 39.08, 39.08, 39.09, 39.1, 39.1, 39.11, 39.12, 39.12, 39.13, 39.13, 39.15, 39.15, 39.16, 39.16, 39.16, 39.16, 39.18, 39.18, 39.18, 39.19, 39.2, 39.22, 39.23, 39.23, 39.24, 39.24, 39.25, 39.25, 39.25, 39.26, 39.27, 39.27, 39.28, 39.29, 39.3, 39.3, 39.32, 39.32, 39.32, 39.33, 39.33, 39.34, 39.34, 39.34, 39.36, 39.46, 39.47, 39.48, 39.49, 39.5, 39.5, 39.5, 39.5, 39.51, 39.52, 39.52, 39.53, 39.55, 39.55, 39.56, 39.57, 39.57, 39.59, 39.59, 39.59, 39.6, 39.61, 39.61, 39.62, 39.62, 39.62, 39.63, 39.65, 39.77, 39.78, 39.79, 39.79, 39.8, 39.8, 39.81, 39.81, 39.81, 39.82, 39.83, 39.84, 39.84, 39.85, 39.86, 39.88, 39.88, 39.88, 39.89, 39.89, 39.89, 39.9, 39.91, 39.91, 39.92, 39.93, 39.93, 39.95, 39.95, 39.95, 39.96, 39.96, 40.1, 40.1, 40.11, 40.11, 40.12, 40.14, 40.14, 40.15, 40.16, 40.17, 40.17, 40.17, 40.18, 40.18, 40.31, 40.31, 40.32, 40.33, 40.33, 40.34, 40.35, 40.36, 40.36, 40.38, 40.38, 40.38, 40.39, 40.39, 40.39, 40.4, 40.41, 40.67, 40.68, 40.69, 40.7, 40.7, 40.71, 40.71, 40.71, 40.71, 40.72, 40.72, 40.73, 40.73, 40.73, 40.75, 40.76, 40.77, 40.77, 40.77, 40.78, 40.78, 40.78, 40.78, 40.78, 40.79, 40.79, 40.8, 40.8, 40.81, 40.82, 40.83, 40.83, 40.83, 40.83, 40.83, 40.84, 40.84, 40.84, 40.84, 40.85, 40.86, 40.86, 40.87, 40.87, 40.88, 40.88, 40.88, 40.89, 40.89, 40.89, 40.89, 40.9, 40.9, 40.91, 40.91, 40.92, 40.93, 40.94, 40.94, 40.94, 40.94, 40.94, 40.95, 40.95, 40.95, 40.96, 40.96, 40.97, 40.98, 40.98, 40.98, 40.98, 40.99, 40.99, 41.0, 41.0, 41.0, 41.0, 41.0, 41.01, 41.02, 41.02, 41.03, 41.04, 41.02, 41.02, 41.02, 41.02, 41.02, 41.02, 41.03, 41.03, 41.03, 41.04, 41.04, 41.05, 41.06, 41.06, 41.06, 41.06, 41.07, 41.07, 41.07, 41.07, 41.08, 41.08, 41.09, 41.09, 41.1, 41.11, 41.11, 41.11, 41.11, 41.12, 41.12, 41.12, 41.12, 41.13, 41.14, 41.14, 41.15, 41.15, 41.16, 41.16, 41.16, 41.16, 41.17, 41.17, 41.17, 41.18, 41.18, 41.18, 41.2, 41.45, 41.45, 41.46, 41.47, 41.47, 41.48, 41.48, 41.48, 41.48, 41.48, 41.49, 41.49, 41.5, 41.51, 41.52, 41.52, 41.52, 41.52, 41.52, 41.52, 41.53, 41.53, 41.53, 41.54, 41.55, 41.55, 41.56, 41.56, 41.57, 41.57, 41.57, 41.58, 41.58, 41.58, 41.58, 41.59, 41.59, 41.59, 41.59, 41.6, 41.61, 41.61, 41.61, 41.62, 41.62, 41.62, 41.63, 41.64, 41.64, 41.64, 41.65, 41.66, 41.66, 41.66, 41.67, 41.68, 41.68, 41.69, 41.69, 41.69, 41.69, 41.69, 41.7, 41.7, 41.7, 41.72, 41.73, 41.73, 41.73, 41.73, 41.73, 41.73, 41.73, 41.74, 41.75, 41.75, 41.75, 41.76, 41.77, 41.77, 41.79, 41.79, 41.79, 41.79, 41.79, 41.8, 41.8, 41.8, 41.8, 41.81, 41.81, 41.81, 41.82, 41.84, 41.84, 41.84, 41.84, 41.84, 41.84, 41.84, 41.84, 41.85, 41.86, 41.86, 41.87, 41.88, 41.88, 41.89, 41.89, 41.89, 41.89, 41.9, 41.9, 41.91, 41.91, 41.91, 41.92, 41.92, 41.92, 41.93, 41.94, 41.94, 41.94, 41.94, 41.95, 41.95, 41.95, 41.95, 41.96, 41.96, 41.97, 41.97, 41.98, 41.98, 41.99, 41.99, 41.99, 41.99, 42.0, 42.0, 42.0, 42.26, 42.27, 42.27, 42.28, 42.28, 42.29, 42.29, 42.33, 42.33 ] }, "late_rate_limit_mb_per_min": 1.0, "verdict": "ok", "exit_code": 0 } }, "findings": [ "No retained Python object was found. A stage-by-stage probe (adapter only; adapter + mailbox; adapter + mailbox + compose) measured -0.01 MB over 40 s for the mailbox-only loop and 0.13 MB/min for the full loop, and forcing gc.collect() every 3 s made RSS grow *faster* (3.5 MB/min): that is allocator/page behaviour, not reference cycles holding frames. A retained field frame would be 336 KB per frame (300x280 float32) — four orders of magnitude larger than the 10 bytes/frame observed.", "The headless tail rate is about 0.35 MB/min (quarter rates 1.885 / -0.338 / 0.358 / 0.354 MB/min: warm-up, then a constant tail). Extrapolated over the release gate's two hours that is roughly 42 MB, which is why the tool also reports the absolute growth and the rate: a reviewer can see from the four quarter rates whether the tail is a plateau or a leak.", "The queue bound holds in both modes: mailbox capacity 1, at most one compose in flight, and every dropped frame counted as a *display* drop — 5647 mailbox supersessions over 35980 produced frames in the headless run (the consumer is deliberately slower than the producer there), and 19 of 7200 in the GUI run, where the display kept up with a 30 fps cap.", "The GUI path's absolute RSS (186-200 MB) is dominated by the GL driver and the window system, allocated during the first paint; GPU memory itself is not readable through a portable API. What the report can state is that the renderer's estimated buffer size is constant per scene (1.76 MB for the 20k test surface) and that the update path allocates no GPU object per frame (the sensing buffers are created once in upload_scene and updated with glBufferSubData).", "The GUI tail rate (0.81 MB/min) is roughly twice the headless one (0.35 MB/min). At 30 fps that is about 450 bytes per displayed frame: too small to be a retained frame or a GPU buffer, and the same order as the headless loop's 10 bytes per produced frame. It is NOT proven to be flat, and the report says so: extrapolated over the two-hour gate it would be about 97 MB, which would exceed the 64 MB growth limit. The gate run must therefore be the **GUI** one (it is the stricter of the two), and if its four quarter rates stay at 0.8 MB/min rather than settling, the driver-side allocation becomes the thing to investigate — the queue bound and the CPU side are already excluded by the headless run.", "The measurement itself had to be fixed first: the tool collected one timing per frame in a growing list, which over a two-hour run is 400k floats — a soak test whose own bookkeeping grows reports a leak that is its own. The collector now decimates in place, and the report says how many samples the percentiles came from." ], "not_measured_here": [ "the two-hour release gate run (the tool takes the duration as an argument; this session's evidence is 14 minutes of running in total)", "GPU memory over time, for the reason above", "the ARM boards (deferred at the user's request; the same command runs there)" ] }