perf: zone CPU profiler (PerfLog) + phase-restructured CPU spectrum render

Инструментация (ВРЕМЕННАЯ, не мержить в main):
- PerfLog.pas: зонные таймеры, отчёт раз в 5с в stderr (core% = доля ядра),
  EWSDR_PERF=0 выкл, EWSDR_PERF_FILE=путь — дублировать в файл
- Замеры // PERF: сеть (DDC IQ/wideband), Pluto (rx_conv/tx_resamp/tx_fill),
  DSP (push_iq/fexchange/slices/tx), аудио, UI (тики/draw/paint/gl_swap,
  разбивка draw_spectrum по фазам)
- doc/PERF_PROFILING.md: карта зон, методика, выводы

Оптимизация CPU-рендера спектра (по результатам замеров на эфире):
диагноз — дорога не пиксельная работа, а чередование raw(ScanLine)/
canvas(QPainter) доступа к битмапу на Qt6 (~6 переходов за кадр, каждый
синкает весь битмап; полоса фильтра в тысячи пикселей стоила 4x дороже
полного memcpy кадра). DrawSpectrum перестроен в фазы calc->raw->canvas->raw
(2 перехода): FillBandRaw вместо Canvas.FillRect, DrawSliceFilterMarkers
разделён на raw-полосы + canvas-линии, композиты флагов и альфа-OR в
финальной raw-фазе. Кадр 8.3мс -> 6.1мс; spec_bands 1.87мс -> 0.03мс.
Альфа-OR проход на Qt6 подтверждён нужным (без него canvas-пиксели теряют
альфу и пропадают при блите), сам цикл ~0.08мс — оставлен; тумблер
EWSDR_ALPHA_FIX=0 только для экспериментов. Кисть перед AGC-подписями
теперь ставится явно (была остаточной после перестройки фаз).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 22:07:36 +03:00
co-authored by Claude Fable 5
parent b2fa2756cf
commit 0b4d126dac
12 changed files with 692 additions and 83 deletions
+7 -1
View File
@@ -16,7 +16,8 @@ interface
uses
Classes, SysUtils, Graphics, Controls, Math,
OpenGLContext, GL,
AppTheme, WaterfallView;
AppTheme, WaterfallView,
PerfLog; // ВРЕМЕННО (perf/cpu-profiling): зонные CPU-таймеры
type
TWaterfallViewOpenGL = class(TWaterfallView)
@@ -461,9 +462,11 @@ procedure TWaterfallViewOpenGL.PaintWaterfall(Sender: TObject);
var
W, H: Integer;
R, G, B: GLFloat;
T0, Tsw: Int64; // PERF
begin
if Sender is TOpenGLControl then FGLControl := TOpenGLControl(Sender);
if (FGLControl = nil) or (not FGLControl.MakeCurrent) then Exit;
T0 := PerfNow; // PERF
W := FGLControl.Width;
H := FGLControl.Height;
if (W <= 0) or (H <= 0) then Exit;
@@ -491,7 +494,10 @@ begin
end;
DrawTextureWrapped(W, H);
DrawMarker(W, H);
Tsw := PerfNow; // PERF
FGLControl.SwapBuffers;
PerfAdd(pzUiGlSwap, Tsw); // PERF: SwapBuffers (в т.ч. ожидание vsync)
PerfAdd(pzUiPaintWaterfall, T0); // PERF: GL-кадр водопада (включая SwapBuffers)
end;
procedure TWaterfallViewOpenGL.SetTheme(const T: TAppTheme);