# 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.