Skip to main content

Engine configuration

This page documents the per-engine YAML configuration surface. Each experiment selects exactly one engine via the top-level engine: field and configures it through a same-named block (transformers:, vllm:, tensorrt:).

Every experiment also declares a required top-level serving_mode: (offline or server) - see the serving_mode: field below. The per-engine configuration on this page applies in both serving modes.

Each engine block is a generated model at src/llenergymeasure/config/generated/<engine>.py, regenerated from the committed schema snapshot (its header reads DO NOT EDIT). The block has exactly two sub-sections, engine_params: and sampling_params:, and both sub-models set extra="allow", so a parameter the current snapshot does not model is still forwarded to the underlying engine. The tables below document the fields the generated models name explicitly at the pinned versions (transformers 5.7.0, vllm 0.19.1, tensorrt 1.2.1); for the exhaustive introspected inventory see the per-engine schema pages, and for which parameters are explicitly modelled vs forwarded see the curation pages (both linked under See also).

For study-level controls (sweeps, runners, images, cycles, output) see study-config.md.

Top-level shape

A single experiment YAML selects an engine and configures it through a same-named block. The engine block nests engine_params: and sampling_params: under it:

serving_mode: offline

task:
model: Qwen/Qwen2.5-0.5B
dataset:
source: aienergyscore
n_prompts: 100
order: interleaved
max_input_tokens: 256
max_output_tokens: 256
random_seed: 42

engine: transformers

measurement:
baseline:
enabled: true
duration_seconds: 30.0
energy_sampler: auto

offline:
warmup:
enabled: true
n_prompts: 5

transformers:
engine_params:
dtype: bfloat16
attn_implementation: sdpa
sampling_params:
temperature: 0.7
# transformers-only llem-owned execution knobs (see Execution knobs section)
llem_execution:
batch_size: 4

# Optional
sampling_preset: deterministic # deterministic | standard | creative | factual
passthrough_kwargs:
trust_remote_code: true

ExperimentConfig sets extra="forbid", so an unknown top-level key is a hard error, and so is a key placed directly on an engine block that is not engine_params or sampling_params (the validator emits a migration hint; validate_engine_section_extras in models.py). Parameters therefore live one level deeper than they did in the pre-0.10 flat layout: transformers.engine_params.dtype, not transformers.dtype.

The engine-specific section must match the engine: field; mixing engine: vllm with a transformers: section is a configuration error (validate_engine_section_match in models.py). When engine: is set without a matching section, the engine's own defaults are used.

There is no top-level dtype: field. dtype lives inside each engine's engine_params (transformers.engine_params.dtype, vllm.engine_params.dtype, tensorrt.engine_params.dtype) because each engine models it differently (see the per-engine tables).

runners:, images:, sweep:, and experiments: are study-level fields and not valid in a single-experiment YAML; they belong on the study document (StudyConfig in models.py). See study-config.md.

Common fields (all engines)

These fields are declared on ExperimentConfig and its sub-models and apply identically across engines. Every one is extra="forbid".

serving_mode:

FieldTypeDefaultDescriptionSource
serving_modeoffline | server(required)Serving mode discriminator, no default. offline measures batch inference over a fixed prompt set; server selects online serving measurement and requires a server: section with a traffic spec.ExperimentConfig

server mode's traffic: namespace (rate, arrival process, window, concurrency cap, SLOs) is not engine configuration and is not covered on this page; see study-config.md for the full field reference.

task:

FieldTypeDefaultDescriptionSource
modelstr (required, min length 1)-HuggingFace model ID or local pathTaskConfig
dataset.sourcestr (min length 1)aienergyscoreBuilt-in dataset alias or .jsonl pathDatasetConfig
dataset.n_promptsint >= 1100Number of prompts to load or generateDatasetConfig
dataset.orderinterleaved | grouped | shuffledinterleavedPrompt ordering strategyDatasetConfig
max_input_tokensint >= 1 | null256Input truncation cap; null disablesTaskConfig
max_output_tokensint >= 1 | null256Output token budget; null generates to EOS or context limitTaskConfig
random_seedint42Per-experiment seed for inference RNG and dataset orderingTaskConfig

measurement:

FieldTypeDefaultDescriptionSource
warmup.enabledbooltrueEnable warmup phase before measurementWarmupConfig
warmup.n_promptsint >= 15Number of warmup prompts in fixed modeWarmupConfig
warmup.thermal_floor_secondsfloat >= 30.060.0Minimum post-warmup wait for thermal stabilisationWarmupConfig
warmup.convergence_detectionboolfalseEnable adaptive CV-based convergence (replaces the fixed n_prompts count)WarmupConfig
warmup.cv_thresholdfloat [0.01, 0.5]0.05CV target for convergenceWarmupConfig
warmup.max_promptsint >= 520Safety cap for CV modeWarmupConfig
warmup.window_sizeint >= 33Sliding window size for CV calculationWarmupConfig
warmup.min_promptsint >= 15Minimum prompts before checking convergenceWarmupConfig
baseline.enabledbooltrueMeasure idle GPU power before experimentsBaselineConfig
baseline.duration_secondsfloat [5.0, 120.0]30.0Baseline measurement windowBaselineConfig
baseline.strategycached | validated | freshvalidatedCaching strategy for the baseline measurementBaselineConfig
baseline.cache_ttl_secondsfloat >= 60.07200.0Cached baseline lifetime (cached/validated only)BaselineConfig
baseline.validation_intervalint >= 15Re-validate every N experiments (validated only)BaselineConfig
baseline.drift_thresholdfloat [0.01, 0.50]0.10Drift fraction that triggers re-measurement (validated only)BaselineConfig
energy_samplerauto | nvml | zeus | codecarbon | nullautoEnergy sampler; null disables energy measurementMeasurementConfig
latency_profilingboolfalseOpt-in per-token latency profiling (TTFT/ITL). Overhead may perturb energy and latency, so profiled runs are tagged in measurement_warnings.MeasurementConfig
measurement_methodologytotal | windowed | steady_statetotalHow the measurement window is derived from the runMeasurementConfig
measurement_window[float, float] | nullnullRequired when measurement_methodology=windowed (start >= 0, end > start)MeasurementConfig
warmup_discard_fractionfloat [0.0, 1.0)0.1Fraction of the run discarded as warmup when deriving steady stateMeasurementConfig
warmup_discard_secondsfloat >= 0.0 | nullnullAbsolute warmup discard window (overrides the fraction)MeasurementConfig
steady_state_auto_detectboolfalseAuto-detect the steady-state windowMeasurementConfig

Top-level optional fields

FieldTypeDefaultDescriptionSource
sampling_presetdeterministic | standard | creative | factual | nullnullMerges preset values into the active engine's sampling_params: section at parse time. Explicit YAML values take precedence.ExperimentConfig (expand_sampling_preset, SAMPLING_PRESETS)
passthrough_kwargsdict | nullnullExtra kwargs forwarded to the engine at execution time; keys must not collide with ExperimentConfig top-level field namesExperimentConfig (validate_passthrough_kwargs_no_collision)

Execution knobs (transformers.llem_execution:) - transformers-only

Some knobs are features llem implements itself in its own runner loop, because the engine exposes no native API for them. They are not engine config, so they are hand-written (at config/llem_execution.py) rather than mined into the generated engine block. They are exposed as a per-engine llem_execution: sub-section, sibling of engine_params: / sampling_params: inside the engine section. Only transformers has an execution residual today; vllm and tensorrt drive batching and precision through native engine APIs, so their sections carry no llem_execution block.

There is no top-level harness: key. A config that still carries one is rejected with an error naming the new location (<engine>.llem_execution).

transformers:
llem_execution:
batch_size: 4
torch_compile: true
torch_compile_mode: reduce-overhead
FieldTypeDefaultDescriptionSource
batch_sizeint >= 1null (-> 1)Prompt-batching size for llem's runner loop (model.generate() has no batch_size kwarg)TransformersLlemExecution
torch_compileboolnull (-> false)Enable torch.compile on the loaded modelTransformersLlemExecution
torch_compile_modestrnull (-> default)default | reduce-overhead | max-autotune. Requires torch_compile=true.TransformersLlemExecution
torch_compile_backendstrnull (-> inductor)torch.compile backend. Requires torch_compile=true.TransformersLlemExecution
allow_tf32boolnullAllow TF32 matmul on Ampere+ via torch.backendsTransformersLlemExecution
autocast_enabledboolnull (-> false)Wrap generation in torch.autocastTransformersLlemExecution
autocast_dtypefloat16 | bfloat16null (-> bfloat16 on Ampere)AMP dtype (used when autocast_enabled=true)TransformersLlemExecution

Naming torch_compile_mode or torch_compile_backend without torch_compile=true is rejected (validate_torch_compile_options in llem_execution.py).

Transformers engine (transformers:)

Loads a model via AutoModelForCausalLM.from_pretrained() and generates with model.generate(). Every generated field is X | None = None: null means "use the engine's own default". Unknown fields under engine_params: or sampling_params: are forwarded to the underlying HuggingFace APIs (extra="allow").

transformers.engine_params:

FieldTypeDefaultDescription
dtypeany | nullnullModel compute dtype (e.g. float32, float16, bfloat16); untyped, forwarded as given
attn_implementationany | nullnullAttention kernel (e.g. sdpa, flash_attention_2, flash_attention_3, eager)
load_in_4bitany | nullnullBitsAndBytes 4-bit quantisation
load_in_8bitany | nullnullBitsAndBytes 8-bit quantisation
bnb_4bit_compute_dtypeany | nullnullCompute dtype for 4-bit
bnb_4bit_quant_typeany | nullnull4-bit quantisation type (e.g. nf4, fp4)
bnb_4bit_use_double_quantany | nullnullDouble quantisation
use_cachebool | nullnullEnable KV cache during generation
cache_implementationstr | nullnullKV cache strategy (e.g. static, offloaded_static, sliding_window)
num_beamsint | nullnullBeam search width (1 = greedy/sampling)
early_stoppingbool | nullnullStop beam search when all beams hit EOS
length_penaltyfloat | nullnullBeam length penalty
no_repeat_ngram_sizeint | nullnullPrevent n-gram repetition
prompt_lookup_num_tokensint | nullnullPrompt-lookup speculative decoding tokens
device_mapany | nullnullDevice placement strategy (e.g. auto)
max_memoryany | nullnullPer-device memory limits, e.g. {0: "10GiB", cpu: "50GiB"}
low_cpu_mem_usageany | nullnullLoad weights incrementally to reduce peak CPU RAM
tp_planany | nullnullNative HF tensor parallelism plan
tp_sizeany | nullnullTensor parallel ranks (used with tp_plan)

Source: src/llenergymeasure/config/generated/transformers.py.

transformers.sampling_params:

Maps to model.generate() kwargs; field names mirror HuggingFace conventions. All fields default to null (use the HF default). Untyped or freeform kwargs are forwarded via extra="allow".

FieldTypeDefaultDescription
temperaturefloat | nullnullSampling temperature (0 = greedy)
do_samplebool | nullnullEnable sampling
top_kint | nullnullHF convention: 0 = disabled
top_pfloat | nullnullNucleus sampling threshold
repetition_penaltyfloat | nullnullRepetition penalty (1.0 = no penalty)
min_pfloat | nullnullMinimum probability filter
min_new_tokensint | nullnullMinimum output tokens

Source: src/llenergymeasure/config/generated/transformers.py.

vLLM engine (vllm:)

vLLM exposes a two-API surface (vllm.LLM() constructor and SamplingParams); the block mirrors that split across engine_params: and sampling_params:. Unlike the flat pre-0.10 layout there is no separate top-level vllm.dtype or vllm.beam_search block: dtype is a field under engine_params, and beam_search / attention are freeform (Any-typed) dict fields under engine_params.

vllm.engine_params:

Constructor arguments for vllm.LLM(). Unlike transformers, several fields carry defaults and bounds from the generated model.

FieldTypeDefaultDescription
dtypeauto | half | float16 | bfloat16 | float | float32 | nullautoModel dtype; auto infers from weights
gpu_memory_utilizationfloat (0.0, 1.0]0.9GPU memory fraction reserved for KV cache
cpu_offload_gbfloat >= 0.00CPU RAM in GiB to offload model weights to
block_sizeint | nullnullKV cache block size in tokens
kv_cache_dtypeauto | float16 | bfloat16 | fp8 | fp8_e4m3 | fp8_e5m2 | fp8_inc | fp8_ds_mla | nullautoKV cache storage dtype
enforce_eagerbool | nullfalseDisable CUDA graphs, always use eager mode
enable_chunked_prefillbool | nullnullChunk large prefills across scheduler iterations
max_num_seqsint >= 1 | nullnullMax concurrent sequences per scheduler iteration
max_num_batched_tokensint >= 1 | nullnullMax tokens per scheduler iteration
max_model_lenint >= 1 | nullnullMax sequence length (input + output)
tensor_parallel_sizeint | null1Number of GPUs to shard the model across
pipeline_parallel_sizeint | null1Pipeline parallel stages
distributed_executor_backendany | nullnullMulti-GPU executor backend (e.g. mp, ray)
enable_prefix_cachingbool | nullnullAutomatic prefix caching for shared prompt prefixes
quantizationany | nullnullQuantisation method (requires a pre-quantised checkpoint)
speculative_configsub-model | nullnullSpeculative decoding config (see the schema page)
offload_group_sizeint >= 0 | null0Groups of layers for CPU offloading
offload_num_in_groupint >= 1 | null1Layers offloaded per group
offload_prefetch_stepint >= 0 | null1Prefetch steps ahead for CPU offload
offload_paramsany | null[]Specific parameter names to offload
disable_custom_all_reducebool | nullfalseDisable custom all-reduce for multi-GPU
kv_cache_memory_bytesint | nullnullAbsolute KV cache size
compilation_configsub-model | nullnullvLLM CompilationConfig passthrough (see the schema page)
attentionany (dict) | nullnullAttention backend selection; freeform dict (e.g. {backend: flash_attn})
beam_searchany (dict) | nullnullBeam-search parameters; freeform dict (e.g. {beam_width: 4, early_stopping: true})

Source: src/llenergymeasure/config/generated/vllm.py. speculative_config and compilation_config are typed sub-models with many fields; see schema-vllm.md for the full inventory.

vllm.sampling_params:

Maps to vllm.SamplingParams(). max_tokens is intentionally absent; it is bridged from task.max_output_tokens at execution time. top_k follows vLLM's 0-for-default convention.

FieldTypeDefaultDescription
temperaturefloat | null1.0Sampling temperature (0 = greedy)
top_kint | null0Top-k cutoff
top_pfloat | null1.0Nucleus sampling threshold
repetition_penaltyfloat | null1.0Repetition penalty
min_pfloat | null0.0Minimum probability filter
min_tokensint | null0Minimum output tokens before EOS allowed
presence_penaltyfloat | null0.0Penalises tokens that appear at all
frequency_penaltyfloat | null0.0Penalises tokens proportional to frequency
ignore_eosbool | nullfalseContinue generating past EOS
nint | null1Number of output sequences per prompt

Source: src/llenergymeasure/config/generated/vllm.py.

TensorRT-LLM engine (tensorrt:)

TensorRT-LLM exposes two runtimes behind one engine, selected by backend: pytorch (the default) runs the model through TensorRT-LLM's PyTorch runtime with no ahead-of-time build, and trt compiles the model into an optimised TensorRT engine on first use and reuses the cached engine afterwards. backend is resolved by constructor class (pytorch -> tensorrt_llm.LLM, trt -> tensorrt_llm._tensorrt_engine.LLM), never forwarded as a kwarg. A handful of fields (quant_config, fast_build) exist only on the trt backend; declaring them under pytorch is a config-load error. On the trt backend, compile-time fields are baked into the engine and changing one triggers a fresh build. The nested TRT-LLM sub-configs (quant_config, kv_cache_config, scheduler_config) are freeform (Any-typed) dict fields under engine_params: on the current pin, so they are written as whole dicts (see the worked example).

tensorrt.engine_params:

FieldTypeDefaultDescription
max_batch_sizeint | nullnullMaximum batch size the engine accepts (compile-time)
tensor_parallel_sizeint | null1Number of GPUs to shard across (compile-time)
pipeline_parallel_sizeint | null1Pipeline parallel stages (compile-time)
max_input_lenint | nullnullMaximum input sequence length (compile-time)
max_seq_lenint | nullnullMaximum total sequence length (compile-time)
max_num_tokensint | nullnullMaximum tokens the engine handles per iteration (compile-time)
dtypestr | nullautoModel compute dtype; untyped, forwarded as given
backendpytorch | trt | nullpytorchRuntime selector, resolved by constructor class (see intro); distinct from the top-level engine: selector. Any other value is a config-load error
fast_buildbool | nullfalseReduced-optimisation build for faster compilation. trt backend only - rejected under pytorch
quant_configany (dict) | nullnullQuantisation config; freeform dict (e.g. {quant_algo: W4A16_AWQ}). trt backend only - rejected under pytorch
kv_cache_configany (dict) | nullnullKV cache config; freeform dict (e.g. {enable_block_reuse: true, free_gpu_memory_fraction: 0.9})
scheduler_configany (dict) | nullnullScheduler config; freeform dict (e.g. {capacity_scheduling_policy: MAX_UTILIZATION})

Source: src/llenergymeasure/config/generated/tensorrt.py.

tensorrt.sampling_params:

Maps to tensorrt_llm.SamplingParams. top_k uses TRT-LLM's convention (matches HuggingFace, not vLLM).

FieldTypeDefaultDescription
temperaturefloat | nullnullSampling temperature (0 = greedy)
top_kint | nullnullTop-k cutoff
top_pfloat | nullnullNucleus sampling threshold
repetition_penaltyfloat | nullnullRepetition penalty
min_pfloat | nullnullMinimum probability filter
min_tokensint | nullnullMinimum output tokens before EOS allowed
nint | null1Number of output sequences per prompt
ignore_eosbool | nullfalseContinue generating past EOS

Source: src/llenergymeasure/config/generated/tensorrt.py.

Validation rules

The Pydantic models enforce structural rules at config-load time, and the engine's shipped rule corpus (rules.yaml) enforces the mined constraints. The full catalogue of invalid combinations - derived from the live corpus plus the cross-engine validators - is in invalid-combos.md.

Cross-engine (structural, in models.py)

  • The engine-specific section must match engine: (validate_engine_section_match).
  • A key placed directly on an engine block (not under engine_params or sampling_params) is rejected with a migration hint (validate_engine_section_extras).
  • passthrough_kwargs keys must not collide with ExperimentConfig top-level field names (validate_passthrough_kwargs_no_collision).

Transformers

  • With attn_implementation flash_attention_2 or flash_attention_3, dtype must not be float32 (validate_transformers_flash_attn_dtype in models.py; a missing dtype is treated as bfloat16).
  • All further transformers constraints (beam-search divisibility, quantisation, caching) come from the shipped rule corpus; see invalid-combos.md.

vLLM and TensorRT-LLM

  • The vLLM/TensorRT constraints (mutually exclusive sections, cross-field bounds, dormant normalisations) come from each engine's shipped rule corpus. Note that the old hand-written dtype: float32 rejection was dropped with the generated configs: vLLM's dtype now includes float32 in its Literal, and the informational per-engine dtypes (on the ssot.ENGINES descriptor) drive pre-flight checks, not Pydantic parsing.

Engine x dtype support (pre-flight)

From the per-engine dtypes on the ssot.ENGINES descriptor - an informational pre-flight map, not a parse-time constraint:

Enginefloat32float16bfloat16
transformersyesyesyes
vllmnoyesyes
tensorrtnoyesyes

Worked examples

Minimal Transformers experiment

serving_mode: offline
task:
model: gpt2
engine: transformers

All other fields fall back to defaults: aienergyscore dataset, 100 prompts, 256-token input/output caps, auto energy sampler, and the engine's own dtype/attention defaults.

Transformers with quantisation and compilation

serving_mode: offline
task:
model: meta-llama/Llama-2-7b-hf
dataset:
n_prompts: 50

engine: transformers

transformers:
engine_params:
dtype: bfloat16
load_in_4bit: true
bnb_4bit_compute_dtype: bfloat16
bnb_4bit_quant_type: nf4
bnb_4bit_use_double_quant: true
attn_implementation: flash_attention_2
llem_execution:
batch_size: 4
torch_compile: false

vLLM with prefix caching and FP8 KV cache

serving_mode: offline
task:
model: meta-llama/Llama-2-7b-hf
max_input_tokens: 1024
max_output_tokens: 256

engine: vllm

vllm:
engine_params:
dtype: bfloat16
gpu_memory_utilization: 0.9
enable_prefix_caching: true
kv_cache_dtype: fp8
block_size: 16
sampling_params:
temperature: 0.0
n: 1

beam_search is a freeform dict under engine_params; it is written as a whole dict.

serving_mode: offline
task:
model: gpt2

engine: vllm

vllm:
engine_params:
enforce_eager: false
beam_search:
beam_width: 4
length_penalty: 1.0
early_stopping: true
sampling_params:
temperature: 0.0

TensorRT-LLM with AWQ quantisation

The TRT-LLM sub-configs are freeform dicts on the current pin, written whole.

serving_mode: offline
task:
model: meta-llama/Llama-2-7b-hf

engine: tensorrt

tensorrt:
engine_params:
backend: trt # quant_config requires the compiled trt backend
dtype: bfloat16
max_batch_size: 8
max_input_len: 1024
max_seq_len: 2048
tensor_parallel_size: 1
quant_config:
quant_algo: W4A16_AWQ
kv_cache_config:
free_gpu_memory_fraction: 0.9
enable_block_reuse: true
scheduler_config:
capacity_scheduling_policy: GUARANTEED_NO_EVICT

Sampling preset (preset values merged into the engine's sampling section)

serving_mode: offline
task:
model: gpt2
engine: transformers
sampling_preset: deterministic # sets temperature: 0.0 under transformers.sampling_params

sampling_preset is expanded at parse time into the active engine's sampling_params: sub-section via setdefault, so explicit YAML values take precedence over preset values (expand_sampling_preset in models.py).

See also