Skip to content

Commit 56491f6

Browse files
committed
Add timeslice-verl package and fully-async two-RL-jobs guide
Adds the timeslice-verl integration package and a guide that time-slices two verl fully_async_policy RL jobs' trainers on one shared 1-GPU node (each job keeps a dedicated 1-GPU rollout node; 2-pod Ray cluster per job). The package ships TimesliceFullyAsyncTrainer, a subclass of verl's FullyAsyncTrainer that overrides the trainer's empty on_* lifecycle hooks (same template-method convention as verl's v1 trainers). It registers under the trainer name "timeslice" via verl's fully-async trainer registry — the package's verl.plugins entry point makes `import verl` load the registering module — and is selected with the hydra override async_training.trainer_name=timeslice. No meta_path monkey-patching. Placement-group pinning uses verl's per-pool extra bundle resources (ray_pg_extra_resources hydra override) instead of patching placement_group; the trainer refuses to train unpinned when TIMESLICE_REQUIRE_PG_PINNING=1. Both verl features ship as format-patch files in the guide's patches/ dir until they are available upstream (default install path: the feat/fully-async-lifecycle-hooks fork branch). New: pkg/integrations/verl/ (TimesliceFullyAsyncTrainer = TimesliceHooksMixin over FullyAsyncTrainer, + PhaseLocks; 33 tests, pure-python: no verl/ray/ grpc/GPU needed) New: guides/rl-frameworks/verl/ (README, job manifests for a math-RLVR and a code-RLVR job, GPU monitor, platform values, verl feature patches)
1 parent d1b37de commit 56491f6

12 files changed

Lines changed: 3473 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Time-Slicing Integration Guide for verl Workloads
2+
3+
This guide covers integrating **verl** (Volcano Engine Reinforcement Learning framework) with the **llm-d-rl-time-slicing** platform using the pre-packaged `timeslice-verl` integration (`pkg/integrations/verl/`).
4+
5+
### Motivation: Maximizing GPU Utilization
6+
7+
In verl's **fully-async** recipe (`fully_async_policy`), rollout generation runs continuously while the trainer sits idle whenever it waits for the next batch of samples — in our reference runs that idle fraction was ~55–70% of wall-clock. Cooperative time-slicing backfills those valleys: multiple jobs' trainers share one physical GPU pool, and the platform checkpoints the idle trainer's GPU state to host RAM (`cuda-checkpoint`) at every handoff. Rollout engines keep dedicated GPUs and never stop generating.
8+
9+
### How It Works
10+
11+
The `timeslice-verl` package ships `TimesliceFullyAsyncTrainer`, a subclass of verl's `fully_async_policy` trainer that overrides the trainer's empty `on_*` lifecycle hooks to acquire/release the orchestrator lock at the trainer's natural wait points. It registers under the trainer name `timeslice` (verl's trainer registry; the package's `verl.plugins` entry point makes `import verl` load the registering module) and is selected with a single hydra override: `async_training.trainer_name=timeslice`. No monkey-patching and no verl source edits in your job — it requires a verl build with the fully-async lifecycle hooks + trainer registry and per-pool placement-group bundle resources (currently the `feat/fully-async-lifecycle-hooks` fork branch, until the commits land upstream).
12+
13+
### Supported Modes
14+
15+
| verl mode | Status | Notes |
16+
|---|---|---|
17+
| **Fully-async** (`fully_async_policy`) | **Supported** | Via the `TimesliceFullyAsyncTrainer` subclass + fork lifecycle hooks. See the runnable example below. |
18+
| v1 sync modes (e.g. `main_ppo` PPO/GRPO) | Not shipped in this PR | The v1 trainers expose the same `on_*` hook convention; integration is future work. |
19+
20+
For a runnable example, see:
21+
22+
* **[Fully-Async Example](examples/fully-async/README.md)** — two fully-async RL jobs (math RLVR + code RLVR) sharing one trainer GPU, each with a dedicated rollout GPU

guides/rl-frameworks/verl/examples/fully-async/README.md

Lines changed: 378 additions & 0 deletions
Large diffs are not rendered by default.

guides/rl-frameworks/verl/examples/fully-async/job-a-math.yaml

Lines changed: 799 additions & 0 deletions
Large diffs are not rendered by default.

guides/rl-frameworks/verl/examples/fully-async/job-b-code.yaml

Lines changed: 961 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Helm override values for the llm-d-rl-time-slicing umbrella chart (deploy/).
2+
# Applied on top of deploy/values-gke.yaml:
3+
# helm install timeslice ./deploy -n timeslice-system --create-namespace \
4+
# -f ./deploy/values-gke.yaml -f values-timeslice.yaml
5+
#
6+
# NOTE ON IMAGES: this guide needs platform images that include the IDLE
7+
# cold-start deadlock fix (jobs that deploy their pods before their first
8+
# Acquire register as IDLE; older orchestrators deadlock on that state).
9+
# Use the official images from a release that contains it, or override the
10+
# tags below with your own build.
11+
#
12+
# TODO: pin the tags below to the first tagged release that includes the
13+
# cold-start Acquire fix (#152); "latest" is used until then.
14+
15+
timesliceorchestrator:
16+
image:
17+
repository: ghcr.io/llm-d-incubation/llm-d-rl-time-slicing/timesliceorchestrator
18+
tag: latest
19+
pullPolicy: Always
20+
21+
snapshot-agent:
22+
image:
23+
repository: ghcr.io/llm-d-incubation/llm-d-rl-time-slicing/snapshot-agent
24+
tag: latest
25+
pullPolicy: Always
26+
27+
# NOTE: no per-GPU device filter is needed in the 1-GPU-per-node topology —
28+
# each node has a single GPU and only the (labeled) head pods on the trainer
29+
# node are ever snapshot targets. This file is images-only.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[build-system]
2+
requires = ["setuptools>=64"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "timeslice-verl"
7+
version = "0.1.0"
8+
description = "GPU time-slicing integration for verl fully-async RL training"
9+
requires-python = ">=3.10"
10+
dependencies = []
11+
12+
# `import verl` auto-loads every module in the verl.plugins entry-point group;
13+
# importing timeslice_verl.trainer registers TimesliceFullyAsyncTrainer under
14+
# the trainer name "timeslice" (select it with the hydra override
15+
# async_training.trainer_name=timeslice; requires verl with fully-async
16+
# lifecycle hooks + trainer registry). The hooks are env-gated: inert unless
17+
# TIMESLICE_FULLY_ASYNC=1, so the same image works with and without the
18+
# time-slicing platform.
19+
[project.entry-points."verl.plugins"]
20+
timeslice = "timeslice_verl.trainer"
21+
22+
[tool.setuptools]
23+
packages = ["timeslice_verl"]

pkg/integrations/verl/tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)