[Bugfix][Metrics] Do not log a 0.0% prefix cache hit rate before any query (#54990)

Signed-off-by: Michele Campi <215741962+MicheleCampi@users.noreply.github.com>

Michele Campi committed Sep 17, 2026 at 20:19 UTC 6a344d8c8595fc7ca32a633b6f146d36dd227430
2 files changed +20 -7
tests/v1/core/test_kv_cache_utils.py
+16
@@ -1068,6 +1068,22 @@ def _stats(requests: int, queries: int, hits: int) -> PrefixCacheStats:
1068 return PrefixCacheStats(requests=requests, queries=queries, hits=hits)
1069
1070
1071 +def test_metrics_empty_distinguishes_no_queries_from_no_hits():
1072 + """`hit_rate` alone cannot tell the two apart; `empty` can.
1073 +
1074 + Both an unobserved window and a genuine all-miss window report a hit
1075 + rate of 0.0, so anything surfacing that number to a human has to check
1076 + `empty` first - which is what the prefix-cache log line does.
1077 + """
1078 + metrics = CachingMetrics(max_recent_requests=5)
1079 + assert metrics.empty
1080 + assert metrics.hit_rate == 0.0
1081 +
1082 + metrics.observe(_stats(1, 20, 0))
1083 + assert not metrics.empty
1084 + assert metrics.hit_rate == 0.0
1085 +
1086 +
1087 def test_metrics():
1088 """Test the prefix caching metrics."""
1089 metrics = CachingMetrics(max_recent_requests=5)
vllm/v1/metrics/loggers.py
+4 -7
@@ -296,19 +296,16 @@ class LoggingStatLogger(StatLoggerBase):
296 log_parts.append("Preemptions: %d")
297 log_args.append(self.num_preemptions)
298
299 - log_parts.extend(
300 - [
301 - "%s KV cache usage: %.1f%%",
302 - "Prefix cache hit rate: %.1f%%",
303 - ]
304 - )
299 + log_parts.append("%s KV cache usage: %.1f%%")
300 log_args.extend(
301 [
302 self.kv_cache_device,
303 self.last_scheduler_stats.kv_cache_usage * 100,
309 - self.prefix_caching_metrics.hit_rate * 100,
304 ]
305 )
306 + if not self.prefix_caching_metrics.empty:
307 + log_parts.append("Prefix cache hit rate: %.1f%%")
308 + log_args.append(self.prefix_caching_metrics.hit_rate * 100)
309
310 if envs.VLLM_COMPUTE_NANS_IN_LOGITS:
311 log_parts.append("Corrupted: %d reqs")