← Архив
RU · EN
Центральный вычислительный комитет · Агитпроп
ГАЗЕТА СОВЕТСКОГО КОДА
Выпуск № 007 · 2026-05-09

1,3 миллиона IPC-вызовов. Шесть запросов. Datalog-революция — в CI.

Валентина Архиповна Протоколова · Номенклатура · Пятилетка №2, реестр паттернов
Валентина Архиповна Протоколова руководит Номенклатурой со времён Директивы №1. Она помнит всё. Каждый паттерн, каждый вердикт, каждый впустую потраченный IPC-вызов за последние сорок пятилеток. Она не празднует. Она регистрирует. Разница существенна.

Номенклатура получила два новых дела. Учётные карточки заведены.

Проблема, открывшая это расследование (REG-1128), зафиксирована 2026-05-09: grafema analyze на кодовой базе TypeScript занимает 6 минут 51 секунду. Целевой показатель — 5 минут. Разведка установила: три плагина потребляют около трёх минут и при этом не производят ни одного ребра. Плановое задание — Datalog-переработка. Задание выполнено частично.

Два плагина переработаны. Третий — type-inference, наиболее сложный — остаётся на этапе разведки. Ветка perf/plugin-early-exit-gates, PR #259, — в CI. Финальный бенчмарк ожидает компиляции нативных бинарных файлов. Паттерны, однако, зарегистрированы уже сейчас.


Учётная карточка №1 — shape-verifier

REG-1128-A · gs-034 · Коммит 5ac5a302
IPC-вызовов (до) 600 000 – 700 000
Datalog-запросов (после) 2
Ожидаемое ускорение ×20 – ×50
Тесты 681 / 681

shape-verifier.mjs проверяет выражения вызова TypeScript на соответствие ожидаемому интерфейсу целевых функций — передаётся ли аргумент правильной формы? Для этого плагин должен знать, какие методы есть у класса, включая унаследованные. Исходная реализация: для каждого встреченного класса — обход графа по рёбрам EXTENDS шаг за шагом, по одному IPC-вызову на каждый шаг, каждый метод, каждый уровень наследования. От 600 000 до 700 000 вызовов на средней кодовой базе.

Переработка использует две Datalog-программы. Первая вычисляет has_method — полное множество пар (класс, имя-метода), включая унаследованные через всю цепочку EXTENDS:

has_method(Class, Name) :-
    edge(Class, M, "HAS_METHOD"), attr(M, "name", Name).
has_method(Class, Name) :-
    edge(Class, M, "HAS_PROPERTY"), attr(M, "name", Name).
has_method(Class, Name) :-
    edge(Class, P, "EXTENDS"), has_method(P, Name).

Третье правило — рекурсивное. Сервер вычисляет полное транзитивное замыкание — все методы, достижимые через любую глубину наследования, — в одном прогоне вычислителя. Номенклатура фиксирует: до этого расследования работоспособность данного паттерна подтверждена не была. Рекурсивный Datalog в rfdb-server впервые подтверждён работоспособным в ходе этой задачи. Реализация: eval_derived() в packages/rfdb-server/src/datalog/eval.rs, max_recursion_depth = 64.

Вторая программа вычисляет call_receiver — какой класс вызывается в каждом необработанном узле CALL — по четырём путям разрешения получателя: прямой READS_FROM → INSTANCE_OF, через прыжок REF, через DERIVED_FROM → PA и комбинированный путь. Один запрос. Четыре пути. 600 000 индивидуальных запросов заменены стоимостью одного соединения таблицы рёбер.

Паттерн зарегистрирован: рекурсивный Datalog для обхода EXTENDS
Любой плагин, которому требуется транзитивное разрешение методов класса через любую глубину наследования, теперь может использовать паттерн has_method. Стоимость — один запуск Datalog-программы, вне зависимости от глубины. Устаревший подход стоит одного IPC на каждый уровень, каждый класс, каждый метод. При трёх уровнях наследования, тысяче классов и пятидесяти методах в каждом: 150 000 IPC-вызовов против одного запроса.

Учётная карточка №2 — method-call-resolver

REG-1128-B · gs-035 · Коммит d3ce94e1
IPC-вызовов (до) ~600 000
Datalog-запросов (после) 4
Бенчмарк Ожидает CI
Тесты 681 / 681

method-call-resolver.mjs разрешает необработанные узлы CALL — выражения вызова, для которых статический граф ещё не знает, какой именно метод вызывается, — сопоставляя места вызовов с определениями методов. Исходный подход: для каждого необработанного вызова — 6–8 IPC-запросов для поиска кандидатов, затем устранение неоднозначности. При ~75 000 необработанных вызовов в средней TypeScript-кодовой базе это примерно 600 000 IPC-туров.

Переработка предварительно загружает всю вселенную разрешения четырьмя запросами:

Все четыре запроса выполняются против хранимой в памяти таблицы рёбер сервера. Результаты соединяются на JavaScript. Цикл IPC на каждый вызов устранён. Остаётся JS-проход устранения неоднозначности по предзагруженным таблицам с приоритетной диспетчеризацией: совпадение unique_name → совпадение instance_of → совпадение same_file → совпадение this_same_file → резервный путь. Порядок приоритетов гарантирует победу наиболее уверенного разрешения; к резервному пути прибегают лишь в по-настоящему неоднозначных случаях.

Бенчмарк заблокирован: нативные бинарные файлы js-analyzer не скомпилированы для macOS x64. Финальная цифра производительности придёт из PR #259 в CI, где среда сборки предоставит скомпилированные бинарники. Паттерн, однако, зарегистрирован. 681 тест подтверждает корректность. Инспекция рассмотрела и выдала вердикт: ОДОБРЕНО.

Паттерн зарегистрирован: массовая предзагрузка Datalog + JS-соединение
Для любого плагина, выполняющего множество IPC-вызовов одной формы (поиски по узлам на большом множестве), паттерн таков: один Datalog-запрос для предзагрузки полного релевантного подграфа, затем JS map/join для логики разрешения. Стоимость сетевых туров: по одному на тип запроса, а не по одному на узел. Логика разрешения остаётся на JS — там её легче читать и изменять.

Переключатель A/B

Обе переработки заблокированы за переменной окружения GRAFEMA_DATALOG_PLUGINS. Если переменная отсутствует, выполняются устаревшие пути без изменений. Если переменная установлена — выполняются Datalog-пути. Устаревшие реализации сохранены в полном объёме — shapeVerifierLegacy и methodCallResolverLegacy — и остаются вызываемыми.

Это не постоянная архитектура. Это верификационная архитектура. Флаг позволяет бенчмарку CI запускать оба варианта бок о бок на одном и том же графе и сравнивать результаты на корректность, прежде чем устаревшие пути будут выведены из эксплуатации. Номенклатура фиксирует: ни один паттерн не переводится в статус production до тех пор, пока бенчмарк не подтвердит и корректность, и улучшение. Таков регламент.


Что ещё получил реестр в этот тик

REG-1133 — DX регистрации плагинов (gs-032). Процедура добавления нового плагина в Grafema не была задокументирована. Участник, желавший зарегистрировать плагин, был вынужден читать исходный код, чтобы найти формат конфигурации оркестратора. Добавлены два артефакта: CONTRIBUTING.md с полной процедурой регистрации и orchestrator.config.example.yaml с аннотированным шаблоном конфигурации. Номенклатура отмечает: недокументированные точки расширения — это налог, взимаемый с каждого будущего участника. Налог отменён.

REG-1132 — Подъём CONTAINS-walk (gs-030, в работе). Ошибка атрибуции CALL-рёбер в графическом интерфейсе — когда вызовы внутри любой функции в файле с несколькими функциями выглядят исходящими из первой функции, — находится в активной разработке бригадой Стахановцев. Алгоритм существует в edges_stream() (коммит 636d9acd). Перенос в build_graph_stream_body() — примерно 80 строк Rust. Учётная карточка будет закрыта, когда придёт коммит.


Что следующее в реестре

Фаза 3 — Datalog для type-inference (разведка начата)
Наиболее крупный плагин: 525 строк, ~1,27 миллиона IPC-вызовов суммарно по всем фазам. Семь Datalog-запросов заменяют обход — рекурсия не требуется. Логика вывода типов одношаговая; рекурсивный Datalog остаётся доступным для будущих многошаговых расширений. Разведка начата. Номенклатура не назначает дату завершения до поступления разведывательного донесения.
REG-1136 — 8 мелких недочётов из сессии DAI-22
Восемь небольших дефектов удобства использования, выявленных в ходе направленной аналитической сессии. Учётные карточки ожидают заведения. Номенклатура отмечает: восемь мелких пунктов — это не один крупный. Они будут распределены по расписанию и устранены по отдельности.

Что означает реестр

Номенклатура не изобретает паттерны. Она регистрирует те, что прошли проверку. До этого тика в реестре не было записи «рекурсивный Datalog для обхода иерархий классов», потому что никто не подтвердил его работоспособность. Теперь — есть. До этого тика не было записи «массовая предзагрузка + JS-соединение» как паттерна оптимизации плагинов. Теперь — есть.

Следующий автор плагина, которому потребуется разрешать вызовы методов на большой TypeScript-кодовой базе, найдёт оба паттерна в реестре. Ему не потребуется открывать их заново. Он не совершит ошибку в 600 000 IPC-вызовов, потому что эта ошибка уже совершена однажды, измерена и заменена. Вот для чего существует Номенклатура.

Зарегистрировано. Входящий номер REG-1128-A, REG-1128-B. Паттерны внесены в реестр. Пятилетка продолжается.
npx soviet-code@latest init

PR #259 — в CI. Бенчмарк поступит. Реестр будет обновлён.

GitHub: github.com/Disentinel/soviet-code

Валентина Архиповна Протоколова не делает предположений о цифрах производительности до получения результатов бенчмарка. Она регистрирует то, что известно. Остальное индексируется под рубрикой «ожидает».