Production Metrics

vLLM exposes a number of metrics that can be used to monitor the health of the system. These metrics are exposed via the /metrics endpoint on the vLLM OpenAI compatible API server.

You can start the server using Python, or using Docker:

  1. vllm serve unsloth/Llama-3.2-1B-Instruct

Then query the endpoint to get the latest metrics from the server:

  1. $ curl http://0.0.0.0:8000/metrics
  2. # HELP vllm:iteration_tokens_total Histogram of number of tokens per engine_step.
  3. # TYPE vllm:iteration_tokens_total histogram
  4. vllm:iteration_tokens_total_sum{model_name="unsloth/Llama-3.2-1B-Instruct"} 0.0
  5. vllm:iteration_tokens_total_bucket{le="1.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  6. vllm:iteration_tokens_total_bucket{le="8.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  7. vllm:iteration_tokens_total_bucket{le="16.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  8. vllm:iteration_tokens_total_bucket{le="32.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  9. vllm:iteration_tokens_total_bucket{le="64.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  10. vllm:iteration_tokens_total_bucket{le="128.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  11. vllm:iteration_tokens_total_bucket{le="256.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  12. vllm:iteration_tokens_total_bucket{le="512.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
  13. ...

The following metrics are exposed:

  1. class Metrics:
  2. """
  3. vLLM uses a multiprocessing-based frontend for the OpenAI server.
  4. This means that we need to run prometheus_client in multiprocessing mode
  5. See https://prometheus.github.io/client_python/multiprocess/ for more
  6. details on limitations.
  7. """
  8. labelname_finish_reason = "finished_reason"
  9. labelname_waiting_lora_adapters = "waiting_lora_adapters"
  10. labelname_running_lora_adapters = "running_lora_adapters"
  11. labelname_max_lora = "max_lora"
  12. _gauge_cls = prometheus_client.Gauge
  13. _counter_cls = prometheus_client.Counter
  14. _histogram_cls = prometheus_client.Histogram
  15. def __init__(self, labelnames: List[str], vllm_config: VllmConfig):
  16. # Unregister any existing vLLM collectors (for CI/CD)
  17. self._unregister_vllm_metrics()
  18. max_model_len = vllm_config.model_config.max_model_len
  19. # System stats
  20. # Scheduler State
  21. self.gauge_scheduler_running = self._gauge_cls(
  22. name="vllm:num_requests_running",
  23. documentation="Number of requests currently running on GPU.",
  24. labelnames=labelnames,
  25. multiprocess_mode="sum")
  26. self.gauge_scheduler_waiting = self._gauge_cls(
  27. name="vllm:num_requests_waiting",
  28. documentation="Number of requests waiting to be processed.",
  29. labelnames=labelnames,
  30. multiprocess_mode="sum")
  31. self.gauge_lora_info = self._gauge_cls(
  32. name="vllm:lora_requests_info",
  33. documentation="Running stats on lora requests.",
  34. labelnames=[
  35. self.labelname_running_lora_adapters,
  36. self.labelname_max_lora,
  37. self.labelname_waiting_lora_adapters,
  38. ],
  39. multiprocess_mode="livemostrecent",
  40. )
  41. self.gauge_scheduler_swapped = self._gauge_cls(
  42. name="vllm:num_requests_swapped",
  43. documentation="Number of requests swapped to CPU.",
  44. labelnames=labelnames,
  45. multiprocess_mode="sum")
  46. # KV Cache Usage in %
  47. self.gauge_gpu_cache_usage = self._gauge_cls(
  48. name="vllm:gpu_cache_usage_perc",
  49. documentation="GPU KV-cache usage. 1 means 100 percent usage.",
  50. labelnames=labelnames,
  51. multiprocess_mode="sum")
  52. self.gauge_cpu_cache_usage = self._gauge_cls(
  53. name="vllm:cpu_cache_usage_perc",
  54. documentation="CPU KV-cache usage. 1 means 100 percent usage.",
  55. labelnames=labelnames,
  56. multiprocess_mode="sum")
  57. # Prefix caching block hit rate
  58. self.gauge_cpu_prefix_cache_hit_rate = self._gauge_cls(
  59. name="vllm:cpu_prefix_cache_hit_rate",
  60. documentation="CPU prefix cache block hit rate.",
  61. labelnames=labelnames,
  62. multiprocess_mode="sum")
  63. self.gauge_gpu_prefix_cache_hit_rate = self._gauge_cls(
  64. name="vllm:gpu_prefix_cache_hit_rate",
  65. documentation="GPU prefix cache block hit rate.",
  66. labelnames=labelnames,
  67. multiprocess_mode="sum")
  68. # Iteration stats
  69. self.counter_num_preemption = self._counter_cls(
  70. name="vllm:num_preemptions_total",
  71. documentation="Cumulative number of preemption from the engine.",
  72. labelnames=labelnames)
  73. self.counter_prompt_tokens = self._counter_cls(
  74. name="vllm:prompt_tokens_total",
  75. documentation="Number of prefill tokens processed.",
  76. labelnames=labelnames)
  77. self.counter_generation_tokens = self._counter_cls(
  78. name="vllm:generation_tokens_total",
  79. documentation="Number of generation tokens processed.",
  80. labelnames=labelnames)
  81. self.counter_tokens = self._counter_cls(
  82. name="vllm:tokens_total",
  83. documentation="Number of prefill plus generation tokens processed.",
  84. labelnames=labelnames)
  85. buckets = [1, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8096]
  86. if not vllm_config.model_config.enforce_eager:
  87. buckets = vllm_config.compilation_config.\
  88. cudagraph_capture_sizes.copy()
  89. buckets.sort()
  90. self.histogram_iteration_tokens = self._histogram_cls(
  91. name="vllm:iteration_tokens_total",
  92. documentation="Histogram of number of tokens per engine_step.",
  93. labelnames=labelnames,
  94. buckets=buckets)
  95. self.histogram_time_to_first_token = self._histogram_cls(
  96. name="vllm:time_to_first_token_seconds",
  97. documentation="Histogram of time to first token in seconds.",
  98. labelnames=labelnames,
  99. buckets=[
  100. 0.001, 0.005, 0.01, 0.02, 0.04, 0.06, 0.08, 0.1, 0.25, 0.5,
  101. 0.75, 1.0, 2.5, 5.0, 7.5, 10.0
  102. ])
  103. self.histogram_time_per_output_token = self._histogram_cls(
  104. name="vllm:time_per_output_token_seconds",
  105. documentation="Histogram of time per output token in seconds.",
  106. labelnames=labelnames,
  107. buckets=[
  108. 0.01, 0.025, 0.05, 0.075, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.75,
  109. 1.0, 2.5
  110. ])
  111. # Request stats
  112. # Latency
  113. request_latency_buckets = [
  114. 0.3, 0.5, 0.8, 1.0, 1.5, 2.0, 2.5, 5.0, 10.0, 15.0, 20.0, 30.0,
  115. 40.0, 50.0, 60.0
  116. ]
  117. self.histogram_e2e_time_request = self._histogram_cls(
  118. name="vllm:e2e_request_latency_seconds",
  119. documentation="Histogram of end to end request latency in seconds.",
  120. labelnames=labelnames,
  121. buckets=request_latency_buckets)
  122. self.histogram_queue_time_request = self._histogram_cls(
  123. name="vllm:request_queue_time_seconds",
  124. documentation=
  125. "Histogram of time spent in WAITING phase for request.",
  126. labelnames=labelnames,
  127. buckets=request_latency_buckets)
  128. self.histogram_inference_time_request = self._histogram_cls(
  129. name="vllm:request_inference_time_seconds",
  130. documentation=
  131. "Histogram of time spent in RUNNING phase for request.",
  132. labelnames=labelnames,
  133. buckets=request_latency_buckets)
  134. self.histogram_prefill_time_request = self._histogram_cls(
  135. name="vllm:request_prefill_time_seconds",
  136. documentation=
  137. "Histogram of time spent in PREFILL phase for request.",
  138. labelnames=labelnames,
  139. buckets=request_latency_buckets)
  140. self.histogram_decode_time_request = self._histogram_cls(
  141. name="vllm:request_decode_time_seconds",
  142. documentation=
  143. "Histogram of time spent in DECODE phase for request.",
  144. labelnames=labelnames,
  145. buckets=request_latency_buckets)
  146. self.histogram_time_in_queue_request = self._histogram_cls(
  147. name="vllm:time_in_queue_requests",
  148. documentation=
  149. "Histogram of time the request spent in the queue in seconds.",
  150. labelnames=labelnames,
  151. buckets=request_latency_buckets)
  152. self.histogram_model_forward_time_request = self._histogram_cls(
  153. name="vllm:model_forward_time_milliseconds",
  154. documentation=
  155. "Histogram of time spent in the model forward pass in ms.",
  156. labelnames=labelnames,
  157. buckets=build_1_2_3_5_8_buckets(3000))
  158. self.histogram_model_execute_time_request = self._histogram_cls(
  159. name="vllm:model_execute_time_milliseconds",
  160. documentation=
  161. "Histogram of time spent in the model execute function in ms.",
  162. labelnames=labelnames,
  163. buckets=build_1_2_3_5_8_buckets(3000))
  164. # Metadata
  165. self.histogram_num_prompt_tokens_request = self._histogram_cls(
  166. name="vllm:request_prompt_tokens",
  167. documentation="Number of prefill tokens processed.",
  168. labelnames=labelnames,
  169. buckets=build_1_2_5_buckets(max_model_len),
  170. )
  171. self.histogram_num_generation_tokens_request = \
  172. self._histogram_cls(
  173. name="vllm:request_generation_tokens",
  174. documentation="Number of generation tokens processed.",
  175. labelnames=labelnames,
  176. buckets=build_1_2_5_buckets(max_model_len),
  177. )
  178. self.histogram_max_num_generation_tokens_request = self._histogram_cls(
  179. name="vllm:request_max_num_generation_tokens",
  180. documentation=
  181. "Histogram of maximum number of requested generation tokens.",
  182. labelnames=labelnames,
  183. buckets=build_1_2_5_buckets(max_model_len))
  184. self.histogram_n_request = self._histogram_cls(
  185. name="vllm:request_params_n",
  186. documentation="Histogram of the n request parameter.",
  187. labelnames=labelnames,
  188. buckets=[1, 2, 5, 10, 20],
  189. )
  190. self.histogram_max_tokens_request = self._histogram_cls(
  191. name="vllm:request_params_max_tokens",
  192. documentation="Histogram of the max_tokens request parameter.",
  193. labelnames=labelnames,
  194. buckets=build_1_2_5_buckets(max_model_len),
  195. )
  196. self.counter_request_success = self._counter_cls(
  197. name="vllm:request_success_total",
  198. documentation="Count of successfully processed requests.",
  199. labelnames=labelnames + [Metrics.labelname_finish_reason])
  200. # Speculatie decoding stats
  201. self.gauge_spec_decode_draft_acceptance_rate = self._gauge_cls(
  202. name="vllm:spec_decode_draft_acceptance_rate",
  203. documentation="Speulative token acceptance rate.",
  204. labelnames=labelnames,
  205. multiprocess_mode="sum")
  206. self.gauge_spec_decode_efficiency = self._gauge_cls(
  207. name="vllm:spec_decode_efficiency",
  208. documentation="Speculative decoding system efficiency.",
  209. labelnames=labelnames,
  210. multiprocess_mode="sum")
  211. self.counter_spec_decode_num_accepted_tokens = (self._counter_cls(
  212. name="vllm:spec_decode_num_accepted_tokens_total",
  213. documentation="Number of accepted tokens.",
  214. labelnames=labelnames))
  215. self.counter_spec_decode_num_draft_tokens = self._counter_cls(
  216. name="vllm:spec_decode_num_draft_tokens_total",
  217. documentation="Number of draft tokens.",
  218. labelnames=labelnames)
  219. self.counter_spec_decode_num_emitted_tokens = (self._counter_cls(
  220. name="vllm:spec_decode_num_emitted_tokens_total",
  221. documentation="Number of emitted tokens.",
  222. labelnames=labelnames))