TT Lab
Blog

한국어 English 日本語 中文

Get started
Blog

Blog

Re-measuring continuous batching, chunked prefill, and prefix caching with repeated measurements

Status: Draft (2026-10-27), Measured. Measured on 2026-10-27 using a single 8GB laptop GPU (Ada generation), vLLM 0.31.0, and Qwen3-Reranker-0.6B. Since the principles of the same three features and the initial measurements of the 1.7B model are covered in "Dissecting the LLM KV Cache" Part 2 and "Preparing Toss ML/AI Infra" Part 14, this post only covers what those articles did not (repeated measurements, disabled baseline, turning off chunks, and cache_salt). Added 2026-10-27. The results of re-running the same test with vLLM 0.32.0 on the same day have been added to Section 6-1. The 0.31.0 figures remain unchanged. Writing Rule: Measured data is the default; unmeasured items are marked as "Unmeasured", and unverified items as "Unverified".

Table of Contents

1. Why Re-measure?

The principles of PagedAttention, continuous batching, and prefix caching within the serving engine's KV cache, along with the initial values measured using a 1.7B model, were covered in Direct Measurement of vLLM with a Smaller Model. Those measurements had three gaps:

  1. Each condition was measured only once, so the variance was unknown.
  2. Continuous batching could not be disabled, making it impossible to see "how it performs without it".
  3. Cases with chunking completely disabled and isolation when multiple users share the cache (cache_salt) were not examined.

This time, all conditions were repeated three to four times, and the first batch was separated as a warm-up and excluded from the median. A server with the features disabled was launched immediately afterward on the same day in the same pod.

2. Environment and Method

3. Continuous Batching: Disabling It Drops Throughput to 1/10

There is no option to directly disable continuous batching. Instead, setting --max-num-seqs 1 to process only one request per step turns it into a "server processing requests one by one". Requests with 256 input tokens and 128 output tokens were sent at 2c requests for a concurrency level c.

Server Concurrent Requests Throughput (tok/s) TTFT Median ITL Median ITL p99
One at a time (--max-num-seqs 1) 1 174.4 18.9ms 5.6ms 6.2ms
One at a time 16 174.6 11,008ms 5.6ms 6.5ms
Default 1 174.2 18.8ms 5.6ms 6.7ms
Default 4 593.8 50.7ms 6.4ms 7.5ms
Default 16 1,683.1 131.0ms 8.2ms 9.4ms
Default 64 2,899.3 272.2ms 16.6ms 90.6ms

The throughputs of the three batches were within 0.3% of each other (concurrency 16 default: 1,681.3, 1,683.1, 1,685.4).

4. chunked prefill: Decode Pause Time is Proportional to Chunk Size

While a single decode request (900 tokens) was running, an input of approximately 3,700 tokens was interleaved five times, and the maximum decode token interval within the interleaved sections was measured.

Server Max Input Tokens per Step Max ITL in Interleaved Section (5 runs) Other ITL Medians Interleaved Input TTFT Median
--max-num-batched-tokens 512 512 35.6ms(35.5, 35.5, 35.6, 35.6, 35.6) 5.7ms 232.0ms
Default 2,048 109.8ms(108.3, 108.6, 109.1, 109.2, 109.8) 5.7ms 216.2ms
--no-enable-chunked-prefill --max-num-batched-tokens 4096 4,096 (No chunk) 197.6ms(191.8, 195.7, 197.1, 197.4, 197.6) 5.8ms 214.1ms

On this GPU, the prefill speed is around 174.7ms for 3,200 tokens, or roughly 18,000 tokens per second. Calculations showing that a single 2,048-token chunk takes about 111ms and the entire 3,700 tokens take about 200ms match the maximum ITL in the table. The five values cluster within around 1ms, which is not a coincidence.

The shape matches previous measurements taken with the 1.7B model (512 tokens: 69ms, 2,048 tokens: 227ms), scaled down in magnitude according to the model's computational load.

5. Prefix Caching: 18.9ms Even with Repetition

We appended 32 different words per request to a common prefix of 3,000 words (about 3,200 tokens). Five batches were run by changing the prefix.

Server Cold First Request TTFT (5 prefixes) Warm Request TTFT (20 runs)
Default (Prefix Caching Enabled) Median 174.7ms (174.6~175.3) Median 18.9ms(Min 18.0, Max 19.9)
--no-enable-prefix-caching Median 173.9ms, server first request only 236.0ms Median 173.8ms (Min 173.0, Max 178.2)

Warm requests only compute the last block and tail of the 3,200 tokens, resulting in a 9.2x speedup. The very first request on the server with prefix caching disabled took 236ms, which was 60ms slower than other cold requests; this represents the warm-up overhead after launching the server. This is why the first value must be separated in measurements.

Keep in mind that caching operates at the block level. Since vLLM hashes and stores only full blocks (default 16 tokens), if the common part cuts off at a block boundary, the final fragment is recomputed. Hashing defaults to sha256 as of 0.11 and can be changed to --prefix-caching-hash-algo .

6. cache_salt: Preventing Tenants from Sharing Caches with Identical Prefixes

Prefix caching has a security issue. By sending the same beginning part as a document sent by another user, if the first token is fast, one can infer that "someone has already viewed this document." This is a timing attack leaking information via elapsed time. vLLM allows attaching cache_salt to requests to mix that value into the first block's hash, ensuring caches are shared only among identical salts.

--enable-prompt-tokens-details Using

to display the number of cached tokens in the response, we sent the same 3,000-word prefix across five batches with varying salts.

Sequence cache_salt Cached Tokens (Response cached_tokens) TTFT Median (2nd to 5th batches)
1 tenant-a 0 173.9ms
2 tenant-a 3,184 or 3,200 17.9ms
3 tenant-b 0 173.7ms
4 tenant-b 3,184 or 3,200 18.3ms
5 None 0 173.9ms

cached_tokens appears in responses only when the server is launched with --enable-prompt-tokens-details . If disabled, this field is empty, requiring cache hits to be inferred solely from timing. Overall server hits can be checked via /metrics 's vllm:prefix_cache_hits_total and vllm:prefix_cache_queries_total .

6-1. Re-measurement on 2026-10-27: Are Results Identical in 0.32.0?

Re-measured in the vLLM 0.32.0 official container using the same GPU, same reranker model, and same client ("2026-10-27 0.31.0 Measurement → 0.32.0 Re-measurement").

Item 0.31.0 0.32.0
Throughput, Concurrency 1 174.2 tok/s 174.2 tok/s
Throughput, Concurrency 16 (Default) 1,683.1 tok/s 1,683.6 tok/s
Throughput, Concurrent 16 (one at a time) 174.6 tok/s 174.3 tok/s
Throughput, Concurrent 64 2,899.3 tok/s 2,899.7 tok/s
Max decode pause when 3,700 tokens are interleaved (default chunk) 109.8ms 108.2ms
3,200-token prefix first token (cold → warm) 174.7 → 18.9ms 175.2 → 18.9ms

All values were identical within 1.5%. The major changes in the 0.32.0 release notes (such as expanding Model Runner V2, removing cascade attention, max_tokens not pre-stripping from the context) did not change the numbers under this small model's baseline load. The conversational Qwen3-0.6B (same architecture) was also identical at 174.1, 1,678.0, and 2,898.7 tok/s at concurrency 1, 16, and 64.

7. Operational Takeaways

8. Unverified Items

References

Sign in to like

Comments

No comments yet.

Sign in to leave a comment