Levers for spending fewer watts per token: a quantified catalogue for LLM inference

Contents

Notation: amounts in euros (N €), decimals with a point. The dollar symbol is not used (on this site it is a formula delimiter).

TL;DR

Seven independent levers act on the numerator or the denominator of the identity \(\text{J/token} = \text{power (W)} / \text{throughput (tok/s)}\). Applied in order of cost-benefit: quantisation (FP16→FP8) cuts J/token by 30–50% without changing hardware; power capping to 70% of TDP reduces power by 30% with less than a 10% drop in throughput on memory-bound loads; DVFS in the decode phase saves a further 22–45%; continuous batching lowers J/token by 25–40% against unoptimised stacks; speculative decoding trims up to 29% off J/token at low batch; prefix caching eliminates the prefill recompute for repeated prompts; and scheduling to clean hours shifts the carbon footprint without changing physical consumption. Starting reference: a vLLM FP16 stack on an H100 SXM (700 W TDP) with Llama-3 70B produces ~0.39 J/token under realistic batch loads; an unoptimised stack (PyTorch baseline) starts 2–6× higher. The levers stack; the combined effect can reach a 73% reduction against the unoptimised baseline (arXiv 2504.17674).


The reference identity

$$\text{J/token} = \frac{\overline{P}\ [\text{W}]}{\text{throughput}\ [\text{tok/s}]}$$

where \(\overline{P}\) is the average power over the measurement window (see the methodology in energy per token). The levers act on one of the two factors:

  • They reduce \(\overline{P}\): power capping, DVFS, scheduling to low-intensity hours.
  • They raise throughput (the denominator): quantisation, continuous batching, speculative decoding, prefix caching, chunked prefill, model selection.
  • Both at once: quantisation (smaller weight footprint → a larger batch fits in VRAM → higher throughput at similar or lower power).

The expanded formula including infrastructure overhead:

$$\text{J/token}_{\text{effective}} = \frac{\overline{P}_{\text{GPU}} + \overline{P}_{\text{rest of node}}}{\text{throughput}_{\text{tok/s}}} \times \text{PUE}$$

For the lever calculations the work is done on \(\overline{P}_{\text{GPU}}\) for clarity; the PUE factor (see energy per token) amplifies or attenuates the effect of each lever proportionally.


Master table: levers × impact × cost × tool

LeverJ/token reduction (%)Effect on latencyEffect on qualityMain OSS toolSource
Quantisation FP16→FP830–50%−8–33% TPOT (improvement)<1% degradation on benchmarksvLLM, TRT-LLM, llm-compressorarXiv 2504.17674, baseten.co
Quantisation FP16→INT4 (AWQ/GPTQ)45–60%latency improves (lower BW)1–3% degradation depending on modelAutoAWQ, llm-compressor, vLLMarXiv 2504.17674
Continuous vs static batching25–40% vs PyTorch+5× throughput (improvement)no impactvLLM, TGI, TRT-LLMarXiv 2504.17674, TokenPowerBench
Power capping 70% TDP20–30% power<10% throughput (decode)no impactnvidia-smi, DCGM, ZeusarXiv 2604.11391, NERSC docs
DVFS decode-phase22–45% in decode1–6% total latencyno impactnvidia-smi, GreenLLM, DVFS-GPTarXiv 2501.08219, HAL 05190051
Speculative decodingup to 29% (batch≤16)TTFT improvesno demonstrable impactvLLM, TRT-LLMarXiv 2602.09113
Prefix caching50–90% on reusable prefillTTFT −50–80% (repeated prompts)no impactvLLM, SGLangvLLM docs
Chunked prefill~10–15% on mixed loadsmore stable TTFTno impactvLLM (SARATHI)arXiv 2308.16369
SLM vs dense LLM selection60–80% (7B vs 70B model)low latencydegradation varies by taskOllama, vLLM, llama.cpparXiv 2504.17674
Scheduling to clean hours0% J/token, up to −70% CO₂no impact on the loadno impactKueue, Volcano, cronACM SLIT, arXiv 2507.09942

Note: the percentages are against the effective J/token of the load, not against idle board power. The effects are always measured under conditions of equal output quality (same model, same serving stack, same prompt distribution).


Lever 1: quantisation

Mechanics

Quantisation reduces the numerical precision of the weights (and optionally the activations), which shortens the time spent reading weights from HBM per generated token. Decode is memory-bandwidth-bound: the bottleneck is reading the weights, not computing. Reducing bit width frees bandwidth for higher throughput or allows a larger batch in VRAM.

FormatBits/weightBW reduction vs FP32J/token vs FP16Tool
FP32321× (reference)+100% (worse)
BF16/FP1616referencevLLM native
FP8 (W8A8)8~4×−30–50%vLLM, TRT-LLM, llm-compressor
INT4 AWQ (W4A16)4~8×−45–60%AutoAWQ, llm-compressor
INT4 GPTQ (W4A16)4~8×−40–55%AutoGPTQ, vLLM

Concrete reference figures:

Quality cost

FP8 quantisation with calibration produces <1% degradation on standard benchmarks (MMLU, HumanEval). INT4 AWQ can produce 1–3% degradation depending on the model and the task; INT4 GPTQ without fine calibration, up to 2–5%. Validate with LLM energy leaderboards and your own quality benchmarks.

OSS tooling

# vLLM with FP8 (load-time quantisation, H100/A100)
vllm serve meta-llama/Llama-3-70B-Instruct \
  --quantization fp8 \
  --dtype auto

# llm-compressor: offline quantisation to W4A16 (AWQ)
python -m llmcompressor.transformers.compression.helpers \
  --model meta-llama/Llama-3-70B-Instruct \
  --recipe w4a16_awq.yaml \
  --output-dir llama-70b-w4a16/

Lever 2: continuous batching

Mechanics

Static batching keeps the batch fixed: if one request finishes early, the slot stays empty until the end of the batch. Continuous batching inserts new requests as soon as a slot frees up, keeping the GPU always at the highest possible utilisation.

The energy effect: GPU power is almost constant (the GPU is always active); the throughput grows. The result is a larger denominator at similar power:

$$\text{J/token}_{\text{continuous batch}} = \frac{\overline{P}}{\text{throughput}_{\uparrow}}$$

Measured figures (arXiv 2504.17674, TokenPowerBench arXiv 2512.03024):

  • vLLM with PagedAttention vs unoptimised Transformers: −25–40% J/token on high batch loads.
  • Online continuous batching vs static offline: a further −5% of J/token (small but consistent).
  • Batch 32→256 tokens: −25% J/token on Llama-3 70B (kernel economies of scale).
  • Throughput: ×5 against static batching stacks at equivalent load.

The efficiency knee on the H100 sits at around 256–512 tokens of batch; beyond that, J/token flattens or rises slightly.

OSS tooling

vLLM, TGI (HuggingFace Text Generation Inference), TRT-LLM. The relevant flag in vLLM: --max-num-seqs (maximum concurrent sequences); tuning it to the available VRAM maximises the effective batch.


Lever 3: power capping

Mechanics

The power cap sets a ceiling on instantaneous power (W). The GPU respects it by cutting the clock (internal DVFS). The efficiency trick: LLM decode is memory-bandwidth-bound; the GPU is already not at usefully full clock, and lowering the TDP reduces power without degrading throughput proportionally.

The power cap vs throughput curve (H100 SXM)

Figures from (arXiv 2604.11391) and NERSC (docs.nersc.gov/jobs/power-capping):

Power cap (W)% of TDP (700 W)Relative throughput (memory-bound)Efficiency (tok/W)
700 W100%100%1.00×
560 W80%~95%~1.19×
490 W70%~90–95%~1.27× (sweet spot)
420 W60%~80–85%~1.33× (latency rises)
350 W50%~75% (the H100 reaches maximum BW at 350 W memory-bound)~1.50×
200 W29%~50%frequency saturation

Key finding from arXiv 2604.11391: the H100 reaches its maximum effective memory bandwidth with only ~350 W on memory-bound loads (STriad benchmark), against a TDP of 700 W. Going from 700 W to 490 W (−30% power) produces less than a 10% drop in decode throughput: J/token improves by ~20–27%.

For compute-bound loads (heavy prefill), the sweet spot shifts to 400–500 W, where performance scales almost linearly with the cap; from 500 W to 700 W, the gain is only ~10% extra throughput for each additional 100 W.

J/token formula with a power cap

$$\text{J/token}(P_{\text{cap}}) = \frac{P_{\text{cap}} \times \eta(P_{\text{cap}})}{\text{throughput}_{\text{base}} \times f(P_{\text{cap}})}$$

where \(\eta(P_{\text{cap}})\) is the fraction of power actually consumed under the cap (on memory-bound loads, the GPU no longer consumes the whole cap), and \(f(P_{\text{cap}})\) is the resulting fraction of throughput. In the H100’s 490–560 W zone, \(\eta \approx 0{.}9\) and \(f \approx 0{.}92\text{–}0{.}95\): the numerator falls more than the denominator, so J/token improves.

Commands

# Set the power cap to 490 W on GPU 0 (H100 SXM, 700 W TDP)
sudo nvidia-smi -i 0 -pl 490

# Check the applied limit and the power draw in real time
nvidia-smi --query-gpu=power.limit,power.draw --format=csv -l 1

# With DCGM: read DCGM_FI_DEV_POWER_USAGE in Prometheus
# and DCGM_FI_DEV_POWER_LIMIT to confirm the cap is active
# Apply the cap to every GPU on the node (systemd/cron script)
for i in $(seq 0 3); do
  sudo nvidia-smi -i $i -pl 490
done

With DCGM in production, the cap can be set via dcgmi policy --set powercap:490 or through the NVIDIA GPU Operator (the powerLimit field in the DevicePlugin). Zeus (ml.energy/zeus) can sweep caps automatically and measure the resulting J/token per configuration.


Lever 4: DVFS (Dynamic Voltage and Frequency Scaling)

Mechanics

DVFS is finer-grained than a power cap: it allows the SM frequency to be set directly (nvidia-smi -lgc to lock the GPU clock) or left for the driver to adjust dynamically according to available power and load. In LLM inference, the asymmetry between phases is the key fact:

  • Prefill: compute-bound. Benefits from maximum clock. Sensitive to frequency reduction.
  • Decode: memory-bandwidth-bound. The SM clock barely matters; what rules is HBM bandwidth.

This asymmetry is what LLM-specific DVFS systems exploit:

SystemEnergy savingLatency penaltyHardwareSource
DVFS-GPT (HAL)up to 32% at iso-latency~1–2%A100, RTX 4090HAL 05190051
EcoInferup to 25.4% (average 21.5%)<5%A100arXiv MDPI Electronics
DualScale (disaggregated prefill/decode)22–45% with SLO1–6%H100arXiv 2602.18755
GreenLLM (SLO-aware DVFS)18–30%within the SLOarXiv 2508.16449

The paper arXiv 2501.08219 measures that reducing the GPU frequency from 2,842 MHz to 180 MHz achieves an average saving of 42% with only a 1–6% latency increase in the decode phase, because decode is memory-bound and the SM frequency is not the bottleneck.

Commands (manual DVFS)

# Lock the SM clock at 1,200 MHz (H100 boost: 1,980 MHz) for decode
sudo nvidia-smi -i 0 -lgc 1200,1200

# Restore the dynamic clock
sudo nvidia-smi -i 0 -rgc

# Persistent mode (needed for the lock to survive between jobs)
sudo nvidia-smi -pm 1

For automatic DVFS tuned to the SLO (target TPOT), systems such as GreenLLM or DVFS-GPT measure the time of each iteration and adjust the frequency in real time, without overrunning the latency budget.


Lever 5: model selection (SLM, MoE vs dense)

The effect of scale

J/token scales with model size, but sublinearly. For Llama-3 (arXiv 2504.17674):

ModelParametersRelative J/tokenFactor vs 1B
Llama-3 1B1B1.0×reference
Llama-3 8B8B~2.3××2.3 (not ×8)
Llama-3 70B70B~7.3××7.3 (not ×70)
Llama-3 405B405B~40××40 (not ×405)

J/token grows ~7.3× from 1B to 70B, while parameters grow ×70: hardware efficiency (caches, tensor parallelism, kernels) cushions the scaling. Even so, moving from 70B to 8B cuts J/token by ~68% if the quality is sufficient for the task.

MoE vs dense

MoE models activate only a subset of experts per token (typically 2 of 8–64), which reduces active compute. But there is an implementation trap:

  • OLMoE-1B-7B (MoE, 1B active) vs OLMo-1B (dense): the MoE consumes 54.24% more energy per token than the dense model of the same active size (arXiv 2504.17674), because the fused expert kernels are ~19–63% slower than an equivalent dense GEMM.
  • OLMoE-1B-7B vs OLMo-7B (dense): here the MoE is indeed more efficient (7B active → only 1B active, a ~7× reduction in active FLOPs per token).

The rule: MoE is efficient when the comparison is equal total parameters, fewer active (for example Mixtral 8×7B vs dense Llama-3 70B). It is not efficient when the comparison is equal active parameters per token.

Model selection table by use case

Use caseRecommended modelEfficiency rationale
Simple chat, entity extractionSLM 7–8B FP8−68% J/token vs 70B
RAG with long contexts70B FP8 or MoE 8×7Boptimal quality/J at K>2K tokens
Complex code, reasoning70B FP8 or 405B INT4quality is non-negotiable
Classification, embeddingsdedicated model (e.g. E5, BGE)orders of magnitude less J
Deferrable offline batchlarge MoE (DeepSeek, Mixtral)high quality, batch throughput

Lever 6: speculative decoding

Mechanics

Speculative decoding uses a small draft model to propose several tokens, which the target model verifies in parallel in a single forward pass. If the tokens are accepted, K tokens are generated per step instead of 1: potentially K× throughput.

The energy efficiency condition

The J/token benefit depends on batch size (arXiv 2602.09113):

Batch sizeEffect on J/tokenReason
1–16 (low batch)−up to 29%the draft model fills the waiting time; verification is cheap
32–64 (medium batch)~0% (neutral)verification overhead cancels out the gain
128+ (high batch)+25% (worse)GPU saturated; the draft model adds overhead without saving

Conclusion: speculative decoding is a J/token lever only in a low-latency regime (batch≤16); in high-throughput serving it is counterproductive in J/token terms (although it reduces TPOT latency).

OSS tooling

vLLM supports speculative decoding with --speculative-model and --num-speculative-tokens. TRT-LLM does too. The draft model must come from the same family (for example Llama-3 8B as draft for Llama-3 70B).


Lever 7: prefix caching and chunked prefill

Prefix caching

The prefill KV-cache of a shared prompt (system prompt, few-shot examples, document context) is identical across requests. Storing and reusing it eliminates the prefill recompute for that fraction of the prompt.

Energy impact: prefill is compute-bound and draws power spikes. Removing the repeated prefill removes those spikes. In scenarios with a fixed 1,000-token system prompt and 200-token user prompts, the saving is ~1,000/(1,000+200) = ~83% of prefill energy. In total J/token, the effect depends on the length of the shared prompt against the generation length.

Enabling it in vLLM:

vllm serve meta-llama/Llama-3-70B-Instruct \
  --enable-prefix-caching \
  --max-num-seqs 256

Chunked prefill (SARATHI)

Chunked prefill splits the prefill into fixed-size chunks and processes each chunk together with decode tokens from other requests. The benefit: the prefill of a long prompt no longer blocks the decode of other requests (reducing TPOT spikes), which allows higher GPU utilisation over time.

In terms of total J/token, chunked prefill reduces the node’s peak power (fewer prefill spikes) and improves average utilisation, which translates into ~10–15% less J/token on mixed loads with long prompts (arXiv 2308.16369).

# Enable chunked prefill in vLLM (chunk size: 512 tokens)
vllm serve meta-llama/Llama-3-70B-Instruct \
  --enable-chunked-prefill \
  --max-num-batched-tokens 512

Lever 8: scheduling to clean hours

This lever does not reduce physical J/token, but it does reduce the gCO₂/token of deferrable load. The mechanics: moving training, document ingestion, batch re-ranking and fine-tuning to the hours of lowest grid carbon intensity.

Impact figures for temporal shifting (ACM SLIT, arXiv 2507.09942):

  • CO₂ reduction from temporal shifting: up to 34.7% for flexible loads.
  • With carbon-aware reinforcement learning (Eco-Orchestrator): up to a 70% offset in integrated deployments.
  • In Spain, the hourly variation in intensity is ~80–250 gCO₂/kWh: a factor of ~3× within the same day (see from watt to carbon).

The practical implementation uses Kueue or Volcano on Kubernetes, with a grid intensity metric (the ElectricityMaps API or esios) as the scheduling signal. Loads are marked with a carbon-deadline annotation (the maximum tolerable wait) and the scheduler places them in the minimum-intensity hours within that window.

# Kueue annotation for carbon-aware scheduling
metadata:
  annotations:
    kueue.x-k8s.io/carbon-aware: "true"
    kueue.x-k8s.io/carbon-deadline: "8h"

The power cap vs throughput curve: the sweet spot

%Power cap (W) →%200280350420490560630700050708090100power (% TDP)throughput (%)sweet spot490–560 W: −30% power, <10% throughput. Minimum J/token.H100 SXM (700 W TDP). Memory-bound load (LLM decode). Source: arXiv 2604.11391, NERSC.

Reading the chart: the power curve (solid line) falls faster than the throughput curve (dashed line) in the 490–560 W zone. Above 560 W, each additional 70 W gives only ~5% extra throughput; below 420 W, throughput starts falling faster than power. The efficiency sweet spot (minimum J/token) sits at 490–560 W for decode-bound loads.

For compute-bound loads (pure prefill), the sweet spot shifts to 500–600 W: prefill saturates SM compute and needs more power to sustain throughput.


How to measure the effect and validate quality

Measurement stack

The full stack for measuring the effect of each lever:

What to measureToolMetric
Real-time GPU powerDCGM (DCGM_FI_DEV_POWER_USAGE)W per GPU, 100ms
J/token in productionKepler + vLLM tokensrate(kepler_joules) / rate(vllm_tokens)
J/token on the benchZeus (ZeusMonitor)J measured during the benchmark
ThroughputvLLM metrics (vllm:generation_tokens_total)tok/s
TPOT latencyvLLM (vllm:e2e_request_latency)ms/tok
Output qualitylm-evaluation-harnessMMLU, HumanEval, etc.

See the full stack in energy tooling.

Measurement protocol per lever

# Real-time J/token (Kepler + vLLM in Prometheus)
sum(rate(kepler_container_joules_total{container="vllm"}[5m]))
  /
sum(rate(vllm_generation_tokens_total[5m]))

# Average power per GPU (DCGM)
avg by (gpu) (DCGM_FI_DEV_POWER_USAGE)

# Check that the power cap is active
avg by (gpu) (DCGM_FI_DEV_POWER_LIMIT)

With Zeus, the configuration sweep is automatic:

from zeus.monitor import ZeusMonitor

monitor = ZeusMonitor(gpu_indices=[0, 1, 2, 3])

with monitor.begin_window("fp8_inference"):
    # run the benchmark with vLLM FP8
    run_benchmark(model="llama-3-70b-fp8", num_tokens=10_000)

result = monitor.end_window("fp8_inference")
print(f"J/token: {result.total_energy / 10_000:.4f}")

Quality validation

Validating that the lever does not degrade quality is done with lm-evaluation-harness (github.com/EleutherAI/lm-evaluation-harness):

# Compare MMLU between FP16 and FP8
lm_eval --model vllm \
  --model_args pretrained=meta-llama/Llama-3-70B-Instruct,dtype=float16 \
  --tasks mmlu --num_fewshot 5 --output_path ./results/fp16/

lm_eval --model vllm \
  --model_args pretrained=meta-llama/Llama-3-70B-Instruct,quantization=fp8 \
  --tasks mmlu --num_fewshot 5 --output_path ./results/fp8/

The MMLU score difference between FP16 and FP8 with calibration is typically <1%. Without calibration it can be 2–4%.


Pareto decision table (energy / latency / quality)

LeverJ/tokenTPOT (latency)QualityImplementation costReversibility
FP8 quantisation↓↓↓↓ (improves)~ (−<1%)Low (1 flag)High
INT4 AWQ quantisation↓↓↓↓↓ (improves)↓ (−1–3%)Medium (recalibrate)High
Continuous batching↓↓↓~ (neutral on TPOT)~Low (new engine)High
Power cap 70% TDP↓↓↑ <10%~Very low (1 command)Immediate
DVFS decode↓↓↓↑ <6%~Medium (script + tuning)High
Speculative decoding↓ (low batch)↓ (improves TTFT)~Medium (draft model)High
Prefix caching↓↓ (prefill)↓↓ (TTFT improves)~Low (1 flag)High
Chunked prefill↑ stable TPOT~Low (1 flag)High
SLM (7B vs 70B)↓↓↓↓↓↓ (improves a lot)↓↓ (−variable)High (quality re-eval)Medium
MoE (vs dense, same active size)↑ (+54%)~
Scheduling to clean hours~ J/token, ↓↓ CO₂~ (for deferrable)~Medium (scheduler)High

Key: ↓↓↓↓ strong improvement · ↓↓↓ significant improvement · ↓↓ moderate improvement · ↓ slight improvement · ~ neutral · ↑ worsens · ↑↑ worsens significantly.


Stacking levers: the combined effect

The levers are mostly orthogonal and they stack. The maximum combined impact documented in (arXiv 2504.17674):

“Correct application of the relevant inference optimisations can reduce total energy consumption by up to 73% against unoptimised baselines.”

Recommended sequence by cost-benefit:

  1. Optimised engine (vLLM, TRT-LLM) with continuous batching: −25–40% immediately.
  2. FP8 quantisation (if the hardware supports it: H100, A100 with limited support): a further −30–50% on the remaining J/token.
  3. Power cap at 70% TDP: −20–30% power with <10% of throughput. Low cost.
  4. Prefix caching: turn it on if there are system prompts or repeated contexts. No cost.
  5. Chunked prefill: if the load has long variable prompts.
  6. DVFS in decode: a further −22–45% if the SLO allows it.
  7. Speculative decoding: only if the batch is low (<16) and TTFT latency matters.
  8. Model selection: move to an SLM if the quality is sufficient (evaluate with lm-evaluation-harness on your specific task).

Quantified example on 4×H100 SXM (2,800 W node TDP), Llama-3 70B, chat load:

ConfigurationPower (W)Throughput (tok/s)J/token
PyTorch FP16, static batching~2,100~4005.25
vLLM FP16, continuous batching~2,200~1,8001.22
vLLM FP8, continuous batching~2,100~2,4000.875
+ power cap 490 W/GPU (1,960 W node)~1,960~2,1600.907
+ prefix caching (40% hit rate)~1,960~2,6000.754
+ DVFS decode 1,200 MHz~1,500~2,4000.625

The values are illustrative estimates based on the cited papers applied to a 4×H100 node. Real J/token depends on the prompt distribution, the effective batch and the temperature of the models. Measuring it with Zeus or DCGM+Kepler is mandatory.


Reference hardware: TDP and power cap ranges

GPUTDP (W)Supported cap rangeDecode sweet spot
H100 SXM 80GB700200–700 W~490–560 W
H100 PCIe 80GB350100–350 W~245–280 W
A100 SXM 80GB400100–400 W~280–320 W
A100 PCIe 80GB300100–300 W~210–240 W
L40S 48GB350100–350 W~245–280 W
RTX 5090 (reference, PCIe)575~100–575 W~400–460 W

For the exact ranges: nvidia-smi -q -d POWER | grep -E "Min|Max|Current".


Executive summary by role

RoleFirst actionSecond actionKey tool
Cluster operatornvidia-smi -pl [70% TDP] on every nodeEnable persistent modenvidia-smi, DCGM
Serving engineerMigrate to vLLM FP8 with continuous batchingEnable prefix cachingvLLM, llm-compressor
Platform architectSelect the smallest model that meets the quality SLODesign a carbon-based scheduling policylm-evaluation-harness, Kueue
MLOps teamSet up a power cap sweep with ZeusInstrument J/token in PrometheusZeus, DCGM exporter

See the full measurement stack in energy tooling and the J/token methodology in energy per token. For the context of reference energy leaderboards and benchmarks, see LLM energy leaderboards. The connection with full TCO is in GPU utilisation as FinOps.


Sources