Skip to content

Commit 8b04cbf

Browse files
committed
update README and reject GPU hardware detection feature
Signed-off-by: louie-tsai <louie.tsai@intel.com>
1 parent cfdb7a8 commit 8b04cbf

3 files changed

Lines changed: 192 additions & 16 deletions

File tree

tools/recipes/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
Utilities for consuming deployment configurations from [vLLM Recipes](https://recipes.vllm.ai/) and converting them into files that can be used directly with vLLM.
44

5+
6+
## Optimized Deployment Flow
7+
8+
The recipe provides the validated deployment baseline. Hardware and workload
9+
information are optional inputs that can refine deployment-sensitive values
10+
before the generated configuration is passed to vLLM.
11+
12+
```mermaid
13+
flowchart LR
14+
R["vLLM Recipe"] --> C["Recipe Converter"]
15+
H["Hardware Info (optional)"] --> C
16+
W["Workload Info (optional)"] --> C
17+
C --> F["config.yml + env.sh"]
18+
F --> D["vLLM Docker Image"]
19+
D --> E["OpenAI Endpoint"]
20+
```
21+
22+
523
## `recipe_json_to_vllm_config.py`
624

725
Converts a hardware-specific vLLM Recipes JSON rendering into:
@@ -154,3 +172,108 @@ Strategy discovery and config conversion are separate concerns.
154172
The converter can resolve any generated strategy JSON exposed by the Recipes API. It currently emits one `config.yml`, so the selected rendering must contain a single `vllm serve` `argv`.
155173

156174
Single-process renderings such as `single_node_tp` can be converted directly. Multi-node, disaggregated prefill/decode, or other multi-process renderings expose fields such as `head_argv`, `worker_argv`, `prefill`, or `decode`; the converter intentionally exits instead of generating an incomplete single-process config.
175+
176+
## Optional Runtime Tuning
177+
178+
The Recipes JSON remains the baseline. vLLM Recipes already provide validated
179+
model, hardware, strategy, environment variables, and serving arguments.
180+
Runtime tuning is optional and is intended for parameters whose best value can
181+
depend on the actual deployment resources or expected request workload.
182+
183+
### Deployment-Time Parameters
184+
185+
The parameters below may already exist in a recipe. They are candidates for
186+
deployment-time refinement when the recipe value is missing, generic, or based
187+
on a validation environment that differs from the user's target deployment.
188+
189+
| Runtime parameter | Why it may need deployment-time refinement | Main decision input | Current draft policy |
190+
| --- | --- | --- | --- |
191+
| `tensor-parallel-size` | The effective CPU/NUMA topology available to a container or pod can differ from the system used to validate the recipe. | Hardware topology | Use the largest power-of-two TP value that does not exceed the effective NUMA-node count. |
192+
| `gpu-memory-utilization` | Available memory can differ by machine size, container limits, and other memory use. The vLLM option name is also used by the CPU backend. | Hardware memory + recipe baseline | Compute a conservative safe fraction, reserve 10%, cap at `0.90`, and never increase a smaller recipe value. If the recipe omits it, start from `0.80`. |
193+
| `max-num-seqs` | The useful scheduler concurrency depends on the number of requests expected to be active at the same time. | Workload concurrency | Set `max-num-seqs` to `--concurrency`. |
194+
| `max-num-batched-tokens` | The batching budget depends strongly on request input length and concurrency. | Workload token shape + concurrency | Compute `input_tokens * min(concurrency, 8)`, round up to a power of two, and clamp to `2048..32768`. |
195+
| `data-parallel-size` | The required replica count depends on the requested throughput and the capacity of one replica. | Capacity target | Keep the recipe value today. `--target-qps` is captured for a future capacity-based policy. |
196+
197+
These policies are intentionally isolated in `runtime_tuning.py` so the
198+
decision rules can evolve as more benchmark data becomes available.
199+
200+
### How Runtime Tuning Determines the Values
201+
202+
The converter can combine the recipe baseline with optional deployment
203+
information. Different information sources are used for different parameters:
204+
205+
| Information source | How it is obtained | Examples | Parameters it can help determine |
206+
| --- | --- | --- | --- |
207+
| vLLM Recipe | Recipes JSON API or direct recipe JSON | model ID, recipe hardware, strategy, existing `argv`, environment variables | Provides the baseline for all parameters and selects the applicable hardware tuning policy. |
208+
| Hardware (optional) | `--detect-hardware` | effective NUMA nodes, allowed CPUs, physical cores, per-NUMA total/available memory | `tensor-parallel-size`, `gpu-memory-utilization` |
209+
| Workload (optional) | User CLI inputs | `--input-tokens`, `--output-tokens`, `--concurrency` | `max-num-seqs`, `max-num-batched-tokens`; output length is also available for future KV-cache-aware policies. |
210+
| SLO / capacity (optional) | User CLI inputs | `--ttft-sla-ms`, `--tpot-sla-ms`, `--target-qps` | Future SLA-aware batching and `data-parallel-size` capacity decisions. |
211+
212+
All additional inputs are optional. If none are supplied, the converter keeps
213+
the normal Recipes conversion behavior.
214+
215+
The effective precedence is:
216+
217+
```text
218+
vLLM defaults
219+
-> vLLM Recipes baseline
220+
-> hardware refinement (optional)
221+
-> workload / SLO refinement (optional)
222+
-> config.yml + env.sh
223+
```
224+
225+
For example, hardware detection can refine TP and memory sizing without any
226+
workload input:
227+
228+
```bash
229+
python3 tools/recipes/recipe_json_to_vllm_config.py \
230+
--model meta-llama/Llama-3.1-8B-Instruct \
231+
--hardware xeon6 \
232+
--detect-hardware
233+
```
234+
235+
Workload information can be added when it is known:
236+
237+
```bash
238+
python3 tools/recipes/recipe_json_to_vllm_config.py \
239+
--model meta-llama/Llama-3.1-8B-Instruct \
240+
--hardware xeon6 \
241+
--detect-hardware \
242+
--input-tokens 2048 \
243+
--output-tokens 128 \
244+
--concurrency 32 \
245+
--ttft-sla-ms 3000 \
246+
--tpot-sla-ms 100
247+
```
248+
249+
`--output-tokens`, `--ttft-sla-ms`, and `--tpot-sla-ms` are accepted as policy
250+
inputs, but the current draft does not force them into an arbitrary formula.
251+
Output length affects KV-cache residency and request lifetime, while TTFT and
252+
TPOT constrain how aggressive scheduler batching can be. These inputs can be
253+
used once benchmark-derived or otherwise validated decision rules are available.
254+
255+
### Runtime-Tuning Hardware Scope
256+
257+
Runtime tuning is selected from the resolved recipe JSON's `hardware` field,
258+
rather than by inspecting which physical devices happen to be present on the
259+
host. This matters because a GPU server also exposes its host CPU topology.
260+
261+
The current runtime-tuning policy registry contains `xeon6`. A tuning request
262+
for unregistered recipe hardware, such as `b200`, fails before host hardware
263+
detection:
264+
265+
```text
266+
ERROR: Runtime tuning is not supported for recipe hardware 'b200'.
267+
Currently supported: xeon6.
268+
```
269+
270+
Plain recipe conversion remains available for all recipe hardware. The gate only
271+
applies when optional runtime-tuning inputs are requested.
272+
273+
The implementation remains modular:
274+
275+
- `hardware_detection.py` collects effective CPU/NUMA/memory information.
276+
- `runtime_tuning.py` owns hardware-policy selection and independent parameter
277+
tuning functions.
278+
- `recipe_json_to_vllm_config.py` resolves the recipe, collects optional inputs,
279+
applies the selected policy, and generates `config.yml` and `env.sh`.

tools/recipes/recipe_json_to_vllm_config.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@
5858
raise SystemExit("PyYAML is required. Install it with: pip install pyyaml") from exc
5959

6060
from hardware_detection import detect_hardware
61-
from runtime_tuning import WorkloadHints, finetune_runtime_config
61+
from runtime_tuning import (
62+
WorkloadHints,
63+
finetune_runtime_config,
64+
get_runtime_tuning_policies,
65+
)
6266

6367

6468
DEFAULT_API_BASE = "https://recipes.vllm.ai"
@@ -123,14 +127,18 @@ def parse_args() -> argparse.Namespace:
123127

124128
tuning = p.add_argument_group(
125129
"optional runtime tuning",
126-
"Refine the recipe baseline only when additional information is supplied.",
130+
(
131+
"Refine the recipe baseline only when additional information is supplied. "
132+
"Runtime tuning is enabled only for recipe hardware with a registered "
133+
"policy (currently: xeon6)."
134+
),
127135
)
128136
tuning.add_argument(
129137
"--detect-hardware",
130138
action="store_true",
131139
help=(
132-
"Detect effective CPU/NUMA/memory resources and allow hardware "
133-
"policies to override recipe runtime arguments."
140+
"Detect effective CPU/NUMA/memory resources and allow the selected "
141+
"recipe-hardware policy to override recipe runtime arguments."
134142
),
135143
)
136144
tuning.add_argument(
@@ -689,7 +697,6 @@ def main() -> int:
689697
argv = recipe_argv(recipe)
690698
config = argv_to_config(argv)
691699

692-
hardware = detect_hardware() if args.detect_hardware else None
693700
workload = WorkloadHints(
694701
input_tokens=args.input_tokens,
695702
output_tokens=args.output_tokens,
@@ -698,22 +705,41 @@ def main() -> int:
698705
tpot_sla_ms=args.tpot_sla_ms,
699706
target_qps=args.target_qps,
700707
)
701-
tuning = finetune_runtime_config(
702-
config,
703-
hardware=hardware,
704-
workload=workload,
708+
tuning_requested = args.detect_hardware or any(
709+
value is not None
710+
for value in (
711+
workload.input_tokens,
712+
workload.output_tokens,
713+
workload.concurrency,
714+
workload.ttft_sla_ms,
715+
workload.tpot_sla_ms,
716+
workload.target_qps,
717+
)
705718
)
706-
config.update(tuning.overrides)
719+
720+
tuning = None
721+
if tuning_requested:
722+
recipe_hardware = recipe.get("hardware")
723+
policies = get_runtime_tuning_policies(recipe_hardware)
724+
hardware = detect_hardware() if args.detect_hardware else None
725+
tuning = finetune_runtime_config(
726+
config,
727+
hardware=hardware,
728+
workload=workload,
729+
policies=policies,
730+
)
731+
config.update(tuning.overrides)
707732

708733
write_config(args.config_out, source, recipe, config)
709734
write_env(args.env_out, source, recipe)
710735

711-
if tuning.overrides:
712-
print("Applied runtime tuning overrides:")
713-
for key, value in tuning.overrides.items():
714-
print(f" {key}: {value}")
715-
for note in tuning.notes:
716-
print(f" tuning: {note}")
736+
if tuning is not None:
737+
if tuning.overrides:
738+
print("Applied runtime tuning overrides:")
739+
for key, value in tuning.overrides.items():
740+
print(f" {key}: {value}")
741+
for note in tuning.notes:
742+
print(f" tuning: {note}")
717743
except Exception as exc:
718744
print(f"ERROR: {exc}", file=sys.stderr)
719745
return 1

tools/recipes/runtime_tuning.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,33 @@ def _resolve_data_parallel_size(
205205
_resolve_data_parallel_size,
206206
)
207207

208+
# Select tuning behavior from the hardware requested by the Recipes rendering,
209+
# not from devices physically present in the host. A GPU server still exposes
210+
# its host CPU topology, so host inspection alone cannot determine deployment
211+
# intent.
212+
HARDWARE_TUNING_POLICIES: dict[str, tuple[Policy, ...]] = {
213+
"xeon6": DEFAULT_POLICIES,
214+
}
215+
216+
217+
def get_runtime_tuning_policies(
218+
recipe_hardware: object,
219+
) -> tuple[Policy, ...]:
220+
if not isinstance(recipe_hardware, str) or not recipe_hardware:
221+
raise ValueError(
222+
"Runtime tuning requires the resolved Recipes JSON to declare "
223+
"a non-empty `hardware` field."
224+
)
225+
226+
policies = HARDWARE_TUNING_POLICIES.get(recipe_hardware)
227+
if policies is None:
228+
supported = ", ".join(sorted(HARDWARE_TUNING_POLICIES))
229+
raise ValueError(
230+
"Runtime tuning is not supported for recipe hardware "
231+
f"{recipe_hardware!r}. Currently supported: {supported}."
232+
)
233+
return policies
234+
208235

209236
def finetune_runtime_config(
210237
config: dict[str, Any],

0 commit comments

Comments
 (0)