3030
3131from contracts import RuntimeSample
3232
33- # Map the schema's rendering-backend vocabulary to the gate's render-preset
34- # tokens used in tasks.json / backend_identity. ``"none"`` (headless, no camera)
35- # maps to ``None``.
3633_SCHEMA_RENDER_TO_GATE : dict [str | None , str | None ] = {
3734 None : None ,
3835 "" : None ,
4441
4542
4643def _as_dict (value : Any ) -> dict :
47- """Return ``value`` if it is a dict, else an empty dict.
48-
49- Bundle sections are always dicts in a valid schema-v1 file; this keeps a
50- malformed/hand-edited bundle (e.g. a list where a dict is expected) from
51- crashing the projection so the gate degrades gracefully instead of the
52- result builder aborting with no output.
53- """
44+ """Return ``value`` if it is a dict, else an empty dict."""
5445 return value if isinstance (value , dict ) else {}
5546
5647
5748def steady_state_slice (step_times : list [float ], warmup_frames : int ) -> tuple [list [float ], int ]:
58- """Drop the leading ``warmup_frames`` cold-start steps, keeping >=1 frame.
59-
60- Producer-side helper used by ``perf_runtime.py`` to exclude warmup at the
61- source before aggregation. If ``warmup_frames`` would leave nothing, it is
62- clamped to ``len(step_times) - 1`` so the aggregate never silently falls back
63- to the full, cold-start-inclusive series (which would misreport non-steady
64- numbers as steady-state).
49+ """Drop leading cold-start steps while retaining at least one frame.
6550
6651 Args:
6752 step_times: Per-step wall times [s], in order.
6853 warmup_frames: Requested number of leading steps to discard.
6954
7055 Returns:
71- ``(measured_step_times, warmup_applied)`` where ``warmup_applied`` is the
72- number of leading steps actually discarded (may be clamped below the
73- request).
56+ Measured step times and the number of warmup frames actually removed.
7457 """
75- n = len (step_times )
76- if n == 0 :
58+ if not step_times :
7759 return [], 0
78- warmup = max (0 , min (warmup_frames , n - 1 ))
60+ warmup = max (0 , min (warmup_frames , len ( step_times ) - 1 ))
7961 return list (step_times [warmup :]), warmup
8062
8163
82- def load_info (info_path : Path ) -> dict | None :
83- """Load the benchmark info JSON, or ``None`` if it is missing/ unreadable."""
64+ def load_info (info_path : Path ) -> object | None :
65+ """Load benchmark JSON, or ``None`` when it is missing or unreadable."""
8466 try :
85- data = json .loads (Path (info_path ).read_text ())
67+ return json .loads (Path (info_path ).read_text ())
8668 except Exception :
8769 return None
88- return data if isinstance (data , dict ) else None
8970
9071
9172def is_runtime_bundle (data : Any ) -> bool :
92- """Return True when ``data`` looks like a schema-v1 runtime/training bundle."""
73+ """Return whether ``data`` looks like a schema-v1 runtime/training bundle."""
9374 return (
9475 isinstance (data , dict )
9576 and isinstance (data .get ("run" ), dict )
@@ -99,7 +80,7 @@ def is_runtime_bundle(data: Any) -> bool:
9980
10081
10182def gpu_driver_version () -> str | None :
102- """Return the GPU driver version from nvidia-smi, or ``None`` if unavailable ."""
83+ """Return the GPU driver version from `` nvidia-smi``, when available ."""
10384 try :
10485 result = subprocess .run (
10586 ["nvidia-smi" , "--query-gpu=driver_version" , "--format=csv,noheader,nounits" ],
@@ -116,7 +97,7 @@ def gpu_driver_version() -> str | None:
11697
11798
11899def _current_gpu (bundle : dict ) -> dict :
119- """Return the first GPU device dict from the hardware snapshot (or ``{}``) ."""
100+ """Return the first GPU device dictionary ."""
120101 devices = _as_dict (bundle .get ("hardware" )).get ("gpu_devices" ) or []
121102 return devices [0 ] if devices and isinstance (devices [0 ], dict ) else {}
122103
@@ -129,53 +110,40 @@ def render_backend(bundle: dict) -> str | None:
129110
130111
131112def fps_stats (bundle : dict ) -> dict :
132- """Return ``raw_fps_{mean,std,min,max}`` from the bundle's runtime aggregates.
133-
134- ``mean``/``std``/``max`` come from ``total_fps``; ``min`` (worst steady-state
135- frame) is recovered from the slowest step time. Percentile fields are not
136- available in the schema and are intentionally omitted.
137- """
113+ """Return steady-state FPS statistics from runtime aggregates."""
138114 runtime = _as_dict (bundle .get ("runtime" ))
139115 total_fps = _as_dict (runtime .get ("total_fps" ))
140- iter_time = _as_dict (runtime .get ("iteration_time_s" ))
141- steps_per_iter = runtime .get ("steps_per_iteration" ) or _as_dict (bundle .get ("run" )).get ("num_envs" )
142-
143- out : dict = {}
116+ iteration_time = _as_dict (runtime .get ("iteration_time_s" ))
117+ steps_per_iteration = runtime .get ("steps_per_iteration" ) or _as_dict (bundle .get ("run" )).get ("num_envs" )
118+ output : dict [str , float ] = {}
144119 if isinstance (total_fps .get ("mean" ), (int , float )):
145- out ["raw_fps_mean" ] = float (total_fps ["mean" ])
120+ output ["raw_fps_mean" ] = float (total_fps ["mean" ])
146121 if isinstance (total_fps .get ("std" ), (int , float )):
147- out ["raw_fps_std" ] = float (total_fps ["std" ])
122+ output ["raw_fps_std" ] = float (total_fps ["std" ])
148123 if isinstance (total_fps .get ("peak" ), (int , float )):
149- out ["raw_fps_max" ] = float (total_fps ["peak" ])
150- peak_step = iter_time .get ("peak" )
151- if isinstance (peak_step , (int , float )) and peak_step > 0 and steps_per_iter :
152- out ["raw_fps_min" ] = float (steps_per_iter ) / float (peak_step )
153- return out
124+ output ["raw_fps_max" ] = float (total_fps ["peak" ])
125+ peak_step = iteration_time .get ("peak" )
126+ if isinstance (peak_step , (int , float )) and peak_step > 0 and steps_per_iteration :
127+ output ["raw_fps_min" ] = float (steps_per_iteration ) / float (peak_step )
128+ return output
154129
155130
156131def startup_seconds (bundle : dict ) -> float | None :
157- """Return total launch-to-first-step wall time [s] (sum of startup phases) ."""
132+ """Return total launch-to-first-step wall time [s]."""
158133 startup = _as_dict (_as_dict (bundle .get ("runtime" )).get ("startup_time_s" ))
159- values = [v for v in startup .values () if isinstance (v , (int , float ))]
134+ values = [value for value in startup .values () if isinstance (value , (int , float ))]
160135 return float (sum (values )) if values else None
161136
162137
163138def provenance (bundle : dict ) -> dict :
164- """Return ``{hardware, software, git}`` for the runtime-compatibility contract.
165-
166- ``software`` is the bundle's typed ``versions`` map verbatim (its field names
167- — ``isaaclab``/``isaacsim``/``torch``/``warp``/``isaaclab_physx``/
168- ``isaaclab_newton``/``newton``/``isaaclab_ov`` — match the contract policy
169- paths, so the ``runtime_contract_hash`` is preserved across the migration).
170- """
139+ """Return hardware, software, and Git runtime provenance."""
171140 versions = _as_dict (bundle .get ("versions" ))
172141 hardware_snapshot = _as_dict (bundle .get ("hardware" ))
173142 gpu = _current_gpu (bundle )
174-
175- software = {k : v for k , v in versions .items () if v is not None and not k .startswith ("git_" )}
143+ software = {key : value for key , value in versions .items () if value is not None and not key .startswith ("git_" )}
176144 hardware = {
177- k : v
178- for k , v in {
145+ key : value
146+ for key , value in {
179147 "cpu_name" : hardware_snapshot .get ("cpu_name" ),
180148 "cpu_physical_cores" : hardware_snapshot .get ("cpu_count" ),
181149 "total_ram_gb" : hardware_snapshot .get ("ram_gb" ),
@@ -184,7 +152,7 @@ def provenance(bundle: dict) -> dict:
184152 "gpu_total_memory_gb" : gpu .get ("mem_gb" ),
185153 "gpu_compute_capability" : gpu .get ("compute_cap" ),
186154 }.items ()
187- if v is not None
155+ if value is not None
188156 }
189157 git = {
190158 gate_key : versions [schema_key ]
@@ -249,11 +217,11 @@ def runtime_resources(bundle: dict) -> dict:
249217 "system_ram_peak_mb" : _gb_to_mb (ram .get ("peak" )),
250218 "cpu_util_pct" : _pct (cpu_util .get ("mean" )),
251219 }
252- return {k : v for k , v in diag .items () if v is not None }
220+ return {key : value for key , value in diag .items () if value is not None }
253221
254222
255223def benchmark_info (bundle : dict ) -> dict :
256- """Return the run's self-reported identity for launch/run drift checks ."""
224+ """Return the run's self-reported workload identity ."""
257225 run = _as_dict (bundle .get ("run" ))
258226 config = _as_dict (run .get ("config" ))
259227 extra = _as_dict (bundle .get ("extra" ))
@@ -268,15 +236,11 @@ def benchmark_info(bundle: dict) -> dict:
268236 "render_backend" : render_backend (bundle ),
269237 "presets" : config .get ("presets" ) or [],
270238 }
271- return {k : v for k , v in info .items () if v is not None }
239+ return {key : value for key , value in info .items () if value is not None }
272240
273241
274242def project_runtime (bundle : dict ) -> RuntimeSample | None :
275- """Project a runtime bundle into a typed :class:`~contracts.RuntimeSample`.
276-
277- Returns ``None`` when ``bundle`` is not a valid schema-v1 runtime bundle, so the
278- caller can degrade to a HARD_FAILURE (missing benchmark output).
279- """
243+ """Project one RuntimeBundle into a canonical runtime sample."""
280244 if not is_runtime_bundle (bundle ):
281245 return None
282246 stats = fps_stats (bundle )
@@ -299,3 +263,9 @@ def project_runtime(bundle: dict) -> RuntimeSample | None:
299263 provenance = provenance (bundle ),
300264 runtime_resources = runtime_resources (bundle ),
301265 )
266+
267+
268+ def project_sample (payload : object , * , warmup_frames : int = 0 ) -> RuntimeSample | None :
269+ """Project the pinned RuntimeBundle payload into the canonical sample."""
270+ del warmup_frames # warmup is applied by perf_runtime.py before aggregation
271+ return project_runtime (payload ) if is_runtime_bundle (payload ) else None
0 commit comments