docs(perception): record latency and triton parity limits

This commit is contained in:
DCCONSTRUCTIONS
2026-09-02 02:52:38 +03:00
parent 34f13ba59e
commit ce09d30c1a
2 changed files with 162 additions and 4 deletions
@@ -15,6 +15,14 @@ latency runs; shared-budget CPU overlap дважды дал 128/128 без drops
p95 128.75/122.69 ms и p99 151.67/157.10 ms. Это не product cutover,
не самостоятельный образ и пока не latency qualification.
Последнее дополнение — 2026-09-02 02:47 МСК: surface cache reuse подтверждён
без изменения functional outputs; добавлены NVML, source-clocked layer freshness
и экспериментальный DDRNet TensorRT backend в общем Triton с RF-DETR.
Все 12 новых source-paced запусков дали 128/128 без drops, но стабильного
125 ms gate нет. TensorRT-кандидат дополнительно **не принят по parity**:
0.01195% отличающихся пикселей изменили одну ячейку grass→hard_surface и
NO_GO→ALLOW_candidate. Default остаётся pinned PyTorch; подробности в конце.
## Решение и сделанный объём
Первый профиль зафиксирован как `K1 Perception — DDRNet-39 + RF-DETR + TGS`:
@@ -711,3 +719,148 @@ Ollama/Frigate остаются exited/restart=no. Deployment и product cutover
**Следующий открытый риск этапа 1:** output-level layered freshness и latency
tail. Direct handoff можно переносить в общий runtime; p99 требует отдельного
профилирования DDRNet/CPU sections и затем повторного whole-path gate.
## Surface / telemetry / cadence / unified Triton — 2026-09-02 01:5702:47 МСК
### Принятые изменения и сохранённая граница
Commit `d9ea7c1` переиспользует уже вычисленные cell observations в online
local-surface cache вместо второго группирования того же облака. Оба
128-frame Worker-повтора побитово сохраняют segmentation/proposals,
lineage/binding, observations, tracks, threats, range/surface state,
costmap states/material и non-timing TGS. Surface p99 = 19.44 / 21.87 ms.
Runtime age/stale flags не входят в побитовое сравнение вычислений.
Новая NVML-сессия заменяет запуск `nvidia-smi` каждые 500 ms. Контроль без
телеметрии не убрал хвост: это полезное упрощение наблюдателя, не доказанное
решение p99. `none` применяется только для диагностики и честно оставляет
resource gates непроверенными.
Пилот теперь публикует source sequence/time, source age и age-at-policy
для segmentation/detection/geometry. Экспериментальный DDRNet cadence
определяется исходным временем, detector и CPU graph продолжают каждый кадр;
повторно используемая маска не получает новый timestamp. `interval=0` остаётся
default. 50 ms cadence использовал 118 новых масок и 10 явно reused;
100 ms — 82/46. Один удачный 50 ms запуск не выдержал повтора, поэтому
снижение cadence не принято как способ закрыть latency gate. Это ещё не
полный versioned layered-freshness ABI общего продуктового runtime.
### Все результаты, включая отрицательные
Источник и временное окно прежние; все 12 запусков: 128 released,
128 completed, 0 drops/unaccounted, clock=1×, capacity=2, byte limit=16 MiB.
Модели и профили не считались параллельно. Числа ниже — source due→local
receiver, не только inference и не сеть приложение↔Worker.
| Run | Mean, ms | p95, ms | p99, ms | 125 ms latency gate |
| --- | --- | --- | --- | --- |
| surface-cache A | 82.42 | 120.32 | 134.60 | FAIL |
| surface-cache B | 74.79 | 118.94 | 153.58 | FAIL |
| NVML surface | 75.26 | 125.43 | 181.81 | FAIL |
| без telemetry, diagnostic | 79.04 | 116.55 | 160.31 | FAIL |
| DDRNet interval 50 ms A | 71.93 | 105.19 | 119.18 | PASS только этого окна |
| DDRNet interval 50 ms B | 83.24 | 133.83 | 139.96 | FAIL повторения |
| DDRNet interval 100 ms | 67.02 | 121.52 | 133.27 | FAIL |
| unified Triton / pinned child A | 87.66 | 141.97 | 147.53 | FAIL |
| unified Triton / pinned child B | 83.93 | 133.58 | 151.37 | FAIL |
| unified Triton / native NumPy C | 75.03 | 116.76 | 137.58 | FAIL |
| C + DDRNet CUDA Graphs D | 72.91 | 127.39 | 143.12 | FAIL |
| D + busy-wait events E | 73.42 | 118.41 | 138.19 | FAIL |
### TensorRT: runtime-кандидат, не незаметная замена модели
Pinned DDRNet checkpoint экспортирован в FP32 ONNX и TensorRT 11 с
`--noTF32`, без FP16/INT8. Sigmoid→first-index argmax→uint8 mask включён в
engine: обратно приходит 256 KiB mask, а не 64 MiB logits. DDRNet и RF-DETR
загружаются в один Triton process и исполняются строго последовательно.
Это всё ещё тот же полный граф с online LiDAR/distance/motion/TGS/costmap/policy,
не новая LAB-микропрограмма и не standalone release.
System Python 3.12 в базе не имел PIL/cv2, поэтому сначала точный preprocess
работал в CPU-only Python 3.9 child. Затем fixed KB4 crop/nearest/RGB/255
перенесён в NumPy текущего процесса. Проверка против pinned runner на всех
128 реальных кадрах: **128/128 tensor побитово равны**, общий SHA-256
`a01e97fa342e0b98b233a8fb4485108243406e89a171e1e8513f8b6d1f2f0e63`.
Устранены передача 1,440,000 B BGR в child и 3,145,728 B tensor обратно;
CPU decode child сохранён. Внутренний HTTP к Triton пока остаётся.
Однако PyTorch→TensorRT mask parity не пройдена: 4,009 различий из
33,554,432 пикселей (0.01195%), ни один из 128 кадров не побитово равен.
Functional сравнение выявило **одну смысловую разницу**: sequence 115,
cell index 1900 / grid (15, 2), XY≈(6.975, 0.675) m:
`grass → hard_surface`, `NO_GO → ALLOW_candidate`; обе сцены fresh.
Это не timing/stale-эффект и не NumPy-препроцессинг. Между всеми пятью
TensorRT-вариантами masks/material совпадают 128/128. Detector proposals,
metric observations, tracks, threats, geometry/costmap occupancy и non-timing
TGS совпадают с PyTorch на всех 128 кадрах.
**Решение:** TensorRT остаётся `experimental-unqualified`; default — PyTorch.
Нельзя принять малый pixel mismatch как разрешение ослабить policy.
Ground truth для спорной ячейки здесь не установлена: это доказанное
расхождение, а не доказательство, какая модель права. Во всех запусках
commands/actuation=false; stale scenes не выдают разрешающих actions.
76/128 cloud/pose pairs доступны, 52 unavailable — это ограничение данного
источника/контракта не исчезает от ускорения сегментации.
### Где осталась задержка
В C server statistics, исключая warmup: DDRNet server success mean 25.82 ms,
из них `compute_infer` interval 23.61 ms, input/output 1.31/0.80 ms,
server queue 0.074 ms. HTTP wall mean 28.30 ms. RF-DETR server
`compute_infer` mean 7.51 ms. Эти server intervals — не CUDA-event
доказательство чистого времени GPU kernels.
Отдельный bounded `trtexec` на точном реальном frame 0, 64 непрерывных
повтора, CUDA Graph + spin wait, **без DMA и source pacing**:
GPU mean 2.67048 ms, p99 3.43756 ms; ArgMax ~0.2152 ms.
Синтетический repeated-input контроль дал ~2.65254 ms. Это исключает
основание немедленно переписывать ArgMax, но не квалифицирует потоковый
профиль и не даёт права обещать сотни FPS полного графа.
Следующий диагностический шаг — GPU clocks/power state и CUDA/host timeline
при source-paced паузах, с разделением server/driver/event waits и actual
kernel work. WDDM/context switching — гипотезы, не установленная единственная
причина. Утверждения «всё из-за сети» и «4090 упёрлась в 24 GiB» не подтверждены:
unified runs sampled VRAM peak 1,8561,862 MiB; внешний сетевой участок не измерен.
CUDA Graphs и busy-wait в Triton по отдельным полным пробам p99 не закрыли.
Официальные измерительные определения:
[Triton statistics](https://raw.githubusercontent.com/triton-inference-server/server/r26.06/docs/protocol/extension_statistics.md),
[CUDA optimization config](https://raw.githubusercontent.com/triton-inference-server/common/r26.06/protobuf/model_config.proto).
### Evidence, проверки и состояние
Единый redacted manifest со всеми 12 результатами, hashes, parity и точными
командами C/D/E:
`.runtime/perception-unified-triton-worker-20260902T0227MSK/manifest.json`,
SHA-256 `ed81475e71b7d02af03dbc65ef628065baaec80bf4877b83e80cc6b3d682a330`.
Копия на Worker — одноимённый каталог под
`D:/NDC_MISSIONCORE/runtime/experiments/`. Предыдущие surface/NVML/layered
каталоги сохранены и перечислены в manifest; данные/веса не входят в Git.
| Артефакт | SHA-256 |
| --- | --- |
| unified probe v1 | `3e6d04fd8d2204933320a1b427ee1bebf4152a781fcc0bd2d6fe0d46e00244af` |
| unified probe v2 | `f5225cccd8b164346aea780c0d5960f8114bffc5535d7bc1b55a4f84f54457a8` |
| DDRNet mask ONNX | `595e40442f6829ee56618c88649f2024e56f469bc67a0768f0dda6cfd3fd82e4` |
| DDRNet mask TensorRT plan | `e004e5cdd3daa14628fe52c5bd5418237e24a6423dddde56f82b402fbe536c3b` |
119 focused tests и Ruff изменённых файлов PASS; `git diff --check` PASS.
Исходники диагностического runtime/export/parity и тесты зафиксированы
отдельным commit `34f13ba`; surface optimization — `d9ea7c1`. Push не выполнялся.
Финальные bounded-response checks и явная backend-status метка добавлены
после Worker v2 и проверены локально; они не выдаются за измеренный v2 source.
Full backend/frontend suite/build и model stress на Mac не выполнялись.
Setup-запуски с отсутствующим cv2/PIL не вошли в performance. В первом
unified A был лишний неиспользуемый readonly bind; B и последующие его не имели.
После окна pilot containers=0, штатный Triton running/healthy, оба Observatory
agent running, canonical Mac 8000=200, 8765 закрыт. Legacy perception Worker
вернулся в прежнюю конфигурацию с HTTP 404 restart loop (restart count 2 на
контрольном снимке); эта посторонняя неисправность не объявлена исправленной.
Ollama/Frigate остаются exited/restart=no. Product registry/defaults,
внешний transport, standalone image и motor boundary не переключались.
**Вердикт:** этап 1 частичный. Функциональная оптимизация surface принята,
реальный лишний IPC устранён в экспериментальном Triton path, предел лучше
локализован. Стабильный whole-path latency, TensorRT parity, полный freshness
ABI и standalone/network qualification остаются открытыми.