105 lines
5.5 KiB
Markdown
105 lines
5.5 KiB
Markdown
# G0 — Baseline đo latency (kết quả)
|
||
|
||
Ngày: 2026-08-27. Probe: `native_bridge/debug/g0_latency_probe.py` (chạy với
|
||
`timeBeginPeriod(1)`, 10k block/config, pipeline thật Python→SHM→fx_vst_bridge→SHM).
|
||
Log: `native_bridge/debug/g0_probe_run_full.log`.
|
||
|
||
## 1. Bảng latency plugin (getLatencySamples, @48kHz)
|
||
|
||
| Plugin | getLatencySamples | ms @48k | Ghi chú |
|
||
|---|---|---|---|
|
||
| Sonible pureComp | 2108 | 43.9 | báo latency thật (lookahead) |
|
||
| iZotope Ozone 11 | 0 | 0 | không báo latency (realtime mode) |
|
||
| empty (passthrough) | — | — | chain rỗng |
|
||
|
||
Nguồn: probe `plugin_latency` + log app thật `fxrt_bridge.log`
|
||
(`[RenderFx] STEP getLatencySamples = 2108/0`).
|
||
|
||
## 2. Jitter round-trip (10k block, 53.3s/config)
|
||
|
||
Round-trip = thời gian từ lúc probe gọi `write_input(block j)` đến lúc nhận
|
||
`read_output()` block j (FIFO theo index). Đã sửa pacing probe bằng
|
||
`timeBeginPeriod(1)` (bridge C++ đã gọi — `RealtimeFxLoop.cpp:160`); lần chạy
|
||
trước thiếu nó → Sleep 15.6ms granularity → pump ~22ms/batch ≠ 21.33ms realtime
|
||
→ pureComp bị "stall 1.9s" giả. Với pacing chuẩn, stall đó biến mất — là
|
||
artifact probe, KHÔNG phải VST stall.
|
||
|
||
| Config | mean ms | σ | p50 | p99 | max | recv/sent |
|
||
|---|---|---|---|---|---|---|
|
||
| empty | 21.54 | 1.74 | 21.64 | 22.03 | 25.73 | 9996/10000 |
|
||
| pureComp | 21.69 | 0.26 | 21.66 | 22.02 | 28.94 | 9996/10000 |
|
||
| Ozone 11 | 21.68 | 0.15 | 21.65 | 22.02 | 23.20 | 9996/10000 |
|
||
|
||
- Round-trip ≈ 21.5–21.7ms = đúng 1 batch 4 block (21.33ms) + overhead nhỏ
|
||
(SHM copy + bridge proc 0.001–0.45ms). Latency plugin KHÔNG nằm trong
|
||
round-trip — plugin latency bù bằng PDC (không chặn pipeline).
|
||
- σ round-trip: 0.15–0.26ms (pureComp/Ozone) — RẤT nhỏ → **Gate G2 MỞ**: PDC
|
||
mẫu có ý nghĩa, không cần giảm jitter trước (không cần relay WS→SHM sớm).
|
||
- empty σ=1.74: 1 outlier khởi động (min=0.04ms), p50/p99 vẫn 21.6/22.0.
|
||
- recv=9996 < 10000: 4 block cuối chưa drain hết lúc probe kết thúc (bridge
|
||
chậm hơn pace probe — xem §4), không phải mất block.
|
||
|
||
## 3. Inter-arrival deviation
|
||
|
||
| Config | σ ms | min | max |
|
||
|---|---|---|---|
|
||
| empty | 9.44 | −5.33 | 38.4 |
|
||
| pureComp | 9.36 | −5.33 | 23.5 |
|
||
| Ozone 11 | 9.36 | −5.33 | 17.8 |
|
||
|
||
Block về theo batch 4 (bridge xử lí take=4/lần) → inter-arrival lệch so với
|
||
5.33ms lý tưởng là đặc tính batching, không phải jitter ngẫu nhiên. Round-trip
|
||
σ (§2) là thước đo đúng cho PDC; inter-arrival dùng cho sizing FILL — xem §5.
|
||
|
||
## 4. Bridge FxRTPerf
|
||
|
||
| Nguồn | procAvg | procMax | loopAvg | loopMax | rate blk/s | vs realtime 187.5 |
|
||
|---|---|---|---|---|---|---|
|
||
| probe empty | 0.001ms | 0.05ms | 22.0ms | 1010ms | 181.7 | −3.1% |
|
||
| probe pureComp | 0.45ms | 0.80ms | 22.0ms | 1012ms | 181.6 | −3.1% |
|
||
| probe Ozone | 0.14ms | 0.35ms | 22.0ms | 1008ms | 181.7 | −3.1% |
|
||
| app thật (master chain đầy) | 3.4ms | 10.0ms | 21.4ms | 156ms | 186.5 | −0.5% |
|
||
|
||
- **loopMax ≈ 1s ở MỌI config probe kể cả empty** — spike 1s/lần chạy ~53s,
|
||
không phải VST (empty cũng có). Không xuất hiện trong log app thật gần nhất
|
||
(loopMax 156ms) — nghi Windows scheduler/antivirus/power, cần theo dõi khi
|
||
chạy thật. Probe round-trip max vẫn ≤29ms → spike xảy ra lúc bridge idle,
|
||
không chặn block đang xử lí.
|
||
- **Drift: bridge chậm 0.5–3.1% so realtime** (rate < 187.5). App thật −0.5%
|
||
(186.5): mỗi giây thiếu ~1 block → FILL 8 block (42.7ms) cạn sau ~8s nếu
|
||
không có cơ chế bù. Probe −3.1% là đo có pace probe riêng (nhịp probe + nhịp
|
||
bridge lệch nhau); con số tin cậy cho drift thật là từ app: −0.5%.
|
||
|
||
## 5. ~0.22s gồm gì (xác nhận)
|
||
|
||
Latency path thực đo + hằng số app:
|
||
|
||
| Thành phần | ms | Nguồn |
|
||
|---|---|---|
|
||
| Batching 4 block (pipeline) | ~21.6 | probe round-trip (§2) |
|
||
| FILL buffer worklet 8 block | 42.7 | `sf-fx-realtime.js` FILL=8 |
|
||
| Plugin latency (pureComp) | 43.9 | `getLatencySamples=2108` @48k |
|
||
| WS/main-thread jitter (warm, p50) | ~101 | dbg.log `fx_play_first` sincePlay 38–160ms |
|
||
| **Tổng nghe thấy (warm)** | **~210ms ≈ 0.21s** | khớp ~0.22s quan sát |
|
||
|
||
- PDC hiện tại `FX_RT_ROUNDTRIP_SAMPLES=3840` (80ms) = batching ~7 block +
|
||
FILL 8 block — khớp thực đo (21.6 + 42.7 ≈ 64ms + WS jitter margin). Giữ
|
||
nguyên; `latencyTotal` (plugin thật qua `{cmd:'latency'}`) cộng thêm đúng
|
||
(pureComp +43.9ms).
|
||
- Cold start VST load: 8–17s (dbg.log sincePlay 8111–17211ms), warm sau đó
|
||
38–160ms — là plugin init, không phải latency pipeline; không nằm trong PDC.
|
||
- fx_stats app thật (session master): u=3 h=3 f=13 s=13 cap=1 fi=13 q=5–11 —
|
||
underrun hiếm, queue duy trì 5–11 block → FILL đủ hấp thụ jitter thường.
|
||
|
||
## 6. Kết luận cho G2+
|
||
|
||
1. **Gate G2: MỞ.** σ round-trip 0.15–0.26ms → PDC mẫu có nghĩa; không cần
|
||
relay WS→SHM trước G2.
|
||
2. **Drift bridge −0.5% là phát hiện mới** (không có trong plan §1–§8): FILL
|
||
cạn dần trên session dài → cần quyết định: (a) chấp nhận (underrun hiếm, có
|
||
resume), (b) bù/resync định kỳ, (c) thêm giám sát rate. **Báo user để review
|
||
trước khi đưa vào plan.**
|
||
3. **loopMax ~1s spike** (probe, cả empty): theo dõi, chưa thấy ở app thật.
|
||
4. Plugin latency bảng §1 đủ cho G2: `graph.getLatencySamples()` sẽ thay hằng
|
||
số; dữ liệu hiện tại xác nhận pureComp là plugin duy nhất có latency thật.
|