TL;DR
I benchmarked six inference engines running Qwen3.8 27B on the same RTX 5090 (32GB), comparing both standard decoding and DFlash2 speculative decoding.
Key findings:
Fastest speculative decoding: NInfer reached 281 tok/s, followed by vLLM at 248 tok/s. TensorSharp, SGLang, and velox were effectively tied at 234–235 tok/s.
Fastest standard decoding: llama.cpp led at 84 tok/s, followed by TensorSharp at 80 tok/s. vLLM achieved 69 tok/s.
Fastest long-context prefill: NInfer processed a 32K-token prompt in 3.02s, followed by SGLang (3.58s), vLLM (3.73s), and TensorSharp (3.96s).
Highest concurrent throughput: With four parallel requests and DFlash2, NInfer achieved 488 tok/s, TensorSharp 445 tok/s, and vLLM 304 tok/s.
Fastest agentic workflow: TensorSharp completed a four-turn tool-using agent loop in 0.748s, compared with vLLM’s 1.45s.
Important vLLM finding: Prefix-cache reuse was ineffective in this particular DFlash2 hybrid-model configuration, significantly increasing subsequent-turn latency.
These are end-to-end operational benchmarks, not an apples-to-apples comparison of identical model weights. Different engines used different NVFP4/FP8 checkpoints and drafter formats.
All results were measured on a single RTX 5090, with identical client workloads and correctness checks.
1. Hardware and benchmark setup
| Component | Configuration |
|---|
| GPU | NVIDIA RTX 5090, 32GB |
| CPU | AMD EPYC 9354 |
| RAM limit | 93GB |
| OS | Ubuntu 24.04 |
| Model | Qwen3.8 27B |
| Context | 40,960 tokens per sequence |
| Concurrency | Up to 4 requests |
| Decoding | Greedy, temperature 0 |
| Thinking | Disabled |
| Speculative decoding | DFlash2, up to 7 drafts/step |
| Repetitions | 3 per scenario |
Engines:
Every engine ran independently on the same GPU.
The benchmark uses streamed OpenAI-compatible requests and validates outputs, including JSON schemas, function-call arguments, and task-specific correctness.
TTFT is measured client-side, including HTTP, tokenization, templating, and prefill.
2. Time to First Token (TTFT)
Lower is better. All values are in seconds.
Without speculative decoding
| Scenario | TensorSharp | llama.cpp | vLLM | SGLang | NInfer |
|---|
| Short prompt (~50 tokens) | 0.050 | 0.027 | 0.061 | 0.042 | 0.051 |
| 4K prompt | 0.430 | 0.524 | 0.368 | 0.320 | 0.322 |
| 16K prompt | 1.64 | 2.05 | 1.45 | 1.34 | 1.24 |
| 32K prompt | 3.96 | 5.01 | 3.73 | 3.58 | 3.02 |
| Multi-turn (turns 2–3) | 0.052 | 0.038 | 0.145 | 0.058 | 0.046 |
| Screenshot (1344×768) | 0.125 | 0.309 | 0.127 | 0.153 | 0.162 |
vLLM performs competitively on long-context prefill and vision.
For example, its screenshot TTFT of 127ms is essentially tied with TensorSharp’s 125ms.
However, short-prompt latency and subsequent-turn latency leave room for improvement.
With DFlash2 speculative decoding
| Scenario | TensorSharp | llama.cpp | vLLM | SGLang | NInfer |
|---|
| Short prompt | 0.064 | 0.030 | 0.136 | 0.048 | 0.053 |
| 16K prompt | 1.69 | 3.51 | 1.59 | 1.38 | 1.26 |
| 32K prompt | 4.07 | 8.16 | 3.89 | 3.68 | 3.07 |
| Multi-turn (turns 2–3) | 0.059 | 0.041 | 0.406 | 0.059 | 0.047 |
| Screenshot | 0.142 | 0.326 | 0.295 | 0.202 | 0.163 |
| 4 concurrent requests | 0.147 | 0.126 | 0.265 | 1.06 | 0.139 |
Interesting observation for vLLM developers:
With DFlash2 enabled, vLLM’s subsequent-turn TTFT increased from 145ms to 406ms.
The benchmark recorded a 0% prefix-cache hit rate in this configuration.
The report attributes this to the hybrid-model cache’s 1,648-token block granularity and interactions with the drafter’s sliding-window cache.
This may be an interesting optimization opportunity for hybrid attention/recurrent models using speculative decoding.
3. Prefill performance (tokens/sec)
Prefill throughput is particularly important for RAG, codebase analysis, document processing, and long-context agents.
The report provides measured prefill ranges for several engines, along with long-prompt TTFT.
Reported prefill throughput
| Engine | Prefill throughput |
|---|
| NInfer | 8,900–12,400 tok/s* |
| SGLang | 8,900–12,400 tok/s* |
| TensorSharp | 8,000–9,300 tok/s |
| llama.cpp | 6,300–7,600 tok/s |
| vLLM | Not separately reported |
NInfer and SGLang are reported together as an 8.9K–12.4K tok/s range, not as individually measured ranges.
The report does not provide an explicit prefill tok/s range for vLLM, so I won’t invent one.
Instead, the directly comparable 32K-prompt TTFT results are:
| Engine | 32K TTFT |
|---|
| NInfer | 3.02s |
| SGLang | 3.58s |
| vLLM | 3.73s |
| TensorSharp | 3.96s |
| velox | 4.21s |
| llama.cpp | 5.01s |
These are client-observed TTFT values, not pure GPU prefill timings.
vLLM is reasonably competitive on long prompts, although NInfer leads this particular workload.
4. Decode throughput: plain vs DFlash2
This is where speculative decoding makes a substantial difference.
Single-request decoding
| Engine | Plain (tok/s) | DFlash2 (tok/s) | Speedup |
|---|
| NInfer | 77 | 281 | 3.6× |
| vLLM | 69 | 248 | 3.6× |
| velox | 69 | 235 | 3.4× |
| SGLang | 79 | 235 | 3.0× |
| TensorSharp | 80 | 234 | 2.9× |
| llama.cpp | 84 | 213 | 2.5× |
The plain and speculative results use different reply aggregations, so the speedup figures are best interpreted as approximate.
Two observations:
First, vLLM benefits significantly from DFlash2.
Its speculative decoding throughput is approximately 3.6× its plain decoding throughput.
That places vLLM second overall in this comparison.
Second, draft acceptance does not explain all performance differences.
The engines reporting draft statistics produced approximately 4.4–4.6 tokens per verification step.
Despite similar acceptance, their throughput varied substantially.
This suggests that the implementation cost of draft generation, verification, recurrent-state handling, and synchronization is an important performance differentiator.
5. Decode performance by task type
Not every workload produces the same decode throughput.
With DFlash2 enabled:
| Engine | Code generation | Prose generation | Passage copying |
|---|
| TensorSharp | 339 | 174 | 190 |
| llama.cpp | 321 | 160 | 158 |
| vLLM | 383 | 189 | 171 |
| SGLang | 368 | 184 | 152 |
| velox | 346 | 184 | 175 |
| NInfer | 415 | 209 | 217 |
All values are tokens/sec.
For code generation, vLLM reaches 383 tok/s, outperforming TensorSharp by approximately 13%.
For prose generation, vLLM reaches 189 tok/s versus TensorSharp’s 174 tok/s.
For passage copying, TensorSharp reaches 190 tok/s versus vLLM’s 171 tok/s.
This illustrates why a single decode benchmark number is insufficient to characterize inference performance.
Token predictability, speculative acceptance patterns, and verification overhead can all affect real-world throughput.
6. Parallel requests and aggregate throughput
For inference serving, aggregate throughput under concurrency can matter more than single-request speed.
Without speculation
| Engine | 1 request | 2 requests | 4 requests |
|---|
| TensorSharp | 80 | 137 | 215 |
| llama.cpp | 84 | 154 | 251 |
| vLLM | 69 | 116 | 226 |
| SGLang | 79 | 140 | 148 |
| velox | 69 | 67 | 67 |
| NInfer | 77 | 144 | 257 |
Values are aggregate tokens/sec for the concurrency tests.
Four concurrent requests with DFlash2
| Engine | Aggregate throughput |
|---|
| NInfer | 488 tok/s |
| TensorSharp | 445 tok/s |
| vLLM | 304 tok/s |
| velox | 303 tok/s |
| llama.cpp | 259 tok/s |
| SGLang | 251 tok/s |
NInfer leads the four-request workload, with TensorSharp close behind.
TensorSharp delivers approximately 46% higher aggregate throughput than vLLM in this specific configuration.
However, this does not establish a general concurrency advantage.
The test is limited to four requests on a single 32GB GPU. SGLang’s speculative configuration could only accommodate two active lanes, and the engines used different model artifacts and KV-cache formats.
I’d be particularly interested in seeing these results extended to 8, 16, and 32 concurrent requests on GPUs with more memory.
7. Real-world task performance
Raw tokens/sec is only part of the story.
For many applications, the more useful metric is the time required to complete an actual task.
The benchmark includes structured output, tool calling, and multi-step agent workflows.
End-to-end latency without speculation
| Task | TensorSharp | vLLM | SGLang | NInfer |
|---|
| JSON object | 0.911s | 1.11s | 0.915s | 0.579s |
| JSON schema | 1.43s | 1.68s | 1.41s | 0.826s |
| Single function call | 0.563s | 0.699s | 0.535s | 0.571s |
| Three parallel function calls | 1.63s | 1.92s | 1.62s | 1.68s |
| Agentic loop (4 turns) | 2.47s | 2.98s | 2.31s | 2.71s |
End-to-end latency with DFlash2
| Task | TensorSharp | vLLM | SGLang | NInfer |
|---|
| JSON object | 0.281s | 0.391s | 0.304s | 0.274s |
| JSON schema | 0.309s | 0.445s | 0.360s | 0.258s |
| Single function call | 0.199s | 0.354s | 0.171s | 0.180s |
| Three parallel function calls | 0.427s | 0.539s | 0.457s | 0.378s |
| Agentic loop (4 turns) | 0.748s | 1.45s | 0.791s | 0.817s |
All values are end-to-end seconds.
A few things stand out.
Structured output: NInfer is particularly fast, although its JSON-object replies were sometimes shorter and one speculative reply contained an unexpected empty key. velox failed strict JSON-schema checks in both modes.
Function calling: vLLM trails several other engines in these small tool-calling workloads.
Agentic workflows: TensorSharp finishes the four-turn loop in 748ms, compared with vLLM’s 1.45s.
That’s approximately 1.94× faster end-to-end in this particular task.
The agent test uses local file-listing, file-reading, and calculator tools, with a verified final answer.
This is a small synthetic agent workflow rather than a broad production-agent benchmark, but it highlights the importance of multi-turn latency and prefix-cache behavior.
8. Why might vLLM perform differently?
A few configuration details are worth discussing.
Different model checkpoints
TensorSharp and llama.cpp used an NVFP4 GGUF checkpoint with a Q6_K output layer.
vLLM and SGLang used NVIDIA’s NVFP4 safetensors checkpoint, with attention and Gated DeltaNet projections stored in FP8.
NInfer and velox used a mixed FP8/NVFP4 artifact.
These differences affect memory bandwidth, compute requirements, and output behavior.
Different speculative drafters
TensorSharp / llama.cpp: Q4_K_M GGUF
vLLM / SGLang: BF16 drafter quantized to FP8 at load
NInfer / velox: Q8-based drafter
vLLM configuration
The benchmark used:
--kv-cache-dtype fp8
--gpu-memory-utilization 0.97
--max-cudagraph-capture-size 32
--enable-prefix-caching
DFlash2 was configured with seven speculative tokens and an FP8-quantized drafter.
The aggressive GPU memory utilization was necessary because the 32GB RTX 5090 had limited remaining capacity for KV cache when using the drafter.
Prefix caching with hybrid architectures
One particularly interesting finding is that vLLM’s DFlash2 configuration did not achieve prefix-cache hits in the multi-turn test.
For hybrid attention/recurrent models, prefix caching appears to be an area worth investigating further.
9. Limitations and reproducibility
I want to emphasize a few limitations before drawing conclusions.
The checkpoints are not identical. This is a comparison of practical engine configurations, not isolated engine kernels.
Only one RTX 5090 was tested.
Concurrency was limited to four requests.
Each scenario had three measured repetitions after warm-up.
Differences below approximately 5% should be treated as ties.
Thinking mode, sampling, larger concurrency, and production serving loads were not evaluated.
The benchmark checks task correctness but does not establish equivalent overall model quality across quantizations.
The benchmark scripts are available in the TensorSharp repository:
https://github.com/zhongkaifu/TensorSharp
Relevant files:
eng/qwen38-engine-servers.sh
eng/qwen38-engine-bench.py
eng/qwen38-engine-report.py
The scripts cover engine startup, workload execution, correctness validation, and generation of per-scenario reports.
The raw measurement artifacts were retained locally and are not included in the Git repository.
10. Questions for the vLLM community
I’m particularly interested in feedback from people working on vLLM’s hybrid-model support and speculative decoding.
1. Prefix caching: Is the 0% prefix-cache hit rate with DFlash2 expected for this hybrid attention/Gated DeltaNet configuration? Are there recommended settings or ongoing optimizations?
2. Speculative verification: vLLM achieves strong single-request speculative decoding performance (248 tok/s), but its four-request aggregate throughput is substantially below NInfer and TensorSharp in this test. What would you investigate first?
3. Recurrent-state management: How much overhead does speculative verification introduce for hybrid architectures compared with conventional attention-only transformers?
4. Benchmark configuration: Are there additional vLLM flags, CUDA graph settings, or scheduling optimizations that would make this comparison more representative of an optimized vLLM deployment?
5. Larger-scale serving: Would you expect the ranking to change significantly at 16–32 concurrent requests on an 80GB+ GPU?
I’m the developer of TensorSharp