Skip to content
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
7d66ba9
feat: Add metrics based on priority-based scheduling.
Jan 13, 2026
8676199
[fix] Incorrect parameter naming
Jan 13, 2026
999d4df
fix lint
huangtingwei9988 Jan 15, 2026
e1ef8c3
Merge branch 'main' into priority_metrics_dev
huangtingwei9988 Jan 15, 2026
bfad739
Merge branch 'main' into priority_metrics_dev
huangtingwei9988 Jan 20, 2026
a582950
[fix] Logic issue in the num_running_reqs_by_priority tracking record.
Jan 22, 2026
f9b834a
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Jan 22, 2026
53785e5
Merge branch 'main' into priority_metrics_dev
huangtingwei9988 Jan 26, 2026
bfe854a
[fix] Optimize priority scheduling logic.
Feb 4, 2026
311721f
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 4, 2026
934758c
[fix] Optimize priority scheduling logic.
Feb 4, 2026
e5dc82b
[fix] Code formatting issues
Feb 8, 2026
38c8494
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 8, 2026
6922329
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 11, 2026
16eb3cc
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 12, 2026
a5f2c62
Merge branch 'main' into priority_metrics_dev
JustinTong0323 Feb 12, 2026
683b39b
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 21, 2026
347ade2
[fix] Optimize the logic of the log_prefill_stats interface
Feb 22, 2026
046b3b8
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 22, 2026
168a589
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 23, 2026
eb75cca
Merge branch 'main' into priority_metrics_dev
zhuxinjie-nz Feb 23, 2026
878ddaa
[PD-Disagg] Support query dp rank from bootstrap server. (#19168)
hnyls2002 Feb 23, 2026
5e1202e
[CI] fix the teardown output of disaggregation test (#19193)
hnyls2002 Feb 23, 2026
c9a5157
add new ci user (#19133)
narutolhy Feb 23, 2026
96516d5
[CI] Tiny enhance the dp attention load blance benchmark (#19194)
hnyls2002 Feb 23, 2026
2fada5b
[PD-Disagg] Unify prefill info data transition flow, all with `Prefil…
hnyls2002 Feb 24, 2026
3c5de3f
fix: patch docker image fixes (#19100)
dougyster Feb 24, 2026
55c7122
Whisper model support & `/v1/audio/transcriptions` endpoint & benchma…
JustinTong0323 Feb 24, 2026
95eb0c7
fix: add missing blank line after docstring in serving_transcription.…
Kangyan-Zhou Feb 24, 2026
1191c05
[PD-Disagg] Deduplicate common KVManager methods into CommonKVManager…
hnyls2002 Feb 24, 2026
c30d115
fix(docker): migrate ROCm Dockerfiles from setuptools-rust to maturin…
slin1237 Feb 24, 2026
11dc631
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 24, 2026
6078c7c
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 24, 2026
06813e7
[fix] Optimize the preempt logic
Feb 24, 2026
5d8dd95
[fix] Optimize the preemption logic
Feb 24, 2026
b5c0a8d
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 25, 2026
bf7cdf5
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Feb 25, 2026
cc90291
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Mar 1, 2026
1f8cebe
Merge remote-tracking branch 'origin/main' into priority_metrics_dev
Mar 4, 2026
6f3e93d
fix wrong server args naming
hnyls2002 Mar 4, 2026
81ccd78
rename confusing name
hnyls2002 Mar 4, 2026
8491531
fix wrong comments
hnyls2002 Mar 4, 2026
56e9b44
simplify the code
hnyls2002 Mar 4, 2026
0724cbe
use QueueCount
hnyls2002 Mar 4, 2026
cdbaf59
fix import error
hnyls2002 Mar 4, 2026
f9d66ad
add comments
hnyls2002 Mar 4, 2026
b14152c
fix dict copy & label type
hnyls2002 Mar 4, 2026
75251d9
Add unit test for priority scheduling metrics
hnyls2002 Mar 4, 2026
e7257b7
fix future
hnyls2002 Mar 4, 2026
6f957cb
fix
hnyls2002 Mar 4, 2026
4504bcf
tiny fix
hnyls2002 Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion python/sglang/srt/managers/scheduler.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to make one or two helper functions that calculate per-priority request counts in scheduler.py and scheduler_metrics_mixin.py and consolidate the usage?

Perhaps that a) takes in the list of requests and return xxx_reqs_by_priority dictionary or b) additionally taking the dictionary and updating in place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much — I’ll work on fixing these issues.

Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,10 @@ def init_schedule_policy(self):
),
)
# Enable preemption for priority scheduling.
self.try_preemption = self.enable_priority_scheduling
self.try_preemption = (
self.enable_priority_scheduling and not self.server_args.disable_preemption
)

self.init_new_token_ratio = min(
envs.SGLANG_INIT_NEW_TOKEN_RATIO.get()
* self.server_args.schedule_conservativeness,
Expand Down Expand Up @@ -2004,6 +2007,7 @@ def _get_new_batch_prefill_raw(
return None

running_bs = len(self.running_batch.reqs)

Comment thread
stmatengss marked this conversation as resolved.
# Ignore the check if self.chunked_req is not None.
# In the non-PP case, when self.chunked_req is not None, num_allocatable_reqs should always be greater than 0,
# as the space for the chunked requests has just been released.
Expand Down Expand Up @@ -2174,12 +2178,16 @@ def _get_new_batch_prefill_raw(
new_batch.prepare_for_extend()

# Record prefill stats for logging after forward
num_running_reqs_by_priority = self._count_reqs_by_priority(
self.running_batch.reqs
)
new_batch.prefill_stats = PrefillStats(
log_input_tokens=adder.log_input_tokens,
log_hit_tokens=adder.log_hit_tokens,
new_token_ratio=adder.new_token_ratio,
running_bs=len(self.running_batch.reqs),
num_new_seqs=len(can_run_list),
num_running_reqs_by_priority=num_running_reqs_by_priority,
)

# Mixed-style chunked prefill
Expand Down
24 changes: 24 additions & 0 deletions python/sglang/srt/managers/scheduler_runtime_checker_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,25 +303,49 @@ def check_memory(self: Scheduler):
num_used, token_usage, _, _ = self._get_token_info()
num_running_reqs = len(self.running_batch.reqs)
self.stats.num_running_reqs = num_running_reqs
self.stats.num_running_reqs_by_priority = self._count_reqs_by_priority(
self.running_batch.reqs
)
self.stats.num_used_tokens = num_used
self.stats.token_usage = round(token_usage, 2)
self.stats.gen_throughput = 0
self.stats.num_queue_reqs = len(self.waiting_queue)
self.stats.num_queue_reqs_by_priority = self._count_reqs_by_priority(
self.waiting_queue
)
self.stats.num_grammar_queue_reqs = len(self.grammar_manager)
if self.disaggregation_mode == DisaggregationMode.PREFILL:
self.stats.num_prefill_prealloc_queue_reqs = len(
self.disagg_prefill_bootstrap_queue.queue
)
self.stats.num_prefill_prealloc_queue_reqs_by_priority = (
self._count_reqs_by_priority(
self.disagg_prefill_bootstrap_queue.queue
)
)
self.stats.num_prefill_inflight_queue_reqs = len(
self.disagg_prefill_inflight_queue
)
self.stats.num_prefill_inflight_queue_reqs_by_priority = (
self._count_reqs_by_priority(self.disagg_prefill_inflight_queue)
)
if self.disaggregation_mode == DisaggregationMode.DECODE:
self.stats.num_decode_prealloc_queue_reqs = len(
self.disagg_decode_prealloc_queue.queue
)
self.stats.num_decode_prealloc_queue_reqs_by_priority = (
self._count_reqs_by_priority(
self.disagg_decode_prealloc_queue.queue
)
)
self.stats.num_decode_transfer_queue_reqs = len(
self.disagg_decode_transfer_queue.queue
)
self.stats.num_decode_transfer_queue_reqs_by_priority = (
self._count_reqs_by_priority(
self.disagg_decode_transfer_queue.queue
)
)
self.metrics_collector.log_stats(self.stats)
self._publish_kv_events()

Expand Down
18 changes: 18 additions & 0 deletions python/sglang/srt/managers/tokenizer_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ def init_model_config(self):
self.context_len = self.model_config.context_len
self.image_token_id = self.model_config.image_token_id
self.max_req_input_len = None # Will be set later in engine.py
self.enable_priority_scheduling = server_args.enable_priority_scheduling
self.default_priority_value = server_args.default_priority_value
speculative_algorithm = SpeculativeAlgorithm.from_string(
server_args.speculative_algorithm
)
Expand Down Expand Up @@ -421,6 +423,8 @@ def init_metric_collector_watchdog(self):
"model_name": self.server_args.served_model_name,
# TODO: Add lora name/path in the future,
}
if self.enable_priority_scheduling:
labels["priority"] = ""
if self.server_args.tokenizer_metrics_allowed_custom_labels:
for label in self.server_args.tokenizer_metrics_allowed_custom_labels:
labels[label] = ""
Expand Down Expand Up @@ -482,6 +486,7 @@ async def generate_request(

# Normalize the request
obj.normalize_batch_and_arguments()
self._set_default_priority(obj)
self._validate_rid(obj)

if isinstance(obj, GenerateReqInput) and obj.routed_dp_rank is not None:
Expand Down Expand Up @@ -1899,6 +1904,10 @@ def collect_metrics(self, state: ReqState, recv_obj: BatchStrOutput, i: int):
if custom_labels
else self.metrics_collector.labels
)
if self.enable_priority_scheduling:
priority = getattr(state.obj, "priority", None)
if priority is not None:
labels["priority"] = priority
if (
state.time_stats.first_token_time == 0.0
and self.disaggregation_mode != DisaggregationMode.PREFILL
Expand Down Expand Up @@ -2367,6 +2376,15 @@ def convert_to_span_attrs(

return span_attrs

def _set_default_priority(self, obj: Union[GenerateReqInput, EmbeddingReqInput]):
"""Set the default priority value."""
if (
self.enable_priority_scheduling
and obj.priority is None
and self.default_priority_value is not None
):
obj.priority = self.default_priority_value


class ServerStatus(Enum):
Up = "Up"
Expand Down
53 changes: 43 additions & 10 deletions python/sglang/srt/observability/metrics_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import os
import time
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Set, Union

from sglang.srt.environ import envs
from sglang.srt.model_executor.forward_batch_info import ForwardMode
Expand All @@ -29,7 +29,6 @@

SGLANG_TEST_REQUEST_TIME_STATS = get_bool_env_var("SGLANG_TEST_REQUEST_TIME_STATS")


logger = logging.getLogger(__name__)


Expand All @@ -51,6 +50,7 @@ def get_histogram_conf_from_env(env_var_name: str) -> Optional[List[float]]:
class SchedulerStats:
# Basics
num_running_reqs: int = 0
num_running_reqs_by_priority: Optional[Dict[int, int]] = None
num_used_tokens: int = 0
token_usage: float = 0.0
pending_prealloc_token_usage: float = 0.0
Expand All @@ -59,6 +59,7 @@ class SchedulerStats:
decode_sum_seq_lens: int = 0
gen_throughput: float = 0.0
num_queue_reqs: int = 0
num_queue_reqs_by_priority: Optional[Dict[int, int]] = None
num_grammar_queue_reqs: int = 0
num_running_reqs_offline_batch: int = 0
cache_hit_rate: float = 0.0
Expand All @@ -75,9 +76,13 @@ class SchedulerStats:

# PD disaggregation
num_prefill_prealloc_queue_reqs: int = 0
num_prefill_prealloc_queue_reqs_by_priority: Optional[Dict[int, int]] = None
num_prefill_inflight_queue_reqs: int = 0
num_prefill_inflight_queue_reqs_by_priority: Optional[Dict[int, int]] = None
num_decode_prealloc_queue_reqs: int = 0
num_decode_prealloc_queue_reqs_by_priority: Optional[Dict[int, int]] = None
num_decode_transfer_queue_reqs: int = 0
num_decode_transfer_queue_reqs_by_priority: Optional[Dict[int, int]] = None
kv_transfer_speed_gb_s: float = 0.0
kv_transfer_latency_ms: float = 0.0
kv_transfer_bootstrap_ms: float = 0.0
Expand Down Expand Up @@ -158,6 +163,7 @@ def __init__(
self.enable_lora = enable_lora
self.enable_hierarchical_cache = enable_hierarchical_cache
self.last_log_time = time.perf_counter()
self._known_priorities: Set[int] = set()

self.num_running_reqs = Gauge(
name="sglang:num_running_reqs",
Expand Down Expand Up @@ -733,9 +739,22 @@ def __init__(
multiprocess_mode="mostrecent",
)

def _log_gauge(self, gauge, data: Union[int, float]) -> None:
def _log_gauge(
self,
gauge,
data: Union[int, float],
by_priority_dict: Optional[Dict[int, int]] = None,
) -> None:
# Convenience function for logging to gauge.
gauge.labels(**self.labels).set(data)
if by_priority_dict is not None:
self._known_priorities.update(by_priority_dict.keys())
for priority in self._known_priorities:
value = by_priority_dict.get(priority, 0)
labels = dict(self.labels)
labels["priority"] = str(priority)
gauge.labels(**labels).set(value)
else:
gauge.labels(**self.labels).set(data)

def _log_histogram(self, histogram, data: Union[int, float]) -> None:
histogram.labels(**self.labels).observe(data)
Expand Down Expand Up @@ -844,7 +863,11 @@ def increment_gpu_execution_seconds(
).inc(t)

def log_stats(self, stats: SchedulerStats) -> None:
self._log_gauge(self.num_running_reqs, stats.num_running_reqs)
self._log_gauge(
self.num_running_reqs,
stats.num_running_reqs,
stats.num_running_reqs_by_priority,
)
self._log_gauge(self.num_used_tokens, stats.num_used_tokens)
self._log_gauge(self.token_usage, stats.token_usage)
self._log_gauge(
Expand All @@ -854,7 +877,9 @@ def log_stats(self, stats: SchedulerStats) -> None:
self._log_gauge(self.mamba_usage, stats.mamba_usage)
self._log_gauge(self.decode_sum_seq_lens, stats.decode_sum_seq_lens)
self._log_gauge(self.gen_throughput, stats.gen_throughput)
self._log_gauge(self.num_queue_reqs, stats.num_queue_reqs)
self._log_gauge(
self.num_queue_reqs, stats.num_queue_reqs, stats.num_queue_reqs_by_priority
)
self._log_gauge(self.num_grammar_queue_reqs, stats.num_grammar_queue_reqs)
self._log_gauge(
self.num_running_reqs_offline_batch, stats.num_running_reqs_offline_batch
Expand All @@ -869,16 +894,24 @@ def log_stats(self, stats: SchedulerStats) -> None:

# PD disaggregation
self._log_gauge(
self.num_prefill_prealloc_queue_reqs, stats.num_prefill_prealloc_queue_reqs
self.num_prefill_prealloc_queue_reqs,
stats.num_prefill_prealloc_queue_reqs,
stats.num_prefill_prealloc_queue_reqs_by_priority,
)
self._log_gauge(
self.num_prefill_inflight_queue_reqs, stats.num_prefill_inflight_queue_reqs
self.num_prefill_inflight_queue_reqs,
stats.num_prefill_inflight_queue_reqs,
stats.num_prefill_inflight_queue_reqs_by_priority,
)
self._log_gauge(
self.num_decode_prealloc_queue_reqs, stats.num_decode_prealloc_queue_reqs
self.num_decode_prealloc_queue_reqs,
stats.num_decode_prealloc_queue_reqs,
stats.num_decode_prealloc_queue_reqs_by_priority,
)
self._log_gauge(
self.num_decode_transfer_queue_reqs, stats.num_decode_transfer_queue_reqs
self.num_decode_transfer_queue_reqs,
stats.num_decode_transfer_queue_reqs,
stats.num_decode_transfer_queue_reqs_by_priority,
)
self._log_gauge(self.kv_transfer_speed_gb_s, stats.kv_transfer_speed_gb_s)
self._log_gauge(self.kv_transfer_latency_ms, stats.kv_transfer_latency_ms)
Expand Down
Loading
Loading