T27.AI

Блог

С минуты до секунды: куда уходило время сборки t27 и куда уходит сейчас

2026-10-11 · 8 мин чтения

[замеры на одном 8-ядерном Mac, нагрузка на котором менялась за ночь; пары сняты при одинаковой нагрузке] Один ночной цикл замерил все места, где t27 собирает и ждёт, и исправил то, на что указали цифры. Тёплый t27c frontier ускорился с 55-68 с примерно до 0,9 с, неизменный битстрим находится за 0,22-0,39 с вместо 4,3-8,9 с, запуск на плате после одобрения больше не собирает сначала, а прогон корпуса, который CI делает на каждом pull request, сократился с 221-257 с до 108-140 с. Почти всё прежнее время уходило на пересчёт того, что не менялось, и на поочерёдное выполнение независимой работы. Что осталось: около 2 с на спеку в перелинковке zig, 27 с nextpnr на правку логики, около 14 с загрузки платы и гейт C-заголовков на 72 с.

Титульная карточка статьи, иллюстрации пока нет: С минуты до секунды: куда уходило время сборки t27 и куда уходит сейчас
Открыть титульную карточку в исходном размере
#t27#Measurement#FPGA#Verification

В ночь с 10 на 11 октября один цикл прошёл по всем местам, где t27 что-то собирает и заставляет автора ждать, замерил каждое и поменял то, на что указали замеры. Тёплый t27c frontier ускорился примерно с минуты до долей секунды, неизменный битстрим находится за четверть секунды вместо четырёх-девяти, а прогон корпуса, который CI делает на каждом pull request, занимает половину прежнего времени. Тринадцать pull request, все смержены; журнал цикла — t27#8737.

Секунды ожидания, до и после (логарифмическая шкала)былостало0,1 с1 с10 с100 с1000 сfrontier, тёплый551frontier после пересборки t27c556,3watch: правка общей спеки (16 перепроверок)34,513,9silicon: дизайн не менялся4,30,39t27c suite (локально)394185CI: шаг corpus ratchet221140
Секунды до и после для шести путей, в логарифмической шкале. Каждая пара — осторожный край измеренного диапазона: самое медленное «после» против самого быстрого «до». Замеры на одном 8-ядерном Mac, нагрузка на котором за ночь менялась примерно от 3 до 140.

Куда уходило время

Почти никуда на новую работу. Оно уходило на пересчёт того, что не менялось с прошлого запуска, и на то, что независимые куски работы выполнялись один за другим. Каждое исправление ниже — про одно из двух.

ГдеБылоСталоЧто изменилосьPR
t27c frontier, тёплый55-68 с~0,9 сЧетыре хэша сгенерированного кода спеки берутся из кэша с ключом по самой спеке, всем её импортам и байтам бинарника t27ct27#8741
t27c frontier после пересборки t27c55-68 с6,3 сКэш сначала заполняют 8 воркеров; решения затем принимаются по порядку, ровно как раньшеt27#8847
frontier --watch в простое33% ядра3%Каждый взгляд смотрит stat файлов и ничего не читает, если stat не сдвинулсяt27#8825
frontier --watch, правка спеки, которую импортируют 16 других34,5 с13,9 сПерепроверки идут параллельно; спеки с одинаковым именем файла остаются на одном воркереt27#8856
t27c silicon, дизайн не менялся4,3-8,9 с0,22-0,39 сХэши инструментов (среди них chipdb на 333 МБ) берутся из кэша по stat файла; Python-пакеты читаются из venv вместо pip freezet27#8808, t27#8814
Запуск на плате после /bench approveсначала сборка, 30-550 столько загрузкаБенч-агент собирает битстрим, пока задача ждёт одобрения, не трогая кабельt27#8797
t27c suite --corpus-only394-498 с167-185 сОколо 13 000 запусков по спекам идут по 8 сразу; результаты собираются в порядке файловt27#8837, t27#8840, t27#8845
Тот же шаг в CI221-257 с108-140 сТо же изменение, замер на раннерахt27#8837

Большую часть сделали три правила

  1. Ключ кэша — всё, что может изменить результат, и ничего больше. Сгенерированный код спеки зависит от её импортов, потому что константы подставляются через них, — поэтому ключ держит всё замыкание импортов. И сам бинарник: любая пересборка t27c — это новый генератор. Ключ, который называет слишком мало, отдаёт неверные ответы; ключ, который называет лишнее, например коммит постороннего чекаута, выбрасывает верные.
  2. Сначала дешёвая проверка, потом дорогая. stat файла стоит микросекунды; прочитать и хэшировать 333 МБ — секунды. И watch, и кэш хэшей сначала смотрят stat и читают только то, что сдвинулось, причём stat снимается до чтения, так что правка, пришедшая во время чтения, будет замечена в следующий раз.
  3. Независимую работу — параллельно, и доказать, что ничего не изменилось. Каждая параллельная фаза собирает результаты в исходном порядке, и каждая прогнана двумя способами, с T27_SUITE_JOBS=1 и по умолчанию: вывод ошибок совпал байт в байт, JSON-сводки — кроме полей времени, 259 падений оба раза.

Дефекты, найденные по пути

Куда время уходит сейчас

ПутьСейчасКуда уходитСледующий шаг
Правка спеки → её вердикт~2 с на спекуZig компилирует и заново линкует тестовый бинарник при каждом запуске; сам t27c тратит 0,03 сУбрать перелинковку: около 0,2-0,3 с на спеку. Это меняет тест-раннер, который называет каждая печать, поэтому нужна одна полная перепечать
Правка логики → битстрим36,7 с (ternary_link)nextpnr 27,3 с: трассировка клоков ищет путь BSCAN → BUFG по всему кристаллу, а роутер настраивает каждый провод 200T, прежде чем развести несколько тысячПатч с побайтно тем же результатом ускоряет трассировку клоков в 1,8-5 раз (t27#8754); place-and-route, который остаётся в памяти, убрал бы настройку
Битстрим → плата~13-15 с9,73 МБ по JTAG на частоте по умолчаниюБолее быстрый JTAG на кабеле HS2 — около 3 с; нужен тест на плате
Одобрение → старт запускадо 60 сБенч-агент опрашивает раз в минутуОпрос раз в 15 с — примерно на 180 вызовов GitHub API в час больше
t27c suite~170 сГейт C-заголовков: 72 с cc -fsyntax-only на каждую спеку при каждом прогонеКэшировать его результаты по содержимому (t27#8900)

Каждый следующий шаг в этой таблице меняет что-то за пределами цикла: то, что записывает каждая печать, то, что уходит на плату, бюджет GitHub API, или файл, который проект открывает для рукописного кода только с разрешения владельца. Ни один из них не сделан без владельца.

Проверьте сами

tri hot прогоняет каждый горячий путь один раз для разогрева, затем один раз с замером, и пишет OVER, если путь вышел за бюджет или запустился и упал. Это регрессионный тест для кэшей выше, и цикл теперь начинает с него каждый тик.

$ T27_OPENXC7=$HOME/t27/build/fpga/openxc7 tri hot
OK       frontier, warm: 856 ms (budget 5000 ms)
OK       silicon, reuse hit: 242 ms (budget 2000 ms)

Чего это не решает

Пруфы

Поработаем вместе

Хотите так же проверить собственный дизайн?

Я аудирую RTL и строю независимые побитово точные модели, затем провожу результат через синтез и, когда это полезно, проверяю на плате Artix-7. Первый модуль проверки — бесплатно.