Optimize WLED processing pipeline and add FPS metrics

- Add numpy-based DDP pixel packing (send_pixels_numpy) and fast send
  path (send_pixels_fast) eliminating per-pixel Python loops
- Move ProcessedLiveStream filter processing to background thread so
  get_latest_frame() returns pre-computed cached result instantly
- Vectorize map_border_to_leds for average interpolation using cumulative
  sums instead of 934 individual np.mean calls (~16ms -> <1ms)
- Batch all CPU work into single asyncio.to_thread call per frame
- Fix FPS calculation to measure frame-to-frame interval (was measuring
  processing time only, reporting inflated values)
- Add Potential FPS metric showing theoretical max without throttling
- Add FPS label to WLED target card properties
- Add fps_potential field to TargetProcessingState API schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 14:43:19 +03:00
parent 7e729c1e4b
commit 8d5ebc92ee
9 changed files with 304 additions and 141 deletions

View File

@@ -4168,6 +4168,7 @@ function createTargetCard(target, deviceMap, sourceMap) {
</div>
<div class="stream-card-props">
<span class="stream-card-prop" title="${t('targets.device')}">💡 ${escapeHtml(deviceName)}</span>
<span class="stream-card-prop" title="${t('targets.fps')}">⚡ ${settings.fps || 30}</span>
<span class="stream-card-prop stream-card-prop-full" title="${t('targets.source')}">📺 ${escapeHtml(sourceName)}</span>
</div>
<div class="card-content">
@@ -4181,6 +4182,10 @@ function createTargetCard(target, deviceMap, sourceMap) {
<div class="metric-value">${state.fps_target || 0}</div>
<div class="metric-label">${t('device.metrics.target_fps')}</div>
</div>
<div class="metric">
<div class="metric-value">${state.fps_potential?.toFixed(0) || '-'}</div>
<div class="metric-label">${t('device.metrics.potential_fps')}</div>
</div>
<div class="metric">
<div class="metric-value">${metrics.frames_processed || 0}</div>
<div class="metric-label">${t('device.metrics.frames')}</div>

View File

@@ -130,6 +130,7 @@
"device.stopped": "Processing stopped",
"device.metrics.actual_fps": "Actual FPS",
"device.metrics.target_fps": "Target FPS",
"device.metrics.potential_fps": "Potential FPS",
"device.metrics.frames": "Frames",
"device.metrics.errors": "Errors",
"device.health.online": "WLED Online",

View File

@@ -130,6 +130,7 @@
"device.stopped": "Обработка остановлена",
"device.metrics.actual_fps": "Факт. FPS",
"device.metrics.target_fps": "Целев. FPS",
"device.metrics.potential_fps": "Потенц. FPS",
"device.metrics.frames": "Кадры",
"device.metrics.errors": "Ошибки",
"device.health.online": "WLED Онлайн",