Skip to content

Commit 979a9e0

Browse files
Add opt-in --warmup_steps to exclude benchmark cold-start
Add a warmup_steps parameter to EnvironmentStepTimingRecorder that drops the first N ``env.step()`` calls (CUDA graph capture, lazy kernel compilation) from the recorded environment-step timing. In serialized mode the skipped steps' simulation call-count and time are rolled back so the recorded aggregate stays consistent. Expose it as an opt-in ``--warmup_steps`` flag (default 0, validated non-negative, recorded in metadata) on the eight RL train/play benchmark adapters. ``runtime.py`` is unchanged: its ``--warmup_frames`` already excludes the startup step before the recorder is installed. Add recorder unit tests for the host-return and serialized exclusion paths and a parse-level test rejecting a negative ``--warmup_steps``.
1 parent 058dd8b commit 979a9e0

12 files changed

Lines changed: 168 additions & 15 deletions

scripts/benchmarks/rl_games/benchmark_rl_games_play.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ def _parse_args(argv: list[str]):
6363
action="store_true",
6464
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
6565
)
66+
parser.add_argument(
67+
"--warmup_steps",
68+
type=int,
69+
default=0,
70+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
71+
)
6672
parser.add_argument(
6773
"--benchmark_formatter",
6874
type=str,
@@ -78,6 +84,8 @@ def _parse_args(argv: list[str]):
7884
args_cli, remaining_args = setup_preset_cli(parser, argv)
7985
if args_cli.num_frames <= 0:
8086
parser.error("--num_frames must be greater than zero")
87+
if args_cli.warmup_steps < 0:
88+
parser.error("--warmup_steps must be non-negative")
8189
sys.argv = [sys.argv[0]] + remaining_args
8290

8391
return args_cli, remaining_args
@@ -170,6 +178,7 @@ def run(argv: list[str]) -> None:
170178
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
171179
),
172180
},
181+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
173182
{"name": "presets", "data": ",".join(cfg.presets)},
174183
]
175184
},
@@ -231,7 +240,9 @@ def policy(obs):
231240
return agent.get_action(obs, is_deterministic=agent.is_deterministic)
232241

233242
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
234-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
243+
env,
244+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
245+
warmup_steps=args_cli.warmup_steps,
235246
)
236247
with environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
237248
step_times, reward, ep_length, success_rate = stepping.run_play_loop(env, policy, args_cli.num_frames)

scripts/benchmarks/rl_games/benchmark_rl_games_train.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ def _parse_args(argv: list[str]):
5555
action="store_true",
5656
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
5757
)
58+
parser.add_argument(
59+
"--warmup_steps",
60+
type=int,
61+
default=0,
62+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
63+
)
5864
parser.add_argument(
5965
"--benchmark_formatter",
6066
type=str,
@@ -88,6 +94,8 @@ def _parse_args(argv: list[str]):
8894
args_cli, remaining_args = setup_preset_cli(parser, argv)
8995
if args_cli.max_iterations is not None and args_cli.max_iterations <= 0:
9096
parser.error("--max_iterations must be greater than zero")
97+
if args_cli.warmup_steps < 0:
98+
parser.error("--warmup_steps must be non-negative")
9199
enable_cameras_for_video(args_cli)
92100
sys.argv = [sys.argv[0]] + remaining_args
93101

@@ -189,6 +197,7 @@ def run(argv: list[str]) -> None:
189197
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
190198
),
191199
},
200+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
192201
{"name": "presets", "data": ",".join(cfg.presets)},
193202
]
194203
},
@@ -234,7 +243,9 @@ def run(argv: list[str]) -> None:
234243
runner.reset()
235244

236245
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
237-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
246+
env,
247+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
248+
warmup_steps=args_cli.warmup_steps,
238249
)
239250
with environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
240251
runner.run({"train": True, "play": False, "sigma": None})

scripts/benchmarks/rsl_rl/benchmark_rsl_rl_play.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ def _parse_args(argv: list[str]) -> tuple[argparse.Namespace, list[str]]:
6565
action="store_true",
6666
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
6767
)
68+
parser.add_argument(
69+
"--warmup_steps",
70+
type=int,
71+
default=0,
72+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
73+
)
6874
parser.add_argument(
6975
"--benchmark_formatter",
7076
type=str,
@@ -80,6 +86,8 @@ def _parse_args(argv: list[str]) -> tuple[argparse.Namespace, list[str]]:
8086
args, remaining = setup_preset_cli(parser, argv)
8187
if args.num_frames <= 0:
8288
parser.error("--num_frames must be greater than zero")
89+
if args.warmup_steps < 0:
90+
parser.error("--warmup_steps must be non-negative")
8391
sys.argv = [sys.argv[0]] + remaining
8492
return args, remaining
8593

@@ -168,6 +176,7 @@ def run(argv: list[str]) -> None:
168176
"serialized_synchronized" if args.measure_synchronized_step_breakdown else "host_return"
169177
),
170178
},
179+
{"name": "environment_step_warmup_steps", "data": args.warmup_steps},
171180
{"name": "presets", "data": ",".join(cfg.presets)},
172181
]
173182
},
@@ -192,7 +201,9 @@ def run(argv: list[str]) -> None:
192201
policy = runner.get_inference_policy(device=env.unwrapped.device)
193202

194203
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
195-
env, measure_synchronized_step_breakdown=args.measure_synchronized_step_breakdown
204+
env,
205+
measure_synchronized_step_breakdown=args.measure_synchronized_step_breakdown,
206+
warmup_steps=args.warmup_steps,
196207
)
197208
with environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
198209
step_times, reward, ep_length, success_rate = stepping.run_play_loop(env, policy, args.num_frames)

scripts/benchmarks/rsl_rl/benchmark_rsl_rl_train.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ def _parse_args(argv: list[str]):
6565
action="store_true",
6666
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
6767
)
68+
parser.add_argument(
69+
"--warmup_steps",
70+
type=int,
71+
default=0,
72+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
73+
)
6874
parser.add_argument(
6975
"--benchmark_formatter",
7076
type=str,
@@ -98,6 +104,8 @@ def _parse_args(argv: list[str]):
98104
args_cli, remaining_args = setup_preset_cli(parser, argv)
99105
if args_cli.max_iterations is not None and args_cli.max_iterations <= 0:
100106
parser.error("--max_iterations must be greater than zero")
107+
if args_cli.warmup_steps < 0:
108+
parser.error("--warmup_steps must be non-negative")
101109
enable_cameras_for_video(args_cli)
102110
sys.argv = [sys.argv[0]] + remaining_args
103111

@@ -194,6 +202,7 @@ def run(argv: list[str]) -> None:
194202
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
195203
),
196204
},
205+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
197206
{"name": "presets", "data": ",".join(cfg.presets)},
198207
]
199208
},
@@ -232,7 +241,9 @@ def run(argv: list[str]) -> None:
232241
)
233242

234243
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
235-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
244+
env,
245+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
246+
warmup_steps=args_cli.warmup_steps,
236247
)
237248
with early, environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
238249
runner.learn(num_learning_iterations=agent_cfg.max_iterations, init_at_random_ep_len=True)

scripts/benchmarks/sb3/benchmark_sb3_play.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ def _parse_args(argv: list[str]):
7171
action="store_true",
7272
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
7373
)
74+
parser.add_argument(
75+
"--warmup_steps",
76+
type=int,
77+
default=0,
78+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
79+
)
7480
parser.add_argument(
7581
"--benchmark_formatter",
7682
type=str,
@@ -86,6 +92,8 @@ def _parse_args(argv: list[str]):
8692
args_cli, remaining_args = setup_preset_cli(parser, argv)
8793
if args_cli.num_frames <= 0:
8894
parser.error("--num_frames must be greater than zero")
95+
if args_cli.warmup_steps < 0:
96+
parser.error("--warmup_steps must be non-negative")
8997
sys.argv = [sys.argv[0]] + remaining_args
9098

9199
return args_cli, remaining_args
@@ -171,6 +179,7 @@ def run(argv: list[str]) -> None:
171179
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
172180
),
173181
},
182+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
174183
{"name": "presets", "data": ",".join(cfg.presets)},
175184
]
176185
},
@@ -222,7 +231,9 @@ def policy(obs):
222231
return actions
223232

224233
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
225-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
234+
env,
235+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
236+
warmup_steps=args_cli.warmup_steps,
226237
)
227238
with environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
228239
step_times, reward, ep_length, success_rate = stepping.run_play_loop(env, policy, args_cli.num_frames)

scripts/benchmarks/sb3/benchmark_sb3_train.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ def _parse_args(argv: list[str]):
129129
action="store_true",
130130
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
131131
)
132+
parser.add_argument(
133+
"--warmup_steps",
134+
type=int,
135+
default=0,
136+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
137+
)
132138
parser.add_argument(
133139
"--benchmark_formatter",
134140
type=str,
@@ -160,6 +166,8 @@ def _parse_args(argv: list[str]):
160166
args_cli, remaining_args = setup_preset_cli(parser, argv)
161167
if args_cli.max_iterations is not None and args_cli.max_iterations <= 0:
162168
parser.error("--max_iterations must be greater than zero")
169+
if args_cli.warmup_steps < 0:
170+
parser.error("--warmup_steps must be non-negative")
163171
enable_cameras_for_video(args_cli)
164172
sys.argv = [sys.argv[0]] + remaining_args
165173

@@ -256,6 +264,7 @@ def run(argv: list[str]) -> None:
256264
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
257265
),
258266
},
267+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
259268
{"name": "presets", "data": ",".join(cfg.presets)},
260269
]
261270
},
@@ -312,7 +321,9 @@ def run(argv: list[str]) -> None:
312321
checkpoint_callback = CheckpointCallback(save_freq=1000, save_path=log_dir, name_prefix="model", verbose=2)
313322

314323
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
315-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
324+
env,
325+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
326+
warmup_steps=args_cli.warmup_steps,
316327
)
317328
with (
318329
contextlib.suppress(KeyboardInterrupt),

scripts/benchmarks/skrl/benchmark_skrl_play.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ def _parse_args(argv: list[str]):
8484
action="store_true",
8585
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
8686
)
87+
parser.add_argument(
88+
"--warmup_steps",
89+
type=int,
90+
default=0,
91+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
92+
)
8793
parser.add_argument(
8894
"--benchmark_formatter",
8995
type=str,
@@ -99,6 +105,8 @@ def _parse_args(argv: list[str]):
99105
args_cli, remaining_args = setup_preset_cli(parser, argv)
100106
if args_cli.num_frames <= 0:
101107
parser.error("--num_frames must be greater than zero")
108+
if args_cli.warmup_steps < 0:
109+
parser.error("--warmup_steps must be non-negative")
102110
sys.argv = [sys.argv[0]] + remaining_args
103111

104112
return args_cli, remaining_args
@@ -200,6 +208,7 @@ def run(argv: list[str]) -> None:
200208
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
201209
),
202210
},
211+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
203212
{"name": "presets", "data": ",".join(cfg.presets)},
204213
]
205214
},
@@ -244,7 +253,9 @@ def policy(obs):
244253
return outputs[-1].get("mean_actions", outputs[0])
245254

246255
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
247-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
256+
env,
257+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
258+
warmup_steps=args_cli.warmup_steps,
248259
)
249260
with environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
250261
step_times, reward, ep_length, success_rate = stepping.run_play_loop(env, policy, args_cli.num_frames)

scripts/benchmarks/skrl/benchmark_skrl_train.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ def _parse_args(argv: list[str]):
166166
action="store_true",
167167
help="Measure a serialized synchronized simulation and outside-simulation step breakdown.",
168168
)
169+
parser.add_argument(
170+
"--warmup_steps",
171+
type=int,
172+
default=0,
173+
help="Exclude the first N env.step() calls from environment-step timing (cold-start). Opt-in; default 0.",
174+
)
169175
parser.add_argument(
170176
"--benchmark_formatter",
171177
type=str,
@@ -200,6 +206,8 @@ def _parse_args(argv: list[str]):
200206
args_cli, remaining_args = setup_preset_cli(parser, argv)
201207
if args_cli.max_iterations is not None and args_cli.max_iterations <= 0:
202208
parser.error("--max_iterations must be greater than zero")
209+
if args_cli.warmup_steps < 0:
210+
parser.error("--warmup_steps must be non-negative")
203211
enable_cameras_for_video(args_cli)
204212
sys.argv = [sys.argv[0]] + remaining_args
205213

@@ -320,6 +328,7 @@ def run(argv: list[str]) -> None:
320328
"serialized_synchronized" if args_cli.measure_synchronized_step_breakdown else "host_return"
321329
),
322330
},
331+
{"name": "environment_step_warmup_steps", "data": args_cli.warmup_steps},
323332
{"name": "presets", "data": ",".join(cfg.presets)},
324333
]
325334
},
@@ -360,7 +369,9 @@ def _generate_trainer(self, env, cfg, agent):
360369
bt = runner._trainer
361370

362371
environment_step_timer = stepping.EnvironmentStepTimingRecorder(
363-
env, measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown
372+
env,
373+
measure_synchronized_step_breakdown=args_cli.measure_synchronized_step_breakdown,
374+
warmup_steps=args_cli.warmup_steps,
364375
)
365376
with success_context, environment_step_timer, BenchmarkMonitor(benchmark, interval=1.0):
366377
runner.run()

scripts/benchmarks/test/test_benchmark_smoke.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ def test_adapters_reject_non_positive_workloads(library: str, workflow: str, arg
5858
assert exc_info.value.code == 2
5959

6060

61+
@pytest.mark.parametrize("library", ["rsl_rl", "rl_games", "skrl", "sb3"])
62+
@pytest.mark.parametrize("workflow", ["play", "train"])
63+
def test_adapters_reject_negative_warmup_steps(library: str, workflow: str):
64+
"""Benchmark adapters reject a negative --warmup_steps (the cold-start exclusion is opt-in, N >= 0)."""
65+
module = _load_adapter(library, workflow)
66+
67+
with pytest.raises(SystemExit) as exc_info:
68+
module._parse_args(["--task", _TASK, "--warmup_steps", "-1", "--headless"])
69+
70+
assert exc_info.value.code == 2
71+
72+
6173
@pytest.mark.parametrize(
6274
(
6375
"library",

source/isaaclab/changelog.d/antoiner-runtime-benchmark-warmup.minor.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Changed
44
* Changed the runtime benchmark to exclude configurable warmup frames and
55
report effective throughput over the complete measured interval, and
66
report environment-step host-return rates across runtime, play, and training
7-
benchmarks. Added an optional serialized synchronized breakdown of time
8-
inside and outside simulation calls; the outside-simulation remainder is not
9-
classified as overhead.
7+
benchmarks. Added an opt-in ``--warmup_steps`` flag to the play and training
8+
benchmarks that excludes the first N ``env.step()`` calls (cold start) from
9+
the environment-step timing; it defaults to ``0`` (no exclusion). Added an
10+
optional serialized synchronized breakdown of time inside and outside
11+
simulation calls; the outside-simulation remainder is not classified as
12+
overhead.

0 commit comments

Comments
 (0)