mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
Canvas на битмапе кадра больше не используется вообще (кроме редкого ADC-overload пути с восстановлением альфы) — убраны все raw<->canvas переходы, каждый из которых синкал весь битмап на Qt6 (~2мс): - RawBegin/RawEnd: прямой доступ к пикселям через RawImage.Data + BytesPerLine (bottom-up DIB win32 учтён отрицательным шагом) - RawVLine/RawHLine (с пунктиром), RawFillRect, RawTriangleDown, RawCurve (кривая = связные вертикальные сегменты по колонкам) - кэш текстовых масок (TRawTextMask, LRU 48): строка рендерится canvas'ом один раз белым-на-чёрном в свой мини-битмап, блитится raw с цветом; все тексты кадра теперь Courier New - конвертированы: маркер (метка без случайной цветной плашки), бикон- маркеры, буквы слайсов, слайс-линии, AGC (пунктир 4/2 и 1/2, подпись с фоном SpecFilter как раньше), края/VFO/TX-курсоры с треугольниками - пофреймовый альфа-OR проход удалён: альфа чинится один раз в кэше СЕТКИ после ребилда (canvas-текст там), кадр наследует её через memcpy Дворд-блендеры (два 16-бит лейна на умножение, /256 вместо /255, расхождение <0.4%) вместо побайтовых с div 255: - BandPlanOverlay.CompositeStrip (~1мс -> ~0.2мс) - SampleRateOverlay.CompositeCache (per-px альфа) - VfoOverlay.BlendBitmapKey (keyed-магента дворд-сравнением) - SpectrumView.DrawSpectrumGradient (source-лейны 1 раз на строку, ~1.6мс -> ~0.8мс) Порог перестройки бэндплана: полпикселя вместо 1 Гц (на QO-100 с decoder-lock центр подтюнивается непрерывно — был canvas-ребилд полоски каждый кадр). Композиты внутри raw-лока (их BeginUpdate вложенные). PerfLog: зона ui.composites отделена от ui.spec_alpha (=RawEnd). Замер на эфире (Pluto, 576k, 52fps): кадр 8.3мс -> 1.67мс (5x), со слайсом 2.1-2.3мс; UI-поток ~45% -> ~26% ядра, из них 15% — блиты paint_spectrum/paint_waterfall (потолок Qt6-вывода). Визуально проверено. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
5.7 KiB
Markdown
86 lines
5.7 KiB
Markdown
# CPU-профилирование (ветка perf/cpu-profiling)
|
||
|
||
Временная инструментация для поиска самых дорогих по CPU мест.
|
||
Модуль `PerfLog.pas` + зонные замеры, помеченные комментарием `// PERF`.
|
||
**Не мержить в main** — после выводов ветка выбрасывается или чистится.
|
||
|
||
## Как запустить
|
||
|
||
```sh
|
||
lazbuild -B --ws=qt6 ewsdr.lpr
|
||
./bin/x86_64-linux/ewsdr-debug # отчёт в stderr каждые 5 с
|
||
EWSDR_PERF_FILE=/tmp/ewsdr-perf.log ./bin/x86_64-linux/ewsdr-debug # + в файл
|
||
EWSDR_PERF=0 ./bin/x86_64-linux/ewsdr-debug # выключить замеры
|
||
```
|
||
|
||
## Как читать отчёт
|
||
|
||
```
|
||
[PERF] ===== interval 5.00 s =====
|
||
[PERF] zone calls c/s avg_us max_us total_ms core%
|
||
[PERF] dsp.push_iq 2929 586 55.1 412 161.4 3.2
|
||
```
|
||
|
||
`core%` — доля одного ядра CPU, потраченная в зоне за интервал. Это главная
|
||
колонка: сортируем по ней и смотрим, куда уходит время. `max_us` показывает
|
||
выбросы (джиттер), `avg_us` — стоимость одного вызова.
|
||
|
||
Зоны вложены: `dsp.push_iq` включает `dsp.spectrum0` + `dsp.fex_main` +
|
||
`dsp.audio_cb` + `dsp.slices`; `dsp.slices` включает `dsp.slice_fex` и
|
||
`audio.write` слайсов; `ui.spectrum_tick` включает `ui.draw_*`, `ui.slice_flags`,
|
||
`ui.vfo_overlay`, `ui.web_push`; `dsp.tx_block` включает `pluto.tx_resamp`
|
||
(SendDUCIQ зовётся из FOnTXIQ). Разница «родитель минус дети» = ненаблюдаемый
|
||
остаток (циклы копирования, мелочь).
|
||
|
||
Бэкенды: на openHPSDR работает `net.*`, на Pluto вместо них `pluto.*`
|
||
(RX-поток Pluto конвертит iio-буфер и кладёт в ту же DSP-очередь).
|
||
|
||
## Карта зон
|
||
|
||
| Зона | Поток | Что меряет |
|
||
|---|---|---|
|
||
| net.ddc_iq | receive | копия IQ-пакета + постановка в DSP-очередь (openHPSDR) |
|
||
| net.wideband | receive | сборка wideband-кадра (openHPSDR) |
|
||
| pluto.rx_conv | Pluto RX | конверсия iio-буфера int16→24bit BE + отдача в DSP-очередь |
|
||
| pluto.tx_resamp | TX DSP | полифазный интерполятор 192k→device-rate + 24→16 + FIFO |
|
||
| pluto.tx_fill | Pluto TX | наполнение iio-буфера из FIFO (без блокирующего push) |
|
||
| dsp.push_iq | DSP | весь путь пакета: декод 24-бит, аккумуляция, всё ниже |
|
||
| dsp.spectrum0 | DSP | скармливание display-блока анализатору WDSP |
|
||
| dsp.fex_main | DSP | fexchange0 главного RX-канала |
|
||
| dsp.audio_cb | DSP | маршрут RX-аудио (web/радио/звуковуха) |
|
||
| dsp.slices | DSP | fan-out всех слайсов целиком |
|
||
| dsp.slice_fex | DSP | fexchange0 одного слайс-канала |
|
||
| dsp.tx_block | TX DSP | TX-блок целиком |
|
||
| disp.get_pixels | display | GetPixels спектр+водопад |
|
||
| audio.write | DSP | запись в PortAudio ring (главный + все слайсы) |
|
||
| ui.spectrum_tick | UI | кадровый таймер целиком |
|
||
| ui.meter_tick | UI | 10 Гц метр-таймер |
|
||
| ui.draw_spectrum / ui.draw_waterfall | UI | CPU-рендер кадра в битмап |
|
||
| ui.paint_spectrum / ui.paint_waterfall | UI | блит на канву (Qt6) или GL-кадр со SwapBuffers |
|
||
| ui.slice_flags | UI | позиционирование + S-метры слайс-флагов |
|
||
| ui.vfo_overlay | UI | обновление главного VFO-флага |
|
||
| ui.wideband_paint | UI | кадр wideband-панорамы |
|
||
| ui.web_push | UI | WebAdapter.PushState |
|
||
| ui.spec_grid…spec_alpha | UI | разбивка ui.draw_spectrum (full-raw рендер): grid=ребилд+memcpy сетки, bands=raw-заливки полос, curve=точки+градиент, overlays=raw-линии/текст/кривая/маркеры, composites=бэндплан/панель/флаги, alpha=RawEnd/EndUpdate (+редкий canvas-путь ADC overload) |
|
||
| ui.gl_swap | UI | SwapBuffers отдельно — включает ожидание vsync, НЕ чистый CPU |
|
||
|
||
## Чего зоны НЕ видят
|
||
|
||
- Общесистемное: Qt event loop, композитор, PortAudio callback-поток
|
||
(сам колбэк не инструментирован — он читает ring без работы).
|
||
- Для сравнения с общим CPU процесса: `pidstat -p $(pidof ewsdr-debug) 5 -t`
|
||
(покажет и раскладку по потокам — сопоставляется с зонами по потокам).
|
||
|
||
## Методика измерений
|
||
|
||
Снять отчёты в фиксированных сценариях по ~30 с каждый и сравнить core%:
|
||
|
||
1. RX, 1 слайс (только VFO A), спектр CPU-рендер.
|
||
2. То же + OpenGL (`ewsdr-debug --opengl` или как включается GL-свитч).
|
||
3. RX + 3–4 слайса (Ctrl+ЛКМ) — рост dsp.slices / dsp.slice_fex / audio.write.
|
||
4. Разные FPS дисплея и размеры FFT.
|
||
5. Открытый web-клиент (ui.web_push, dsp.audio_cb с Opus).
|
||
6. Wideband включён/выключен (openHPSDR).
|
||
7. Pluto: разные sample rate (576k/1536k/3072k) — pluto.rx_conv и dsp.push_iq
|
||
растут линейно с рейтом; TX (MOX/TUN) — pluto.tx_resamp vs dsp.tx_block.
|