Профиль каскада плит ур.13 к.23: три рабочих документа по фазам

Контрольный замер перед оптимизацией (задача OPT-BLIT требовала начать с
него, а не с правок).  Сцена: старт уровня 13, комната 23, шесть плит
сыплются с потолка вразнобой.

Пик логического кадра — 1 437 150 тактов при растровом кадре 430 000, то
есть 5-6 растровых кадров вместо трёх.  По секциям (бюджет 400 000):
синяя 142 830 (в норме), зелёная до 805 000, циан до 632 000.

Что нашлось (всё подтверждено зондами, не гипотезы):

  RDA_CEIL      дрожащая плита-потолок     48 658 x до 6 = 292 000
  RDA_CEIL_GONE запечь колодец            251 023 x до 2 = 619 000
  RD_FLOOR      щебень на месте посадки   198 259 x до 2 = 397 000

Внутри RDA_CEIL: heal 8 491 + draw_tile 39 029, а блитов в этом draw_tile
всего 1,17 на тайл (15-16 тыс.) — то есть ~23 700 тактов чистых накладных.
Подсчёт asm сходится до процентов: у draw_tile 26-байтовый стековый кадр и
513 обращений (ix), при ~46 замеренных тактах на обращение это те же
~23 600.  У blit_b_clip — 22 Б кадра и 211 (ix).

Разбор одного pop_blit_b (157 замеров быстрого пути): atlas_image+w0_map
1 086, ядро libbgi 10 422, pop_cd_touch 4 502 (28%!), unmap+возврат 264.
В mob_render эти три pop_cd_touch к тому же ИЗБЫТОЧНЫ — коридор куска уже
помечен одним вызовом в pop_loose_mob_tick: 81 000 тактов в кадре впустую.

Итог по пиковому кадру: блиты 488 100 (34%), из них «железный» минимум
пикселей ~150 000; остальные ~1 150 000 (80% кадра) — наши накладные.
Узкое место не передача пикселей, а 16-битная арифметика в IX-кадрах.

Ответ на вопрос про uint8_t: просканированы все 109 .atl и наборы
TITLE/PV — максимум по игровому кадру 56x63 (kid3), фон 48x63, спрайты
комнаты принцессы 49x60.  Шире 255 только восемь полноэкранных подложек
титров/сюжета (три 320x200 и пять 256..272), и все рисуются раз на экран.
Значит горячий путь переводится на байтовые габариты целиком, а подложкам —
отдельный банк / прямой libbgi (решение пользователя).

Документы (решение пользователя — вести работу по фазам, чтобы результаты
не теряись между сессиями):

  docs/perf_l13_room23.md  сцена, рецепт воспроизведения, зонды, канал clog,
                           сводка по кадрам, габариты спрайтов
  docs/perf_green_phase.md зелёная фаза: раскладка, позиции G1..G6, журнал
  docs/perf_cyan_phase.md  циан: раскладка, позиции C1..C7, журнал

Отдельно записан рецепт воспроизведения: сцена повторяется ТОЛЬКО
перезапуском программы (ESC → зонды → roomtest).  Возврат в комнату не
годится — упавшая плита уходит в страницу уровня насовсем; рестарт уровня
не годится — гряда доваливается заочно через trob комнаты 17, пока телепорт
уносит Кида; запись отладчиком на бегущей машине затирается тем же trob.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 12:22:21 +03:00
parent c312e4a043
commit babd40bc84
5 changed files with 612 additions and 2 deletions
+26 -1
View File
@@ -928,6 +928,29 @@ HP/минуты, номера «особых» комнат и уровней (
## OPT-BLIT — цена отрисовки: чистка кодогена (СЛЕДУЮЩАЯ СЕССИЯ)
> **2026-08-17: контрольный замер снят, задача разложена по фазам.**
> Работа теперь ведётся в трёх документах, которые живут между сессиями —
> туда же писать результаты каждой правки:
>
> - [`../docs/perf_l13_room23.md`](../docs/perf_l13_room23.md) — сцена
> (каскад 6 плит, ур. 13 комната 23), рецепт воспроизведения, зонды, канал
> `clog`, сводка по кадрам, разбор габаритов спрайтов;
> - [`../docs/perf_green_phase.md`](../docs/perf_green_phase.md) — ЗЕЛЁНАЯ
> фаза: пик **805 000** при бюджете 400 000; позиции G1..G6;
> - [`../docs/perf_cyan_phase.md`](../docs/perf_cyan_phase.md) — ЦИАН фаза:
> пик **632 000** при бюджете 400 000; позиции C1..C7.
>
> Порядок работ: **G1** (окно клипа для запечки, −250..400 тыс.) → **G2**
> (расколоть `draw_tile` + лист для ряда −1) → **C1** (убрать избыточный
> `pop_cd_touch` в `mob_render`, 81 тыс.) → **G3/C3** (`blit_b_clip` на
> байтовые габариты) → **C4** (разобрать `pop_char_fore(KID)`: 1 722 → 150 978).
>
> Синяя секция (**142 830**) в бюджет укладывается — не трогаем.
> Ответ на вопрос про `uint8_t`: горячий путь можно переводить целиком,
> максимум по всем игровым атласам **56×63**; шире 255 только восемь
> полноэкранных подложек титров/сюжета (320×200 и т. п.), и они рисуются раз
> на экран — им отдельный банк / прямой libbgi.
Открыто 2026-08-13 по итогам разбора зелёного блока. Контекст и все замеры
— в memory `blit_cost_model` и `sdcc_z80_stack_locals_hot_loop`, протокол
разбора — в коммитах `f89b7dd` / `b27b313` / этом.
@@ -994,7 +1017,9 @@ grep -n "pop.*\n.*pop.*\n.*push" ... # чтение спилла
- Пакетная пометка `pop_cd_touch` (`pop_cd_batch_begin/end`, скобка в
`draw_tile`) — сделана, но выигрыш замером НЕ подтверждён: в захваченных
кадрах скобка не срабатывала (блиты шли из холодной отрисовки комнаты).
Переснять на кадрах ЗАПЕКАНИЯ.
Переснять на кадрах ЗАПЕКАНИЯ. **2026-08-17: цена НЕпакетного вызова
замерена — 4 502 такта, 28 % всей цены блита; в `mob_render` он к тому же
избыточен (см. C1).**
- Снять временную оснастку: `pop_dbg_m9..m16`, `pop_dbg_b1..b6`,
`pop_dbg_wh`, `pop_dbg_kind`, `pop_dbg_rdmax*`, `mame/v306/run_bridge_log.sh`.
- Цель по кадру не достигнута: зелёный пик был 792 012 при цели 400 000.