Performance Profiling¶
RLightning collects per-phase wall-clock timings for every training iteration and exposes GPU memory snapshots through a lightweight profiler module. This page explains how to enable detailed profiling, read the output, identify bottlenecks, and configure logging backends.
Built-in Timing¶
The engine instruments four phases automatically:
Phase name |
What it measures |
|---|---|
|
Total time from |
|
Inner rollout time only (excludes offload reload/save overhead). Only
recorded when |
|
Total time from |
|
Inner train time only. Only recorded when |
|
Total weight-sync time, including any offload operations. |
|
Inner sync time only. Only recorded when |
|
Time to sample from the buffer and transfer data to the train policy.
Only recorded when |
The timer_wrap decorator on _rollout, _train, and
_sync_weights always fires. The inner timer context managers are
gated on InternalFlag.DEBUG (i.e., the RLIGHTNING_DEBUG environment
variable).
Each timing entry accumulates count, total, and avg across calls
within the same engine instance. The engine’s print_timing_summary()
method logs the full table at DEBUG level and is called automatically at
the end of every epoch when RLIGHTNING_DEBUG=1.
Enabling Profiling¶
Two environment variables control profiling depth:
Variable |
Effect |
|---|---|
|
Enables inner-phase timers ( |
|
Enables the rich progress bar. Does not affect timing collection. |
Set these before launching:
RLIGHTNING_DEBUG=1 RLIGHTNING_VERBOSE=1 uv run train.py --config-name train_algo
In multi-process (Ray) runs, launch() automatically propagates these
variables to all Ray workers via runtime_env.env_vars.
Reading Profiler Output¶
With RLIGHTNING_DEBUG=1, the log contains two classes of entries.
Per-call timing (emitted at INFO level after each method call):
[rlightning] INFO - time_profile/_rollout: 1.2345s
[rlightning] INFO - time_profile/_train: 0.8901s
[rlightning] INFO - time_profile/_sync_weights: 0.1234s
Epoch summary (emitted at DEBUG level at the end of each epoch):
[rlightning] DEBUG - Timing summary:
[rlightning] DEBUG - SyncRLEngine:
[rlightning] DEBUG - _rollout count=1 total=1.234567s avg=1.234567s
[rlightning] DEBUG - _train count=1 total=0.890123s avg=0.890123s
[rlightning] DEBUG - _sync_weights count=1 total=0.123456s avg=0.123456s
The summary propagates down to env_group, policy_group, and
buffer — each prints its own timing breakdown.
GPU memory is logged via log_gpu_memory_usage(head, level):
[GPU Memory] before_train, memory allocated (GB): 12.34,
memory reserved (GB): 14.00, device memory used/total (GB): 15.00/24.00
Call log_gpu_memory_usage at any point in custom policy or env code to
snapshot memory at that phase.
Common Bottlenecks and Remedies¶
Rollout-Bound¶
Symptom: _rollout time dominates; _train finishes quickly and
waits for new data.
Remedies:
Increase
eval_worker_numto add more inference workers.Increase
env_worker_num(ornum_envsper env group) to collect more experience in parallel.Switch from
syncrltoasyncrlso training proceeds concurrently with rollout.Use
env_strategy: device-colocateto avoid idle GPU time between Env and Eval workers.
Training-Bound¶
Symptom: _train time dominates; rollout completes but the buffer
fills before training catches up.
Remedies:
Enable DDP multi-GPU training by increasing
train_worker_numandtrain_each_gpu_num.Use
enable_offload: truewithstrategy: colocateto reclaim GPU memory occupied by the eval model during training.Reduce
batch_sizeor limit gradient accumulation steps if the training loop itself is the bottleneck.
Data Transfer Bound¶
Symptom: update_dataset time is disproportionately large; GPU
utilization is low during training.
Remedies:
Use
strategy: disaggregateto place buffer shards on the same nodes as train workers, eliminating cross-node data movement.Set
buffer_worker_num: autoso GRM automatically aligns shards with train nodes.Enable node-affinity routing for buffer shards (automatic under resource- pool strategies).
Weight Sync Bound¶
Symptom: _sync_weights time is large relative to _train.
Remedies:
Co-locate train and eval workers (
strategy: colocate) to reduce weight-transfer distance.Use
enable_offload: trueonly when necessary — offload add reload/save overhead to each sync cycle.
Note
[Placeholder: representative timing numbers from benchmark runs showing the expected ratio of rollout:train:sync_weights for typical PPO configurations.]
Logging Backends¶
Experiment metrics (rewards, losses, and time_profile/* entries
when log_to_metric=True) are written to the configured backend.
Configuration is in the log section:
log:
level: INFO # console log level: DEBUG / INFO / WARNING / ERROR
backend: tensorboard # tensorboard | wandb | swanlab
project: my_project
name: run_001
log_dir: ./runs
mode: null # wandb only: online | offline | shared | disabled
TensorBoard¶
The default backend. Scalars are written with SummaryWriter to
<log_dir>/<project>/<name>/tensorboard/<timestamp>/. Launch the viewer:
tensorboard --logdir ./runs
Weights & Biases¶
Set backend: wandb. Default mode is offline to avoid network
dependency during training; sync manually with wandb sync:
log:
backend: wandb
project: rlightning_runs
name: ppo_maniskill
mode: offline
Warning
Do not instantiate TensorBoard loggers inside Ray actor class constructors.
TensorBoard’s internal threading.Lock cannot be serialized by Ray.
Use get_metrics_logger(__name__) and log_metric() instead.
SwanLab¶
Set backend: swanlab. Supports cloud and local modes:
log:
backend: swanlab
project: rlightning_runs
name: ppo_maniskill
mode: local
Debugging Tips¶
Single-process mode¶
Remove the cluster config block to run everything in a single process
without Ray. This enables standard Python debuggers (pdb, VSCode breakpoints):
uv run python train.py ~cluster
Single-process mode is limited to one GPU but eliminates Ray serialization and actor lifecycle overhead, making it the fastest way to debug data flow issues.
Multi-process debugging¶
For distributed debugging, use the Ray Distributed Debugger VSCode
extension (anyscalecompute.ray-distributed-debugger). It attaches to
individual Ray worker processes via remote attach, allowing step-through
debugging of actor code running in a live cluster.
Install the required VSCode extensions:
ms-python.debugpy(Python Debugger)anyscalecompute.ray-distributed-debugger
Set RAY_DEBUG=1 in the runtime_env.env_vars passed to ray.init
to enable the debugger server inside workers.
Tip
Start with a minimal configuration (1 train worker, 1 eval worker, 1 env, small model) to reproduce the issue before scaling up to the full cluster. This avoids long iteration cycles during diagnosis.