YSLAB-ai commited on
Commit
0bae7d5
·
verified ·
1 Parent(s): d6ddb10

Correct and publish full MTP sweep

Browse files
README.md CHANGED
@@ -34,8 +34,10 @@ on one DGX Spark. They do not describe Inferact or RadixArk runtime performance.
34
 
35
  - The MTP load guard verified 31/31 expected tensors. The compact BF16 MTP file is
36
  4.86 GiB.
37
- - An MTP depth sweep selected `MTP=2`: 57.13 tok/s median versus 31.12 tok/s at
38
- `MTP=0`, an 83.6% increase under the tested short-request method.
 
 
39
  - Native 262,144-token startup used 76.21 GiB for model loading and exposed 17.37
40
  GiB of BF16 KV, enough for 627,960 cached tokens (2.40 concurrent native windows).
41
  - Exact retrieval passed at 240,051 prompt tokens, with 116.80s TTFT and 2,055.17
 
34
 
35
  - The MTP load guard verified 31/31 expected tensors. The compact BF16 MTP file is
36
  4.86 GiB.
37
+ - A single-stream MTP depth sweep selected `MTP=2`: 44.23 tok/s end-to-end,
38
+ including hidden reasoning and first-visible latency, versus 27.26 tok/s
39
+ at `MTP=0`, a 62.2% increase. Its separately measured visible-answer phase was
40
+ 46.15 tok/s, with 1.324s to first visible content.
41
  - Native 262,144-token startup used 76.21 GiB for model loading and exposed 17.37
42
  GiB of BF16 KV, enough for 627,960 cached tokens (2.40 concurrent native windows).
43
  - Exact retrieval passed at 240,051 prompt tokens, with 116.80s TTFT and 2,055.17
benchmarks/common.py CHANGED
@@ -63,7 +63,7 @@ def read_json(url: str, timeout: float) -> dict[str, Any]:
63
 
64
 
65
  def stream_completion(base_url: str, payload: dict[str, object], timeout: float) -> dict[str, Any]:
66
- """Measure TTFT and decode rate from the first and last emitted delta."""
67
  request = urllib.request.Request(
68
  endpoint(base_url, "chat/completions"),
69
  data=json.dumps(payload).encode("utf-8"),
@@ -78,6 +78,8 @@ def stream_completion(base_url: str, payload: dict[str, object], timeout: float)
78
 
79
  first_delta: float | None = None
80
  last_delta: float | None = None
 
 
81
  usage: dict[str, Any] | None = None
82
  content_parts: list[str] = []
83
  with response:
@@ -93,25 +95,50 @@ def stream_completion(base_url: str, payload: dict[str, object], timeout: float)
93
  usage = event["usage"]
94
  for choice in event.get("choices") or []:
95
  delta = choice.get("delta") or {}
 
96
  text = delta.get("content")
97
- if isinstance(text, str) and text:
98
- content_parts.append(text)
 
99
  now = time.perf_counter()
100
  first_delta = now if first_delta is None else first_delta
101
  last_delta = now
 
 
 
 
 
 
102
  finished = time.perf_counter()
103
  if usage is None or first_delta is None:
104
  raise RuntimeError("stream ended without usage or final output")
105
  decode_seconds = max((last_delta or finished) - first_delta, 1e-9)
106
  completion_tokens = int(usage["completion_tokens"])
 
 
 
 
 
 
 
 
107
  return {
108
  "content": "".join(content_parts),
109
  "usage": usage,
110
  "ttft_seconds": first_delta - started,
 
 
 
111
  "total_seconds": finished - started,
112
  "decode_seconds": decode_seconds,
113
  "prefill_tokens_per_second": int(usage["prompt_tokens"]) / max(first_delta - started, 1e-9),
114
  "decode_tokens_per_second": max(completion_tokens - 1, 0) / decode_seconds,
 
 
 
 
 
 
115
  }
116
 
117
 
 
63
 
64
 
65
  def stream_completion(base_url: str, payload: dict[str, object], timeout: float) -> dict[str, Any]:
66
+ """Measure reasoning-aware TTFT, decode, visible-content, and wall rates."""
67
  request = urllib.request.Request(
68
  endpoint(base_url, "chat/completions"),
69
  data=json.dumps(payload).encode("utf-8"),
 
78
 
79
  first_delta: float | None = None
80
  last_delta: float | None = None
81
+ first_visible_delta: float | None = None
82
+ last_visible_delta: float | None = None
83
  usage: dict[str, Any] | None = None
84
  content_parts: list[str] = []
85
  with response:
 
95
  usage = event["usage"]
96
  for choice in event.get("choices") or []:
97
  delta = choice.get("delta") or {}
98
+ reasoning = delta.get("reasoning_content")
99
  text = delta.get("content")
100
+ has_reasoning = isinstance(reasoning, str) and bool(reasoning)
101
+ has_content = isinstance(text, str) and bool(text)
102
+ if has_reasoning or has_content:
103
  now = time.perf_counter()
104
  first_delta = now if first_delta is None else first_delta
105
  last_delta = now
106
+ if has_content:
107
+ content_parts.append(text)
108
+ first_visible_delta = (
109
+ now if first_visible_delta is None else first_visible_delta
110
+ )
111
+ last_visible_delta = now
112
  finished = time.perf_counter()
113
  if usage is None or first_delta is None:
114
  raise RuntimeError("stream ended without usage or final output")
115
  decode_seconds = max((last_delta or finished) - first_delta, 1e-9)
116
  completion_tokens = int(usage["completion_tokens"])
117
+ details = usage.get("completion_tokens_details") or {}
118
+ reasoning_tokens = int(details.get("reasoning_tokens") or 0)
119
+ visible_tokens = max(completion_tokens - reasoning_tokens, 0)
120
+ visible_seconds = (
121
+ max((last_visible_delta or finished) - first_visible_delta, 1e-9)
122
+ if first_visible_delta is not None
123
+ else None
124
+ )
125
  return {
126
  "content": "".join(content_parts),
127
  "usage": usage,
128
  "ttft_seconds": first_delta - started,
129
+ "time_to_first_visible_content_seconds": (
130
+ first_visible_delta - started if first_visible_delta is not None else None
131
+ ),
132
  "total_seconds": finished - started,
133
  "decode_seconds": decode_seconds,
134
  "prefill_tokens_per_second": int(usage["prompt_tokens"]) / max(first_delta - started, 1e-9),
135
  "decode_tokens_per_second": max(completion_tokens - 1, 0) / decode_seconds,
136
+ "visible_content_tokens_per_second": (
137
+ max(visible_tokens - 1, 0) / visible_seconds
138
+ if visible_seconds is not None
139
+ else None
140
+ ),
141
+ "end_to_end_tokens_per_second": completion_tokens / max(finished - started, 1e-9),
142
  }
143
 
144
 
docs/BENCHMARKS.md CHANGED
@@ -10,31 +10,41 @@ also use the exact 31 BF16 MTP tensors from pinned
10
  `7b719225242aacd3dbd3f9407468c2ee9a9d2594`. Inferact and RadixArk are not
11
  runtime-qualified by these results.
12
 
13
- ## BF16 MTP depth sweep
14
 
15
  The load guard verified 31/31 tensors before accepting requests. Each depth used a
16
- 32,768-token server profile, one maximum sequence, 0.80 GPU-memory utilization, one
17
- 128-token warm-up, then three fixed 256-token streamed samples. The table reports
18
- the median decode rate and TTFT. Thinking mode used medium reasoning effort,
 
 
 
19
  `temperature=1.0`, `top_p=0.95`, `top_k=20`, `min_p=0.0`,
20
  `presence_penalty=0.0`, and `repetition_penalty=1.0`.
21
 
22
- | MTP depth | Median decode tok/s | Median TTFT | Aggregate acceptance |
23
  | ---: | ---: | ---: | ---: |
24
- | 0 | 31.12 | 1.196s | n/a |
25
- | 1 | 39.16 | 1.206s | 305/463 (65.9%) |
26
- | **2** | **57.13** | 1.324s | **532/722 (73.7%)** |
27
- | 3 | 55.55 | 1.629s | 563/993 (56.7%) |
28
- | 4 | 51.04 | 1.123s | 611/1,148 (53.2%) |
29
- | 5 | 45.19 | 1.249s | 454/1,560 (29.1%) |
30
- | 6 | 44.43 | 1.429s | 516/1,230 (42.0%) |
31
- | 8 | 37.89 | 1.758s | 487/1,600 (30.4%) |
32
- | 10 | 36.32 | 1.648s | 642/2,150 (29.9%) |
33
-
34
- `MTP=2` is the qualified selection. It was 83.6% faster than `MTP=0` in this
35
- specific short-request measurement. Higher draft depths lost enough acceptance to
36
- cost more verification work than they saved. Depths five and above require the
37
- recipe's 48-token block alignment for the QSA speculative ring.
 
 
 
 
 
 
 
38
 
39
  The machine-readable record is
40
  [`mtp-bf16-sweep.json`](../results/orcarouter/mtp-bf16-sweep.json).
 
10
  `7b719225242aacd3dbd3f9407468c2ee9a9d2594`. Inferact and RadixArk are not
11
  runtime-qualified by these results.
12
 
13
+ ## Single-stream BF16 MTP depth sweep
14
 
15
  The load guard verified 31/31 tensors before accepting requests. Each depth used a
16
+ 32,768-token server profile, `concurrency=1`, one maximum sequence, 0.80 GPU-memory
17
+ utilization, one 128-token warm-up, then three fixed 256-token streamed samples.
18
+ The primary rate divides all completion tokens—including hidden reasoning—by total
19
+ request wall time, so it also includes latency before visible content. The next
20
+ column is the median time from request start to the first visible content delta.
21
+ Thinking mode used medium reasoning effort,
22
  `temperature=1.0`, `top_p=0.95`, `top_k=20`, `min_p=0.0`,
23
  `presence_penalty=0.0`, and `repetition_penalty=1.0`.
24
 
25
+ | MTP depth | Median end-to-end completion tok/s | Time to first visible content | Aggregate acceptance |
26
  | ---: | ---: | ---: | ---: |
27
+ | 0 | 27.26 | 1.196s | n/a |
28
+ | 1 | 33.17 | 1.206s | 305/463 (65.9%) |
29
+ | **2** | **44.23** | **1.324s** | **532/722 (73.7%)** |
30
+ | 3 | 40.95 | 1.629s | 563/993 (56.7%) |
31
+ | 4 | 41.84 | 1.123s | 611/1,148 (53.2%) |
32
+ | 5 | 35.45 | 1.249s | 454/1,560 (29.1%) |
33
+ | 6 | 35.71 | 1.429s | 516/1,230 (42.0%) |
34
+ | 8 | 30.43 | 1.758s | 487/1,600 (30.4%) |
35
+ | 10 | 28.31 | 1.648s | 642/2,150 (29.9%) |
36
+
37
+ `MTP=2` is the qualified selection. It was 62.2% faster end-to-end than `MTP=0`
38
+ in this single-stream short-request measurement. For MTP2, retained reasoning-token
39
+ accounting also gives a separate median visible-answer phase rate of 46.15 tok/s,
40
+ measured from the first through last visible content token. That rate excludes hidden
41
+ reasoning and must not be combined with total completion-token counts.
42
+
43
+ An earlier revision did combine all completion tokens with a visible-content-only
44
+ time interval. That mixed metric has been superseded and is not comparable to either
45
+ rate above. Higher draft depths lost enough acceptance to cost more verification
46
+ work than they saved. Depths five and above require the recipe's 48-token block
47
+ alignment for the QSA speculative ring.
48
 
49
  The machine-readable record is
50
  [`mtp-bf16-sweep.json`](../results/orcarouter/mtp-bf16-sweep.json).
results/orcarouter/mtp-bf16-sweep.json CHANGED
@@ -5,6 +5,7 @@
5
  "mtp_source_revision": "7b719225242aacd3dbd3f9407468c2ee9a9d2594",
6
  "runtime": "vLLM 0.1.dev20073+g8e685d198",
7
  "context_window": 32768,
 
8
  "max_num_seqs": 1,
9
  "gpu_memory_utilization": 0.8,
10
  "sampling": {
@@ -17,8 +18,14 @@
17
  "presence_penalty": 0.0,
18
  "repetition_penalty": 1.0
19
  },
20
- "measurement": "median of three fixed 256-token streamed samples after a 128-token warm-up",
 
 
 
 
 
21
  "selected_depth": 2,
 
22
  "mtp_overlay": {
23
  "dtype": "BF16",
24
  "loaded_tensors": 31,
@@ -26,15 +33,15 @@
26
  "compact_file_gib": 4.86
27
  },
28
  "results": [
29
- {"depth": 0, "median_decode_tokens_per_second": 31.1235, "median_ttft_seconds": 1.1963, "acceptance": null},
30
- {"depth": 1, "median_decode_tokens_per_second": 39.1602, "median_ttft_seconds": 1.20583, "accepted_tokens": 305, "draft_tokens": 463, "acceptance": 0.6587},
31
- {"depth": 2, "median_decode_tokens_per_second": 57.1303, "median_ttft_seconds": 1.32445, "accepted_tokens": 532, "draft_tokens": 722, "acceptance": 0.7368},
32
- {"depth": 3, "median_decode_tokens_per_second": 55.5512, "median_ttft_seconds": 1.62869, "accepted_tokens": 563, "draft_tokens": 993, "acceptance": 0.5670},
33
- {"depth": 4, "median_decode_tokens_per_second": 51.0404, "median_ttft_seconds": 1.12255, "accepted_tokens": 611, "draft_tokens": 1148, "acceptance": 0.5322},
34
- {"depth": 5, "median_decode_tokens_per_second": 45.1911, "median_ttft_seconds": 1.24926, "accepted_tokens": 454, "draft_tokens": 1560, "acceptance": 0.2910},
35
- {"depth": 6, "median_decode_tokens_per_second": 44.4321, "median_ttft_seconds": 1.42869, "accepted_tokens": 516, "draft_tokens": 1230, "acceptance": 0.4195},
36
- {"depth": 8, "median_decode_tokens_per_second": 37.8855, "median_ttft_seconds": 1.75837, "accepted_tokens": 487, "draft_tokens": 1600, "acceptance": 0.3044},
37
- {"depth": 10, "median_decode_tokens_per_second": 36.3225, "median_ttft_seconds": 1.64792, "accepted_tokens": 642, "draft_tokens": 2150, "acceptance": 0.2986}
38
  ],
39
  "native_context_validation": {
40
  "max_model_len": 262144,
 
5
  "mtp_source_revision": "7b719225242aacd3dbd3f9407468c2ee9a9d2594",
6
  "runtime": "vLLM 0.1.dev20073+g8e685d198",
7
  "context_window": 32768,
8
+ "concurrency": 1,
9
  "max_num_seqs": 1,
10
  "gpu_memory_utilization": 0.8,
11
  "sampling": {
 
18
  "presence_penalty": 0.0,
19
  "repetition_penalty": 1.0
20
  },
21
+ "measurement": "single-stream median of three fixed 256-token streamed samples after a 128-token warm-up",
22
+ "timing_definitions": {
23
+ "end_to_end_completion_tokens_per_second": "all completion tokens, including hidden reasoning, divided by total request wall time",
24
+ "time_to_first_visible_content_seconds": "request start through the first non-empty visible content delta",
25
+ "visible_content_tokens_per_second": "visible content tokens only, measured from the first through last visible content delta"
26
+ },
27
  "selected_depth": 2,
28
+ "selected_depth_end_to_end_gain_vs_mtp0": 0.6222,
29
  "mtp_overlay": {
30
  "dtype": "BF16",
31
  "loaded_tensors": 31,
 
33
  "compact_file_gib": 4.86
34
  },
35
  "results": [
36
+ {"depth": 0, "median_end_to_end_completion_tokens_per_second": 27.2645, "median_time_to_first_visible_content_seconds": 1.1963, "acceptance": null},
37
+ {"depth": 1, "median_end_to_end_completion_tokens_per_second": 33.1749, "median_time_to_first_visible_content_seconds": 1.20583, "accepted_tokens": 305, "draft_tokens": 463, "acceptance": 0.6587},
38
+ {"depth": 2, "median_end_to_end_completion_tokens_per_second": 44.2286, "median_visible_content_tokens_per_second": 46.1523, "median_time_to_first_visible_content_seconds": 1.32445, "accepted_tokens": 532, "draft_tokens": 722, "acceptance": 0.7368},
39
+ {"depth": 3, "median_end_to_end_completion_tokens_per_second": 40.9544, "median_time_to_first_visible_content_seconds": 1.62869, "accepted_tokens": 563, "draft_tokens": 993, "acceptance": 0.5670},
40
+ {"depth": 4, "median_end_to_end_completion_tokens_per_second": 41.8389, "median_time_to_first_visible_content_seconds": 1.12255, "accepted_tokens": 611, "draft_tokens": 1148, "acceptance": 0.5322},
41
+ {"depth": 5, "median_end_to_end_completion_tokens_per_second": 35.4522, "median_time_to_first_visible_content_seconds": 1.24926, "accepted_tokens": 454, "draft_tokens": 1560, "acceptance": 0.2910},
42
+ {"depth": 6, "median_end_to_end_completion_tokens_per_second": 35.7146, "median_time_to_first_visible_content_seconds": 1.42869, "accepted_tokens": 516, "draft_tokens": 1230, "acceptance": 0.4195},
43
+ {"depth": 8, "median_end_to_end_completion_tokens_per_second": 30.4295, "median_time_to_first_visible_content_seconds": 1.75837, "accepted_tokens": 487, "draft_tokens": 1600, "acceptance": 0.3044},
44
+ {"depth": 10, "median_end_to_end_completion_tokens_per_second": 28.3075, "median_time_to_first_visible_content_seconds": 1.64792, "accepted_tokens": 642, "draft_tokens": 2150, "acceptance": 0.2986}
45
  ],
46
  "native_context_validation": {
47
  "max_model_len": 262144,
tests/test_benchmarks.py CHANGED
@@ -12,10 +12,60 @@ ROOT = Path(__file__).resolve().parents[1]
12
  sys.path.insert(0, str(ROOT / "benchmarks"))
13
 
14
  from functional import validate # noqa: E402
 
15
  import long_context # noqa: E402
16
  import stability # noqa: E402
17
 
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  class FunctionalBenchmarkTests(unittest.TestCase):
20
  def test_code_validator_rejects_malicious_output_without_executing_it(self):
21
  """An extra payload after square must never be executed by validation."""
 
12
  sys.path.insert(0, str(ROOT / "benchmarks"))
13
 
14
  from functional import validate # noqa: E402
15
+ import common # noqa: E402
16
  import long_context # noqa: E402
17
  import stability # noqa: E402
18
 
19
 
20
+ class _StreamResponse:
21
+ def __init__(self, lines: list[bytes]):
22
+ self._lines = lines
23
+
24
+ def __enter__(self):
25
+ return self
26
+
27
+ def __exit__(self, *_args):
28
+ return None
29
+
30
+ def __iter__(self):
31
+ return iter(self._lines)
32
+
33
+
34
+ class StreamCompletionMetricTests(unittest.TestCase):
35
+ def test_reasoning_and_visible_output_use_separate_token_clocks(self):
36
+ """Hidden tokens must never be divided by visible-content-only time."""
37
+ events = [
38
+ b'data: {"choices":[{"delta":{"reasoning_content":"think"}}]}\n',
39
+ b'data: {"choices":[{"delta":{"content":"A"}}]}\n',
40
+ b'data: {"choices":[{"delta":{"content":"B"}}]}\n',
41
+ (
42
+ b'data: {"choices":[],"usage":{"prompt_tokens":10,'
43
+ b'"completion_tokens":5,"completion_tokens_details":'
44
+ b'{"reasoning_tokens":2}}}\n'
45
+ ),
46
+ b'data: [DONE]\n',
47
+ ]
48
+ clock = [0.0, 1.0, 3.0, 4.0, 5.0]
49
+
50
+ with patch.object(
51
+ common.urllib.request,
52
+ "urlopen",
53
+ return_value=_StreamResponse(events),
54
+ ), patch.object(common.time, "perf_counter", side_effect=clock):
55
+ result = common.stream_completion(
56
+ "http://127.0.0.1:1/v1",
57
+ {"stream": True},
58
+ 1.0,
59
+ )
60
+
61
+ self.assertEqual(result["content"], "AB")
62
+ self.assertEqual(result["ttft_seconds"], 1.0)
63
+ self.assertEqual(result["time_to_first_visible_content_seconds"], 3.0)
64
+ self.assertAlmostEqual(result["decode_tokens_per_second"], 4 / 3)
65
+ self.assertEqual(result["visible_content_tokens_per_second"], 2.0)
66
+ self.assertEqual(result["end_to_end_tokens_per_second"], 1.0)
67
+
68
+
69
  class FunctionalBenchmarkTests(unittest.TestCase):
70
  def test_code_validator_rejects_malicious_output_without_executing_it(self):
71
  """An extra payload after square must never be executed by validation."""
tests/test_publication_docs.py CHANGED
@@ -93,7 +93,10 @@ class PublicationDocumentationTests(unittest.TestCase):
93
  self.assertIn("orca-uncensored-bf16-mtp", docs)
94
  self.assertIn("31/31", docs)
95
  self.assertIn("MTP=2", docs)
96
- self.assertIn("57.13 tok/s", docs)
 
 
 
97
  self.assertIn("240,051 prompt tokens", docs)
98
  for stale_claim in (
99
  "requires `MTP=0`",
@@ -111,9 +114,29 @@ class PublicationDocumentationTests(unittest.TestCase):
111
  )
112
  )
113
  self.assertEqual(record["selected_depth"], 2)
 
114
  self.assertEqual([row["depth"] for row in record["results"]], [0, 1, 2, 3, 4, 5, 6, 8, 10])
115
  selected = next(row for row in record["results"] if row["depth"] == 2)
116
- self.assertEqual(selected["median_decode_tokens_per_second"], 57.1303)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  self.assertEqual(record["mtp_overlay"]["loaded_tensors"], 31)
118
 
119
  def test_private_deployment_terms_are_absent(self) -> None:
 
93
  self.assertIn("orca-uncensored-bf16-mtp", docs)
94
  self.assertIn("31/31", docs)
95
  self.assertIn("MTP=2", docs)
96
+ self.assertIn("44.23 tok/s", docs)
97
+ self.assertIn("46.15 tok/s", docs)
98
+ self.assertIn("single-stream", docs)
99
+ self.assertNotIn("57.13 tok/s", docs)
100
  self.assertIn("240,051 prompt tokens", docs)
101
  for stale_claim in (
102
  "requires `MTP=0`",
 
114
  )
115
  )
116
  self.assertEqual(record["selected_depth"], 2)
117
+ self.assertEqual(record["concurrency"], 1)
118
  self.assertEqual([row["depth"] for row in record["results"]], [0, 1, 2, 3, 4, 5, 6, 8, 10])
119
  selected = next(row for row in record["results"] if row["depth"] == 2)
120
+ baseline = next(row for row in record["results"] if row["depth"] == 0)
121
+ self.assertEqual(
122
+ selected["median_end_to_end_completion_tokens_per_second"],
123
+ 44.2286,
124
+ )
125
+ self.assertEqual(
126
+ selected["median_visible_content_tokens_per_second"],
127
+ 46.1523,
128
+ )
129
+ self.assertEqual(
130
+ selected["median_time_to_first_visible_content_seconds"],
131
+ 1.32445,
132
+ )
133
+ self.assertEqual(
134
+ baseline["median_end_to_end_completion_tokens_per_second"],
135
+ 27.2645,
136
+ )
137
+ self.assertFalse(
138
+ [row for row in record["results"] if "median_decode_tokens_per_second" in row]
139
+ )
140
  self.assertEqual(record["mtp_overlay"]["loaded_tensors"], 31)
141
 
142
  def test_private_deployment_terms_are_absent(self) -> None: