File size: 9,743 Bytes
fcd69cc 076169b 063a504 076169b 063a504 076169b 063a504 076169b 1e2d768 fcd69cc 1e2d768 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | # Qwen3-TTS benchmarks on RTX PRO 6000 Blackwell
Two studies live in this repo — **note the model size for every table**:
| study | model | date | report | raw data |
|---|---|---|---|---|
| TRT vs native vocoder A/B (FastAPI + Silero path) | **1.7B** `Qwen3-TTS-RU-CallCenter-stressed` | 2026-07-14 | this README (below) + [`VOCODER_RUNTIME_BENCH.md`](./VOCODER_RUNTIME_BENCH.md) | `metrics/native-eager-fastapi-silero-c10-c60/`, `metrics/trt-fastapi-silero-c10-c60/` |
| Load test + 1.7B comparison + TRT-vs-eager A/B (direct vLLM path) | **0.6B** `Qwen/Qwen3-TTS-12Hz-0.6B-Base` | 2026-07-16 | [`QWEN06B_BENCH.md`](./QWEN06B_BENCH.md) | `metrics/qwen06b-trt-c1-c50/`, `metrics/qwen06b-trt-high-c30-c64/`, `metrics/qwen06b-eager-c1-c50/` |
---
# [1.7B] TensorRT Vocoder vs Native PyTorch Vocoder with FastAPI and Silero Stress
Exact A/B measurement date: 2026-07-14. Hardware: NVIDIA RTX PRO 6000
Blackwell Server Edition. Model: `Qwen3-TTS-RU-CallCenter-stressed`, Base voice
clone with `10_ekaterina.wav`, PCM16 mono at 24 kHz.
## Result
The TensorRT vocoder sustained every tested level from 10 through 60 concurrent
sessions within SLO. The native PyTorch/eager vocoder passed through concurrency
30 and failed at 40, 50, and 60.
Both runs used the complete public service path, including Russian text
normalization and automatic stress placement:
`DVC replay -> FastAPI :8000 -> normalization -> Silero Stress -> vLLM -> vocoder`
The only intentional inference-runtime variable was:
- **TRT run:** `OMNI_TRT_VOCODER=1`, code2wav decoded by TensorRT in Triton.
- **Native run:** `OMNI_TRT_VOCODER=0`, code2wav decoded by the original
in-process PyTorch/eager implementation.
## Exact workload controls
Both runs used:
- the same 100 private-HF call scenarios and seed 42;
- the same `10_ekaterina.wav` and transcript reference;
- the same `qwen3_tts_bigmem.yaml` deployment configuration;
- the same sentence chunker and LLM simulator;
- two in-flight TTS chunks per session;
- real recorded user-pause pace (`user_time_scale: 1.0`);
- 90-second sustained windows at concurrency 10, 20, 30, 40, 50, and 60;
- the same SLO thresholds and 200 ms audible-gap boundary.
TRT-path verification: the Triton `code2wav` inference counter increased during
the TRT run. Native-path verification: it remained exactly `30674 -> 30674`
through the complete native run. After the experiment, the TRT service was
restored and the counter increased again on a control request.
## Gap definitions
- **Micro-gap:** a playback-buffer underrun shorter than 200 ms. It is measured,
written into the WAV timeline, and logged, but does not count as an audible
SLO stutter.
- **Audible gap:** a playback-buffer underrun of at least 200 ms.
- **Total gaps:** micro-gaps plus audible gaps.
- **Gap frequency:** gap events per 100 completed turns. Turns can contain more
than one gap, so this is an event rate rather than a percentage of turns.
- **Audible-gap turns:** percentage of turns containing at least one gap of
200 ms or longer.
- Initial silence before the first PCM bytes is represented by TTFA/E2E and is
not counted as a mid-phrase gap.
## Primary comparison: gap scaling
| Concurrency | TRT turns | TRT total gaps | TRT gaps / 100 turns | TRT audible gaps | Native turns | Native total gaps | Native gaps / 100 turns | Native audible gaps | Native audible-gap turns |
|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
| 10 | 60 | 0 | 0.00 | 0 | 61 | 0 | 0.00 | 0 | 0.00% |
| 20 | 119 | 0 | 0.00 | 0 | 119 | 2 | 1.68 | 0 | 0.00% |
| 30 | 185 | 0 | 0.00 | 0 | 178 | 11 | 6.18 | 6 | 3.37% |
| 40 | 246 | 2 | 0.81 | 0 | 246 | 36 | 14.63 | 14 | 5.69% |
| 50 | 310 | 7 | 2.26 | 0 | 305 | 72 | 23.61 | 28 | 8.52% |
| 60 | 374 | 18 | 4.81 | 0 | 358 | 157 | 43.85 | 54 | 12.57% |
At concurrency 60, the native vocoder produced one playback gap per 2.28 turns
on average. The TRT vocoder produced one short micro-gap per 20.78 turns and no
audible gaps.
## Gap duration detail
| Concurrency | TRT micro-gaps | TRT micro p95, ms | TRT max gap, ms | Native micro-gaps | Native micro p95, ms | Native audible gaps | Native audible p95, ms | Native max gap, ms |
|---:|---:|---:|---:|---:|---:|---:|---:|---:|
| 10 | 0 | - | - | 0 | - | 0 | - | - |
| 20 | 0 | - | - | 2 | 195.6 | 0 | - | 195.6 |
| 30 | 0 | - | - | 5 | 188.9 | 6 | 360.2 | 360.2 |
| 40 | 2 | 33.8 | 33.8 | 22 | 166.0 | 14 | 910.8 | 911.6 |
| 50 | 7 | 53.8 | 53.8 | 44 | 193.2 | 28 | 1,217.8 | 1,846.1 |
| 60 | 18 | 71.0 | 110.3 | 103 | 172.4 | 54 | 1,235.6 | 1,242.0 |
The TRT run's worst gap across all levels was 110.3 ms. The native run's worst
gap was 1,846.1 ms at concurrency 50.
## Latency and throughput
| Concurrency | TRT TTFA p95, ms | Native TTFA p95, ms | TRT E2E p95, ms | Native E2E p95, ms | TRT audio x | Native audio x | TRT SLO | Native SLO |
|---:|---:|---:|---:|---:|---:|---:|:---:|:---:|
| 10 | 173.5 | 202.5 | 1,120.7 | 1,126.1 | 7.64 | 7.79 | PASS | PASS |
| 20 | 259.9 | 440.8 | 1,210.3 | 1,280.7 | 16.87 | 16.21 | PASS | PASS |
| 30 | 278.6 | 489.6 | 1,179.3 | 1,242.6 | 23.51 | 23.82 | PASS | PASS |
| 40 | 504.6 | 1,151.0 | 1,243.8 | 2,004.0 | 31.13 | 31.01 | PASS | FAIL |
| 50 | 522.4 | 1,720.7 | 1,258.9 | 2,315.6 | 39.05 | 39.02 | PASS | FAIL |
| 60 | 578.2 | 2,816.9 | 1,319.6 | 3,658.6 | 47.40 | 45.16 | PASS | FAIL |
Throughput remains similar through concurrency 50, but the native vocoder's
queueing latency and playback discontinuities grow sharply. At concurrency 60,
native TTFA p95 is 4.87 times the TRT value.
## Detailed run tables
### TensorRT vocoder
| Concurrency | Turns | Micro-gaps | Audible gaps | Gap events / 100 turns | TTFA p50/p95/p99, ms | E2E p95, ms | Errors | SLO |
|---:|---:|---:|---:|---:|---:|---:|---:|:---:|
| 10 | 60 | 0 | 0 | 0.00 | 130.2 / 173.5 / 194.9 | 1,120.7 | 0 | PASS |
| 20 | 119 | 0 | 0 | 0.00 | 148.0 / 259.9 / 299.0 | 1,210.3 | 0 | PASS |
| 30 | 185 | 0 | 0 | 0.00 | 153.9 / 278.6 / 331.1 | 1,179.3 | 0 | PASS |
| 40 | 246 | 2 | 0 | 0.81 | 167.1 / 504.6 / 642.4 | 1,243.8 | 0 | PASS |
| 50 | 310 | 7 | 0 | 2.26 | 176.1 / 522.4 / 694.0 | 1,258.9 | 0 | PASS |
| 60 | 374 | 18 | 0 | 4.81 | 197.6 / 578.2 / 845.8 | 1,319.6 | 0 | PASS |
Measured TRT capacity lower bound: **at least 60 concurrent sessions**. A level
above 60 was not included in this exact A/B run.
### Native PyTorch/eager vocoder
| Concurrency | Turns | Micro-gaps | Audible gaps | Gap events / 100 turns | TTFA p50/p95/p99, ms | E2E p95, ms | Errors | SLO |
|---:|---:|---:|---:|---:|---:|---:|---:|:---:|
| 10 | 61 | 0 | 0 | 0.00 | 143.9 / 202.5 / 253.9 | 1,126.1 | 0 | PASS |
| 20 | 119 | 2 | 0 | 1.68 | 181.3 / 440.8 / 537.0 | 1,280.7 | 0 | PASS |
| 30 | 178 | 5 | 6 | 6.18 | 202.6 / 489.6 / 706.6 | 1,242.6 | 0 | PASS |
| 40 | 246 | 22 | 14 | 14.63 | 235.7 / 1,151.0 / 3,334.2 | 2,004.0 | 0 | FAIL |
| 50 | 305 | 44 | 28 | 23.61 | 322.3 / 1,720.7 / 3,542.4 | 2,315.6 | 0 | FAIL |
| 60 | 358 | 103 | 54 | 43.85 | 460.9 / 2,816.9 / 5,477.3 | 3,658.6 | 0 | FAIL |
Measured native capacity under the configured SLO: **30 concurrent sessions**.
## Conclusions
1. Silero Stress is compatible with both vocoder implementations: neither run
produced HTTP or TTS errors, and both returned valid streaming PCM.
2. The original native vocoder remains acceptable through concurrency 30, but
playback gaps begin at 20 and audible gaps begin at 30.
3. Native latency crosses the SLO at concurrency 40 and degrades rapidly at
50/60 despite similar aggregate audio throughput.
4. TensorRT eliminates all audible gaps in the tested 10-to-60 range and keeps
TTFA/E2E p95 within SLO at every level.
5. The measured SLO capacity improvement is **30 -> at least 60 concurrent
sessions**.
## Data provenance
TRT aggregate artifacts:
- `experiments/fastapi-stress-c10-c60-90s-20260714/metrics.json`
- `experiments/fastapi-stress-c10-c60-90s-20260714/env.json`
- `experiments/fastapi-stress-c10-c60-90s-20260714/params_used.yaml`
- `experiments/fastapi-stress-c10-c60-90s-20260714/gpu_dmon.log`
Native aggregate artifacts:
- `experiments/fastapi-stress-native-eager-c10-c60-90s-20260714/metrics.json`
- `experiments/fastapi-stress-native-eager-c10-c60-90s-20260714/env.json`
- `experiments/fastapi-stress-native-eager-c10-c60-90s-20260714/params_used.yaml`
- `experiments/fastapi-stress-native-eager-c10-c60-90s-20260714/gpu_dmon.log`
Private-corpus artifacts (`events.jsonl`, `turns.jsonl`, WAV recordings, and the
HTML report containing turn text) are intentionally kept local and are not
published to the public Hugging Face repository.
- Scenario SHA-256: `627261a0ada620c562449c53ffc6ee546eb29720d68ba3327c95a22d506b77cb`
- Reference WAV SHA-256: `d913ffab4a16c5a017a36ad2d00a8352fcdb190396d64f37d5a5d91466dec673`
SLO thresholds: TTS TTFA p95 <= 800 ms, E2E first-audio p95 <= 2,000 ms,
audible underruns <= 0.2 per turn, and errors <= 1%.
---
# [0.6B] Update 2026-07-16: Qwen3-TTS-12Hz-0.6B-Base study
Everything in this section was measured on the **0.6B** model
(`Qwen/Qwen3-TTS-12Hz-0.6B-Base`), not the 1.7B production finetune.
Full report: [`QWEN06B_BENCH.md`](./QWEN06B_BENCH.md). Highlights (same GPU,
same rig, shipped `qwen3_tts_gb10.yaml` config):
- 0.6B swap is weight-only (identical codec dims, engines auto-rebuild).
- Capacity within SLO: **>= 50 concurrent calls** (same as 1.7B) at 25-40 %
lower TTFA: p95 at c50 **350 ms vs 594 ms** (1.7B).
- TRT-vs-eager A/B on 0.6B: **SLO capacity 50 vs 30**; at c50 eager TTFA p95
2344 ms vs **350 ms** TRT (x6.7) - the TRT vocoder wins regardless of talker
size (the vocoder is the same in both checkpoints).
- Raw data: `metrics/qwen06b-trt-c1-c50/`, `metrics/qwen06b-trt-high-c30-c64/`,
`metrics/qwen06b-eager-c1-c50/`.
|