plow vs vLLM

Compare compiled execution, multi-model serving, live load and unload, deployment requirements and measured latency.

Updated

plow separates model compilation from serving and can host several model bundles in one Rust process. Each bundle has its own checkpoint, settings and model name. vLLM offers broad model support and a large serving ecosystem. The practical choice depends on your models, deployment needs and measured workload.

Architecture and deployment

Standard serving paths, checked November 4, 2026
CapabilityvLLMplow
ExecutionPyTorch execution with compilation caching and graph capture.Ahead-of-time packet plans for a hardware target. GPU interpreters execute the prepared operations; the host still handles requests and batching.
Multiple base modelsStandard serving uses separate model servers with a routing layer.One process registers multiple bundles and routes by the request’s model name.
Memory lifecycleSleep and wake controls release and restore engine memory.Per-model load, bounded-drain unload and residency status. Managed GPU groups can evict models when memory is needed.
Starting a serverLoads weights and initializes execution. Compatible compilation artifacts can be reused.Loads compiled assets and checkpoint weights. Device initialization and any backend-specific warmup still apply.
Deployment artifactModel weights, the serving environment and compatible caches.Model bundles carry execution plans and serve defaults. One runtime binary serves compatible bundles of a release.

Sources: vLLM’s multi-model FAQ, compilation cache and sleep mode; plow’s runtime deployment contract and model manager.

The multiple-base-model row describes standard vLLM serving. vLLM also supports dynamic LoRA adapters, and its Gaudi plugin offers sequential model swaps.

Auto objective follows demand

--objective auto is plow’s default serving policy. It selects latency- or throughput-oriented rules from live decode width, queued requests and KV-memory pressure:

  • Light traffic: latency-oriented decode grouping and prefill packing.
  • Rising demand: switch to throughput rules when a queue forms, the decode batch widens or the KV budget fills.
  • Traffic settles: return to latency rules after a two-second calm window, avoiding repeated mode changes around a threshold.

The policy adjusts supported decode and prefill mechanisms within the compiled plan. Backend and packet capabilities still determine which mechanisms can run. You can pin --objective latency or --objective throughput; /metrics exposes the active class and switch count as plowrt_serve_mode and plowrt_serve_mode_switches_total.

This is an adaptive scheduling policy, not a measured speedup by itself. See the serving-objective reference and policy implementation.

Multiple models, one process

Repeat --assets to register separate compiled bundles. Each can use a different checkpoint and served name. This example assumes compatible bundles at the paths shown, each with its weights and tokenizer in a checkpoint/ subdirectory:

plowrt serve --objective auto --bind 127.0.0.1 --port 8080 \
  --socket /tmp/plowrt.sock \
  --assets /models/model-a,slug=model-a \
  --assets /models/model-b,slug=model-b

Send "model": "model-a" or "model": "model-b" in the inference request. Each model has its own dispatcher and engine state. Models can stay resident together when memory permits; they still share compute capacity. The runtime provides scheduling between resident models, including round-robin turns. Co-residency does not guarantee simultaneous kernel execution or unchanged latency.

Load, unload and inspect

The control API manages residency without restarting the server:

  • Load: make a registered model resident, or register a new bundle. Explicit loads do not evict other models unless evict: true is requested.
  • Unload: stop admission, drain in-flight work up to a deadline, then release the model’s engine. The default deadline is 30 seconds; remaining work is preempted when it expires.
  • Reload: an explicitly unloaded model stays unavailable until loaded again. Its name remains registered unless deregister: true was requested.
  • Inspect: /v1/models/status reports resident and serving state, device placement and supported control capabilities. /v1/models lists registered models, including unloaded ones.

These operations use the owner-only Unix socket or the authenticated control listener, separate from the public inference listener. With the example server above:

curl --unix-socket /tmp/plowrt.sock http://localhost/v1/models/status

curl --unix-socket /tmp/plowrt.sock http://localhost/v1/models/unload \
  -H 'Content-Type: application/json' \
  -d '{"model":"model-b","drain_timeout_ms":30000}'

curl --unix-socket /tmp/plowrt.sock http://localhost/v1/models/load \
  -H 'Content-Type: application/json' \
  -d '{"model":"model-b"}'

The CLI command plowrt load downloads assets into the local store. The control API’s load makes a model resident in a running server. CPU and Metal support explicit load/unload but do not support automatic eviction. See the control API and CPU/Metal implementation.

Other reasons to evaluate plow

  • Language and speech together. Supported LLM, speech recognition and speech synthesis bundles share the server’s API, model listing and metrics. Availability depends on the model and backend. See the deployment contract.
  • Check bundles before serving. The loader checks packet/object pairing and runtime requirements. Bundles with checkpoint pins also check shard sizes and tensor headers before loading weights. These compatibility checks complement numerical validation. See the bundle checks.
  • Separate downloads from startup. serve --model resolves locally prepared assets. Fetching a build is a separate step, so a provisioned server can start without contacting the registry. See model distribution.

Selected measured comparisons

These results compare plow with vLLM on specific models and configurations. They do not measure multi-model switching or establish a universal latency advantage. The board includes wins, ties and losses; each result links to settings and quality checks.

Showing all results for throughput, all GPUs.

How to read the charts

plow wins shows workloads where plow leads on the selected metric. All results includes ties and vLLM wins. Each bar is one workload: right of parity, plow is ahead; left, vLLM is. Throughput counts input and output tokens. Latencies are displayed as speed ratios. Bars use a logarithmic scale capped at 4x; labels show the full ratio. The table shows all metrics for the same filtered workloads.

Gemma-4 26B-A4B on 1x H100

Against
vLLM 0.29
Precision
FP8
Run
Accuracy
FP32-reference gate passed
Chat mix1.8 sessions/s parity
Agent sessions, 16k context64 sessions 1.40x
Chat mix1.8 sessions/s 1.47x
Agent sessions, 16k context64 sessions 1.19x
Chat mix1.8 sessions/s 1.82x
Agent sessions, 16k context64 sessions 1.67x

The chat mix arrives at a fixed rate, so throughput is pinned by the arrivals and the wins are in latency.

Latency is the 99th percentile (p99) of requests. Settings and source, every row (CSV).

Gemma-4 E4B on 1x H100

Against
vLLM 0.29
Precision
BF16
Run
Accuracy
FP32-reference and logit-parity gates passed
1,000 / 128 tokens32 requests 1.11x
1,000 / 128 tokens32 requests 1.35x
1,000 / 128 tokens32 requests 1.08x

Greedy decoding, 1,000 input tokens and 128 output tokens, two repeats at 32 concurrent requests.

Latency is the 99th percentile (p99) of requests. Settings and source, every row (CSV).

Qwen3.8 27B on 1x H100

Against
vLLM 0.28
Precision
BF16
Run
Accuracy
FP32-reference gate passed at 1, 8 and 32 requests
1,000 / 128 tokens1 request vLLM 1.08x
1,000 / 128 tokens8 requests vLLM 1.18x
1,000 / 128 tokens32 requests vLLM 1.04x
1,000 / 128 tokens64 requests vLLM 1.14x
1,000 / 128 tokens128 requests vLLM 1.10x
1,000 / 128 tokens1 request 2.08x
1,000 / 128 tokens8 requests vLLM 1.01x
1,000 / 128 tokens32 requests 1.01x
1,000 / 128 tokens64 requests vLLM 1.70x
1,000 / 128 tokens128 requests vLLM 1.22x
1,000 / 128 tokens1 request vLLM 1.12x
1,000 / 128 tokens8 requests vLLM 1.40x
1,000 / 128 tokens32 requests vLLM 1.25x
1,000 / 128 tokens64 requests 1.06x
1,000 / 128 tokens128 requests 1.30x

Sampled decoding (temperature 1, top-p 0.95), 1,000 input tokens and 128 output tokens, two repeats per cell. The source also contains greedy runs.

Latency is the 99th percentile (p99) of requests. Settings and source, every row (CSV).

GLM-5.3-Flash on 8x AMD MI350X

Against
vLLM 0.31.1rc1 (ROCm)
Precision
FP8
Run
Accuracy
Accuracy gate passed
1,024 / 128 tokens8 requests vLLM 1.10x
4,096 / 128 tokens1 request vLLM 1.20x
4,096 / 128 tokens8 requests vLLM 1.04x
16,384 / 128 tokens1 request vLLM 1.22x
16,384 / 128 tokens128 requests vLLM 1.54x
1,024 / 128 tokens8 requests 2.78x
4,096 / 128 tokens1 request 3.57x
4,096 / 128 tokens8 requests 2.08x
16,384 / 128 tokens1 request 1.61x
16,384 / 128 tokens128 requests vLLM 1.53x
1,024 / 128 tokens8 requests 1.22x
4,096 / 128 tokens1 request vLLM 1.26x
4,096 / 128 tokens8 requests 1.41x
16,384 / 128 tokens1 request vLLM 1.26x
16,384 / 128 tokens128 requests 1.25x

Both engines use the same eight-GPU host and benchmark client. Prefix caching is on for plow and off for vLLM; these results apply to those settings.

Latency is the 99th percentile (p99) of requests. Settings and source, every row (CSV).

Selected results as a table
plow / vLLM ratios for the filtered workloads
Model and GPUWorkloadLoadThroughputFirst tokenPer tokenLatency stat
Gemma-4 26B-A4B, 1x H100Chat mix1.8 sessions/s1.00x0.68x0.55xp99
Gemma-4 26B-A4B, 1x H100Agent sessions, 16k context64 sessions1.40x0.84x0.60xp99
Gemma-4 E4B, 1x H1001,000 / 128 tokens32 requests1.11x0.74x0.93xp99
Qwen3.8 27B, 1x H1001,000 / 128 tokens1 request0.93x0.48x1.12xp99
Qwen3.8 27B, 1x H1001,000 / 128 tokens8 requests0.85x1.01x1.40xp99
Qwen3.8 27B, 1x H1001,000 / 128 tokens32 requests0.96x0.99x1.25xp99
Qwen3.8 27B, 1x H1001,000 / 128 tokens64 requests0.88x1.70x0.94xp99
Qwen3.8 27B, 1x H1001,000 / 128 tokens128 requests0.91x1.22x0.77xp99
GLM-5.3-Flash, 8x AMD MI350X1,024 / 128 tokens8 requests0.91x0.36x0.82xp99
GLM-5.3-Flash, 8x AMD MI350X4,096 / 128 tokens1 request0.83x0.28x1.26xp99
GLM-5.3-Flash, 8x AMD MI350X4,096 / 128 tokens8 requests0.96x0.48x0.71xp99
GLM-5.3-Flash, 8x AMD MI350X16,384 / 128 tokens1 request0.82x0.62x1.26xp99
GLM-5.3-Flash, 8x AMD MI350X16,384 / 128 tokens128 requests0.65x1.53x0.80xp99

Ratios are plow divided by vLLM, as published. For throughput higher is better; for the two latency columns lower is better.

Choose for your workload

Check available plow builds against your model, hardware and precision. Then test the same prompts, output lengths, cache settings and offered load on both engines. Include memory use, cold and warm startup, and first-request latency after a model reload.

OpenAI-compatible clients can reuse the base URL pattern, but compatibility is endpoint- and option-specific. Validate the request fields, tool calls and streaming behavior your application uses. plow’s API compatibility notes describe its supported surface and gaps.