Перейти к содержанию

Aggregate lowering — первое исследование

Исследование и кандидат оптимизации, не универсальная гарантия скорости. Baseline PR #19 слит отдельно (77610b4), исходный baseline b320611 не менялся. JSON-парсер также не менялся. Измерение: Apple M4, 16 ГиБ, Apple Clang 21, O2, generic CPU, тот же корпус и чанки 2048 байта. Кандидат: 7c1da5d.

Изоляция изменений

Вариант Что проверяет
A0 Исходный компилятор b320611, повторно измеренный на том же стенде
A1 Только readonly/nocapture/noalias-аннотации ABI для JsonState; не перебор всех возможных ABI
A2 Локальное переиспользование временных значений и stack slots в ациклических функциях
A3 Специализация целого состояния при доказанном отсутствии старых наблюдателей

A1/A2 включаются только исследовательским emitter. В рабочий backend добавлен только A3. Semantic IR всех вариантов совпадает; различается физическое lowering.

Медиана throughput ядра, МиБ/с

По 10 повторов на вариант и нагрузку, всего 240 сырых измерений. Больше — быстрее.

Нагрузка A0 A1 A2 A3 A3/A0
ascii 42.88 42.39 38.64 71.77 1.67×
depth64 29.76 29.75 26.64 49.33 1.66×
escaped 55.18 56.06 43.29 88.23 1.60×
long-string 64.50 63.49 60.94 118.51 1.84×
numbers 38.96 39.53 38.56 99.70 2.56×
unicode 55.59 54.65 52.40 95.20 1.71×

A1 не дал существенного ускорения. A2 уменьшил frame, но не улучшил скорость. Это подтверждает необходимость измерять горячий путь: размер frame и количество статических memcpy сами по себе не определяют стоимость исполнения.

Динамические bulk-copy и stack frame

На ASCII диагностическая сборка подсчитала объём выполненных memcpy/memmove в оптимизированном IR на входной байт:

A0 A1 A2 A3
720.53 717.53 772.63 256.13

Это не все машинные копирования: scalarized stores и перемещения регистров не учитываются. Счётчики вставлены после O2; отдельная диагностическая сборка не участвует в измерении времени. Учитываются также bridge, init и finish.

Для горячей specialized-функции __liza_owned___liza_json_step frame составляет 720 байт вместо 4480 байт исходной функции. Обычная immutable-версия сохраняется для случаев, где уникальность не установлена; её frame в кандидате — 3696 байт. Frame json.feed уменьшился с 608 до 416 байт. Это размеры отдельных функций, не оценка максимального стека цепочки вызовов.

Почему снимки остаются независимыми

Публичный ABI по-прежнему передаёт большие значения через immutable storage. Дополнительный callee используется только если caller доказал отсутствие живого наблюдателя исходного allocation, включая копии, проекции и views. Сам move не является доказательством уникальности; входной параметр caller не считается его эксклюзивным allocation.

Новая форма специализации ограничена ациклической функцией с одним большим аргументом и результатом того же типа. Все возвраты должны происходить от этого аргумента через проверенные обновления, phi или уже доказанный direct-callee. Каждый разрушающий переход проверяет отсутствие старых наблюдателей; второй аргумент вызова не может наблюдать обновляемый корень. Композиция строится снизу вверх; рекурсивная группа не может объявить собственную сводку доказанной. Readonly-параметры и функции с View-параметрами исключены. Циклические callee остаются на обычном ABI; caller с циклом может использовать доказанный callee.

Проверки арифметики и границ не удаляются. Существующая специализация функций, возвращающих входное значение первым полем обёртки, сохраняется отдельно.

Проверки и граница результата

  • 351 локальный тест компилятора: успешно, 11 платформенных пропусков.
  • 202 теста Verified: успешно; это регрессии прежних доказательных фрагментов.
  • 7 новых тестов: цепочки вызовов, порядок обнаружения сводок, публичный ABI, snapshot/view, bounds и overflow при O0/O2.
  • Мутация liveness принимает destructive call при живом snapshot: snapshot(3) возвращает ошибку 1 вместо 0 в конкретном нативном replay.
  • Мутация overflow-guard позволяет trap(255) завершиться нормально вместо trap; контроль обнаруживает нарушение при O0/O2.
  • A0–A3 совпадают на 6785 разбиениях и 615 CLI-проверках до измерения.

Это не формальное доказательство soundness storage analysis и не проверка всех машинных программ. Достигнут выигрыш на шести выбранных нагрузках; глубоко вложенный JSON всё ещё ниже ориентира 70 МиБ/с. Рубежи 150/300 МиБ/с не достигнуты. T2-B и дальнейшая работа над lowering остаются самостоятельными этапами.

Исходники исследования — benchmarks/aggregate/. Сырые измерения, команды, версии, хеши, counters и stack records сохранены в results/apple-m4/report.json. Архив evidence.tar.gz содержит IR/assembly; manifest.json фиксирует его хеши. Полные snapshots и бинарники остаются в каталоге локального запуска и воспроизводятся по указанным коммитам. Никакие старые отчёты не переписаны.