/ sgl-project / sglang
Key Takeaways
- GPT-5.6 Terra leads with 46 of 59 tasks resolved while costing $0.61 per test, taking 162 seconds, and using 0.76M tokens.
- GPT-5.6 Luna, GLM 5.2 (Fireworks), GPT 5.5, and Claude Fable 5 form the next tier at 45 of 59.
- GPT-5.6 Terra and GLM 5.2 (Fireworks) resolve 51 of 59 tasks together, making GLM the most complementary partner to the winner.
Cost / Test vs. Accuracy
GPT-5.6 Terra combines the best score with a $0.61 cost per test; GPT-5.6 Luna is one task behind at $0.58.
Latency vs. Accuracy
GPT-5.6 Terra is effectively the fastest model at 162 seconds and resolves three more tasks than Gemini 3.1 Pro Preview (02/26), which finishes in 160 seconds.
Average token use / test
Tasks with failures
| Model | 095a817 | 1967b9e | 19c53c4 | 238448f | 24a8944 | 26cb0fc | 2d00e20 | 41e0b4b | 43241b7 | 44e3dd2 | 52a88fb | 5609f8e | 5e7eed4 | 72c4ed1 | 77d23a7 | 7a03d30 | 8432eaf | 861d97d | 947a14d | 9d147fd | a5a71c6 | a5c0b94 | b6cc897 | c9b1740 | dc078dd | e77d95c | e78051a | ec6a316 | f2c875d |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| GPT-5.6 Terra | |||||||||||||||||||||||||||||
| GPT-5.6 Luna | |||||||||||||||||||||||||||||
| GLM 5.2 | |||||||||||||||||||||||||||||
| GPT-5.5 | |||||||||||||||||||||||||||||
| Claude Fable 5 | |||||||||||||||||||||||||||||
| GPT-5.6 Sol | |||||||||||||||||||||||||||||
| Muse Spark 1.1 | |||||||||||||||||||||||||||||
| Gemini 3.1 Pro Preview | |||||||||||||||||||||||||||||
| Grok 4.5 | |||||||||||||||||||||||||||||
| Claude Opus 4.8 | |||||||||||||||||||||||||||||
| Kimi K3 | |||||||||||||||||||||||||||||
| Gemini 3.5 Flash | |||||||||||||||||||||||||||||
| Claude Sonnet 5 | |||||||||||||||||||||||||||||
| Claude Opus 4.7 | |||||||||||||||||||||||||||||
| Claude Haiku 4.5 |
Task detail
095a81761244Issue statement
HiCache reports two Prometheus metrics for KV-cache load-back operations: the number of tokens moved from host (CPU) memory back to device (GPU) memory (sglang:load_back_num_tokens) and the time each load-back takes (sglang:load_back_duration_seconds).
Today the duration is measured on the host with time.perf_counter() around the code that enqueues the asynchronous host-to-device copy. Because the copy runs on a separate device stream and completes later, this wall-clock span only covers the time spent submitting the work, not the time the transfer actually takes. The reported duration is therefore misleading and the token counter is updated at enqueue time rather than when the load actually completes.
The load-back duration should instead be measured on the device around the actual copy, and both metrics should be recorded when the load-back operation is confirmed complete (i.e. when its completion event is processed), not when it is submitted.
Requirements:
-
Add a helper in
sglang/srt/managers/cache_controller.pythat creates a pair of device timing events for a load-back operation:- A cached predicate
_timing_events_supported()that returns whether the active device backend'sEventtype acceptsenable_timing=True. It must probe by constructingdevice_module.Event(enable_timing=True)and returnFalse(logging a warning) when that raisesTypeErrororNotImplementedError, andTrueotherwise. The result must be cached so the probe runs at most once, and the cache must be clearable. - A function
make_timing_event_pair()that returns a 3-tuple(start_event, finish_event, timing_enabled). When timing is supported both events are created withenable_timing=True; otherwise they are created with no timing kwargs. The two returned events must be distinct objects, andtiming_enabledmust reflect whether timing is supported.
- A cached predicate
-
Extend the
HiCacheAckrecord with two new fields carrying the completion information for a load-back:num_tokens(defaulting to0) andtiming_enabled(defaulting toFalse). Existing construction ofHiCacheAckwith onlystart_event,finish_event, andnode_idsmust continue to work. -
Record the load-back metrics when completed load acks are processed in
HiRadixCache.loading_check()(rather than at submission time). For each completed ack, and only when a metrics collector is present, always increment the load-back token counter by the ack'snum_tokens. Additionally, when the ack has timing enabled, compute the elapsed device time between its start and finish events (start_event.elapsed_time(finish_event), which returns milliseconds) and observe the load-back duration in seconds. When timing is not enabled, the duration must not be observed and the events' elapsed time must not be queried.
The submission-time time.perf_counter() based duration/token bookkeeping for load-back should be removed so the metrics are only recorded on completion.
Hidden tests
diff --git a/test/registered/unit/mem_cache/test_hicache_load_back_metrics.py b/test/registered/unit/mem_cache/test_hicache_load_back_metrics.pynew file mode 100644index 0000000..a4333b5--- /dev/null+++ b/test/registered/unit/mem_cache/test_hicache_load_back_metrics.py@@ -0,0 +1,152 @@+"""Unit tests for the HiCache load-back duration/token metrics.++These tests exercise the device-event based instrumentation that HiCache uses to+report how long a KV-cache load-back took and how many tokens it moved. They run+on any backend (including CPU-only environments) by using mock device events, so+they do not require a real GPU.+"""++import unittest+from types import SimpleNamespace+from unittest.mock import MagicMock, patch+++class TestMakeTimingEventPair(unittest.TestCase):+ def setUp(self):+ from sglang.srt.managers import cache_controller as cc++ cc._timing_events_supported.cache_clear()+ self.cc = cc++ def tearDown(self):+ self.cc._timing_events_supported.cache_clear()++ def test_timing_supported_uses_enable_timing(self):+ created = []++ def create_event(*, enable_timing=False):+ created.append(enable_timing)+ return MagicMock()++ with patch.object(self.cc.device_module, "Event", side_effect=create_event):+ self.cc._timing_events_supported.cache_clear()+ start, finish, timing_enabled = self.cc.make_timing_event_pair()++ self.assertTrue(timing_enabled)+ self.assertIsNot(start, finish)+ # Every event (probe + the returned pair) was created with enable_timing.+ self.assertTrue(created and all(created))++ def test_timing_fallback_uses_dedicated_events(self):+ events = []++ def create_event(*, enable_timing=False):+ if enable_timing:+ raise TypeError("Event() takes no arguments")+ event = MagicMock()+ events.append(event)+ return event++ with patch.object(self.cc.device_module, "Event", side_effect=create_event):+ self.cc._timing_events_supported.cache_clear()+ start, finish, timing_enabled = self.cc.make_timing_event_pair()++ self.assertFalse(timing_enabled)+ self.assertIs(start, events[0])+ self.assertIs(finish, events[1])+ self.assertIsNot(start, finish)+++class TestHiCacheAckFields(unittest.TestCase):+ def test_num_tokens_and_timing_defaults(self):+ from sglang.srt.managers.cache_controller import HiCacheAck++ ack = HiCacheAck(start_event=None, finish_event=None, node_ids=[1])+ self.assertEqual(ack.num_tokens, 0)+ self.assertFalse(ack.timing_enabled)++ def test_fields_carry_supplied_values(self):+ from sglang.srt.managers.cache_controller import HiCacheAck++ ack = HiCacheAck(+ start_event=None,+ finish_event=None,+ node_ids=[3, 4],+ num_tokens=128,+ timing_enabled=True,+ )+ self.assertEqual(ack.num_tokens, 128)+ self.assertTrue(ack.timing_enabled)+++def _make_load_stub(ack):+ return SimpleNamespace(+ cache_controller=SimpleNamespace(ack_load_queue=[ack]),+ ongoing_load_back={i: object() for i in ack.node_ids},+ dec_lock_ref=MagicMock(),+ metrics_collector=MagicMock(),+ pp_rank=0,+ _all_reduce=MagicMock(),+ )+++class TestLoadingCheckMetrics(unittest.TestCase):+ def test_loading_check_records_duration_and_tokens(self):+ from sglang.srt.managers.cache_controller import HiCacheAck+ from sglang.srt.mem_cache.hiradix_cache import HiRadixCache++ finish_event = MagicMock()+ finish_event.query.return_value = True+ start_event = MagicMock()+ start_event.elapsed_time.return_value = 2000.0 # milliseconds++ ack = HiCacheAck(+ start_event=start_event,+ finish_event=finish_event,+ node_ids=[1, 2],+ num_tokens=1024,+ timing_enabled=True,+ )+ stub = _make_load_stub(ack)++ HiRadixCache.loading_check(stub)++ stub.metrics_collector.increment_load_back_num_tokens.assert_called_once_with(+ 1024+ )+ stub.metrics_collector.observe_load_back_duration.assert_called_once()+ (observed,), _ = stub.metrics_collector.observe_load_back_duration.call_args+ # Duration is reported in seconds (2000 ms -> 2.0 s).+ self.assertAlmostEqual(observed, 2.0)+ self.assertEqual(stub.cache_controller.ack_load_queue, [])+ self.assertEqual(stub.ongoing_load_back, {})++ def test_loading_check_skips_duration_when_timing_unsupported(self):+ from sglang.srt.managers.cache_controller import HiCacheAck+ from sglang.srt.mem_cache.hiradix_cache import HiRadixCache++ finish_event = MagicMock()+ finish_event.query.return_value = True+ start_event = MagicMock()++ ack = HiCacheAck(+ start_event=start_event,+ finish_event=finish_event,+ node_ids=[7],+ num_tokens=512,+ timing_enabled=False,+ )+ stub = _make_load_stub(ack)++ HiRadixCache.loading_check(stub)++ stub.metrics_collector.increment_load_back_num_tokens.assert_called_once_with(+ 512+ )+ stub.metrics_collector.observe_load_back_duration.assert_not_called()+ start_event.elapsed_time.assert_not_called()+ self.assertEqual(stub.cache_controller.ack_load_queue, [])+++if __name__ == "__main__":+ unittest.main()
Head-to-head
Accuracy
77.97%Δ 1.69%
76.27%
Cost / test
$0.61
$0.58Δ $0.03
Latency
162sΔ 105s
267s
Cost distribution
Latency distribution
Input token distribution
Output token distribution
Task outcomes
59 tasks