3d8b81c9f6
`make all` собирал и examples/, из-за чего цикл «правка libc -> проверка» упирался в mdview (компилируется минутами) и ничего нового про libc не показывал. Регресс ловит разжирение библиотеки, а для этого хватает мелких tests/ — каждый тянет свой кусок libc и пересобирается за секунды. - `make all` = tools lib tests; examples собираются явно (`make examples`, и как зависимость `make floppy`); - size_check.py смотрит только tests/*. Эталон принят заново. Разбор расхождения, чтобы оно не выглядело необъяснённым: эталон стоял с 30 июля (0280b05), а libc менялась 1 и 3 августа (b56f2b4kbd_raw_poll,1f16e8ffake shift) — _irq_tramp вырос 267 -> 336 Б и не был перебазирован, отсюда +33 Б у всех, кто линкует трамплин (cbl*, irqtest, rt_test), и +22 у gfx_dbuf (gfx_set_idle_hook в libbgi из того же KBD-1). Текущий фикс BUG-KBD-5 вернул 36 Б из этих 69. Заодно выкинуты мёртвые строки эталона (rpgprof/rpgwalk/scroll/space — их давно нет в APPS, mdview/mdview2 — теперь вне регресса). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
size_check.py — размерный регресс-тест: сравнение _CODE тестов с эталоном
|
|
docs/size_baseline.tsv.
|
|
|
|
Использование:
|
|
python3 toolchain/size_check.py # сверка с эталоном
|
|
python3 toolchain/size_check.py --update # перезаписать эталон
|
|
|
|
Логика: собираем _CODE из .map каждой программы под tests/, сравниваем с
|
|
эталоном. Любое отличие печатается; выход 1 — если есть РОСТ (случайное
|
|
разжирение libc), 0 — если только уменьшения/без изменений. Новые
|
|
программы (нет в эталоне) — предупреждение, добавить через --update.
|
|
Запускать после `make all`.
|
|
|
|
ТОЛЬКО tests/, без examples/: регресс ловит разжирение libc, а для этого
|
|
хватает мелких тестов — каждый тянет свой кусок библиотеки и пересобирается
|
|
за секунды. Крупные приложения (examples/mdview компилируется минутами)
|
|
не показывают ничего сверх этого и лишь удлиняют цикл, поэтому и из
|
|
`make all` они убраны (см. корневой Makefile).
|
|
"""
|
|
|
|
import glob
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
BASELINE = os.path.join(ROOT, "docs", "size_baseline.tsv")
|
|
|
|
|
|
def collect():
|
|
"""Имя программы → размер _CODE (байт) по свежим .map."""
|
|
sizes = {}
|
|
pats = [
|
|
os.path.join(ROOT, "tests", "*", ".sprinter-cc-*", "*.map"),
|
|
]
|
|
for pat in pats:
|
|
for map_path in glob.glob(pat):
|
|
name = os.path.splitext(os.path.basename(map_path))[0]
|
|
# .map должен лежать в своей папке .sprinter-cc-<name>
|
|
if os.path.basename(os.path.dirname(map_path)) != ".sprinter-cc-" + name:
|
|
continue
|
|
with open(map_path, encoding="utf-8", errors="replace") as f:
|
|
for line in f:
|
|
m = re.match(r"^_CODE\s+([0-9A-Fa-f]+)\s+([0-9A-Fa-f]+)", line)
|
|
if m:
|
|
sizes[name] = int(m.group(2), 16)
|
|
break
|
|
return sizes
|
|
|
|
|
|
def load_baseline():
|
|
base = {}
|
|
if os.path.exists(BASELINE):
|
|
with open(BASELINE) as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
name, size = line.split("\t")
|
|
base[name] = int(size)
|
|
return base
|
|
|
|
|
|
def save_baseline(sizes):
|
|
with open(BASELINE, "w") as f:
|
|
f.write("# Эталон размеров _CODE (байт); обновление: "
|
|
"python3 toolchain/size_check.py --update\n")
|
|
for name in sorted(sizes):
|
|
f.write(f"{name}\t{sizes[name]}\n")
|
|
|
|
|
|
def main():
|
|
update = "--update" in sys.argv
|
|
sizes = collect()
|
|
if not sizes:
|
|
print("size_check: .map не найдены — сначала `make all`")
|
|
return 2
|
|
|
|
if update:
|
|
save_baseline(sizes)
|
|
print(f"size_check: эталон обновлён ({len(sizes)} программ) → "
|
|
f"{os.path.relpath(BASELINE, ROOT)}")
|
|
return 0
|
|
|
|
base = load_baseline()
|
|
if not base:
|
|
print("size_check: эталона нет — создать: size_check.py --update")
|
|
return 2
|
|
|
|
grew = 0
|
|
for name in sorted(set(sizes) | set(base)):
|
|
new, old = sizes.get(name), base.get(name)
|
|
if new is None:
|
|
print(f" {name}: исчез из сборки (был {old} Б)")
|
|
elif old is None:
|
|
print(f" {name}: НОВЫЙ ({new} Б) — добавить в эталон (--update)")
|
|
elif new != old:
|
|
mark = "РОСТ" if new > old else "ок, меньше"
|
|
print(f" {name}: {old} -> {new} ({new - old:+d} Б) [{mark}]")
|
|
if new > old:
|
|
grew += 1
|
|
if grew:
|
|
print(f"size_check: {grew} программ(ы) ВЫРОСЛИ — проверить правки libc")
|
|
return 1
|
|
print(f"size_check: OK ({len(sizes)} программ, роста нет)")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|