Files
owniverse/tests/artifacts/all_objects_speed6_results.md
Kirill 273093bd9e Разделить частоту обновления часов и расчёта симуляции
Счётчик времени UI обновляется до 10 Гц по запрошенному времени, а тяжёлые циклы по-прежнему запускаются с адаптивным интервалом и обрабатывают весь накопленный промежуток. Обновить тесты и описание модели.
2026-10-17 23:41:18 +03:00

519 lines
62 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Все объекты, скорость 6
Создано скриптом `tests/create_full_benchmark_save.gd`. Пароль нативного сохранения: `qwerty`.
Генератор не читает и не перезаписывает сохранение игрока.
Начальное состояние: 151 запись каталога (включая группы), все 44 стадии правил цивилизаций, все шесть этик на каждой стадии, 1000 когорт (по десять на сущность с временными партиями). У большинства обычных объектов количество равно 6e60, у стадий цивилизаций — 6e20. Пространство и водород имеют количество 1e90, гелий и металлы — 1e80, энергия — 1e100. Возраст — 1e15 лет. Запасов достаточно для требований продвинутых стадий звезд и структур. Оставшиеся сроки жизни когорт покрывают весь срок жизни сущностей, поэтому переходы происходят во время замера.
Это искусственный экстремальный сценарий, а не прогноз для обычного сохранения.
Машина: Apple M4 Pro, Godot 4.7.2, рендерер Metal Mobile.
| Замер | Результат |
|---|---:|
| Headless, скорость 6, шесть шагов по 0,5 секунды | 943,936–1221,992 мс на шаг |
| Среднее время headless-шага | 1122,287 мс |
| Пропускная способность headless | 0,446 секунды симуляции на секунду CPU |
| Настоящий UI, страница цивилизаций, 600 кадров | 17,38 FPS |
| Средний / p95 / максимальный кадр UI | 57,55 / 99,78 / 116,94 мс |
| Завершенные транзакции | 23 |
| Запрошенный прирост игрового времени | 3464662,267 лет |
| Опубликованный прирост игрового времени | 1080000 лет |
| Пропускная способность с UI | 0,3117 |
| Накопленный долг за замер | 2384662,267 игровых лет (23,85 реальных секунд на скорости 6) |
| Записей каталога осталось в конце | 151 |
Динамический шаг достигает предела в 0,5 секунды. Рендеринг идет быстрее 5 FPS, но симуляция не успевает за заданным темпом в этом сценарии. На обработку поколений приходится примерно 94% времени CPU. Подготовка цивилизаций занимает в среднем 634 мс на шаг, в том числе дрифт этик — 218 мс, войны — 124 мс; колонизация — 121 мс на шаг. Интервалы профилировщика вложенные и частично перекрываются.
## Сравнение оптимизации дрифта (2026-10-05)
Замеры сделаны на одном сгенерированном сохранении и одной машине до и после прямого распределения потоков для обычного и колониального дрифта, а также кеширования ставок дипломатии в фиксированной точке. Каждый headless-запуск выполняет шесть последовательных шагов по 0,5 секунды на каждой скорости.
| Замер | До | После |
|---|---:|---:|
| Средний headless-шаг на скорости 6 | 1122,287 мс | 1018,559 мс |
| Пропускная способность headless на скорости 6 | 0,446 | 0,491 |
| Дрифт этик, сумма интервалов за шесть шагов | 1,338 с | 0,643 с |
| UI, FPS за 600 кадров | 17,38 | 17,04 |
| Средний / p95 / максимальный кадр UI | 57,55 / 99,78 / 116,94 мс | 58,70 / 102,67 / 114,30 мс |
| Завершенные UI-транзакции | 23 | 25 |
| Запрошено / опубликовано игровых лет в UI | 3464662 / 1080000 | 3533627 / 1180000 |
| Пропускная способность симуляции с UI | 0,3117 | 0,3339 |
Средний headless-шаг ускорился примерно на 9,2%, а интервал профиля дрифта этик сократился примерно на 52%. Частота кадров UI практически не изменилась (в этом запуске снизилась примерно на 2%), при этом завершилось больше транзакций и выросла доля опубликованного игрового времени. На скорости 6 стресс-сценарий все еще отстает от реального времени: пропускная способность — около 0,49 секунды симуляции на секунду CPU в headless и 0,33 с UI. Самыми затратными остаются планирование поколений и войны.
Прямые пути сохраняют целое население, но разносят малые целочисленные потоки по нескольким последовательным переходам с помощью остатков для каждого источника. Поэтому распределение в отдельном переходе отличается от независимого округленного распределения по матрице 6×6. Ставки дипломатии округляются до сетки фиксированной точки с шагом 1e-9. Целевая регрессия: 769 проверок эволюции цивилизаций, оптимизаций симуляции, границ партий, укрупненных поколений и эволюции кадров; все пройдены.
## Последующая оптимизация подготовки поколений и кешей (2026-10-05)
На той же нагрузке среднее время headless-шага на скорости 6 снизилось с 1018,559 до 1005,138 мс (примерно на 1,3%). Пропускная способность headless изменилась с 0,491 до 0,497. Суммарные интервалы `generations` близки: 5,703 с и 5,629 с за шесть шагов. Подготовка цивилизаций остается самой затратной измеренной подфазой — 3,130 с. UI также почти не изменился: 17,04 → 17,09 FPS, пропускная способность симуляции — 0,3339 → 0,3351. Улучшение небольшое: арифметика населения в поколениях по-прежнему дорога при сотнях активных когорт и множестве правил цивилизаций.
Профиль теперь отдельно показывает `generation_withdrawal` и `generation_products`. Первый интервал занимает 55,5 мс, второй — 120,2 мс за шесть headless-шагов на скорости 6. Эти значения нельзя складывать с общим временем поколений, поскольку интервалы профилировщика вложенные.
## Инкрементальная обработка партий новорожденных (2026-10-05)
Удалены снимки когорт до и после рождения и последующий полный обход когорт. `append_batch` теперь сразу накапливает поправку на возраст новорожденных при добавлении частей когорт. Финальный замер после повторного использования сумм завершившихся партий в пределах поколения дал 1028,991 мс на headless-шаг скорости 6 и пропускную способность 0,486. В повторных прогонах этой же версии получилось 1005–1011 мс, поэтому при выборке всего в шесть шагов разброс велик, и устойчивое ускорение утверждать нельзя. В UI получилось 17,05 FPS, среднее время кадра 58,66 мс и пропускная способность 0,3342. Новый профиль показывает 319 мс на обработку партий новорожденных за шесть шагов. Это изменение пока не демонстрирует снижения общего времени на этом сохранении; его потенциальная польза относится прежде всего к сценариям с гораздо большим числом когорт на сущность, где прежние обходы росли пропорционально числу когорт.
Повторить замеры из родительской папки проекта:
```sh
godot --headless --path Owniverse.GI --script res://tests/create_full_benchmark_save.gd
godot --headless --path Owniverse.GI --script res://tests/benchmark_saved_state.gd -- Owniverse.GI/tests/artifacts/all_objects_speed6.adventure.json 0.5 profile
godot --path Owniverse.GI --script res://tests/benchmark_full_ui.gd
```
## Проверка на Android Note8 (2026-10-06)
Сборка benchmark установлена отдельным пакетом `com.KIDGameProduction.Owniverse.AndroidBench`, сохранение основной игры не использовалось. Подготовка и декодирование сохранения выполнялись в фоновом потоке; ход и результат записывались в файл приложения. Устройство: Samsung SM-N950F, Android 9. Сценарий: все объекты и цивилизации, скорость 6, 120 кадров (119 интервалов).
| Метрика | Результат |
|---|---:|
| FPS UI | 1,76 |
| Средний / p95 / максимальный кадр | 567,28 / 817,54 / 1278,33 мс |
| Завершенные транзакции за прогон | 1 |
| Запрошено / опубликовано игрового времени | 1599938,57 / 10000 лет |
| Доля опубликованного от запрошенного | 0,00625 |
| Итоговый динамический шаг | 0,2 с |
Самый дорогой участок профиля — `generations`: 5,350 с суммарно за единственную завершенную транзакцию; внутри него `civilization_prepare` занял 3,186 с, `wars` — 2,217 с, `civilization_transitions` — 1,034 с. Интервалы вложены, поэтому их нельзя складывать с `generations`. Этот экстремальный сценарий на Note8 не достигает целевых 5 FPS и сильно отстает по игровому времени. Это замер именно полного стресс-сохранения, а не обычного игрового сохранения.
### Покадровая уступка в расчётах цивилизаций
Добавлены контрольные точки внутри обработки этик, проигравших в войне, падения популяции и выходов между стадиями. Математика и порядок переходов не меняются. На том же Note8 повторный прогон дал 1,87 FPS против 1,76 FPS до изменения (прирост около 6%). Средний кадр сократился с 567 до 535 мс, но p95 остался 630 мс, максимум — 1281 мс. Это слишком малое улучшение для цели 5 FPS.
В повторном профиле `generations` заняли 5,166 с, `civilization_prepare` — 3,040 с, войны — 0,985 с, переходы между стадиями — 0,640 с. Профиль не показывает явного трёхкратного ускорения: контрольные точки лучше дробят отдельные подциклы, но главный синхронный участок остается слишком дорогим. Диагностическая сборка для измерения максимального непрерывного участка не завершила прогон на телефоне; при следующем проходе сначала нужно локализовать этот участок, а затем оптимизировать его отдельно.
Контрольный запуск UI-бенчмарка на Apple M4 Pro после изменения: 21,51 FPS, средний / p95 / максимальный кадр — 46,49 / 89,62 / 107,19 мс. Этот результат подтверждает отсутствие регрессии на компьютере, но не заменяет Android-замер.
### После перехода этик на доли (2026-10-06)
Этическое состояние теперь хранит шесть долей `float`, а точное целое население берётся из реестра объектов. Исходы одной стадии сначала собираются по назначениям; доли состояния обновляются после агрегации потоков. Формат сохранения повышен до версии 6; миграции прежних сохранений нет.
Финальная APK повторно проверена на Samsung SM-N950F, Android 9, тем же полным сценарием и 120 кадрами. Два последовательных прогона дали **14,57 и 15,02 FPS**, средний кадр — **68,61 и 66,58 мс**, p95 — **113,03 и 123,03 мс**, по одной завершённой транзакции из 119 интервалов. Опубликовано 10 000 лет из 647 331 и 634 134 запрошенных; пропускная способность — 0,01545 и 0,01577. В последнем профиле `generations` заняли 5,120 с, `civilization_prepare` — 3,162 с, войны — 1,026 с, переходы — 0,728 с, дрейф этик — 0,474 с. Самый длинный непрерывный участок составил **458,14 мс** в `deep_copy_and_coarsen`, максимальный кадр — 976 мс. Предыдущий одиночный запуск старой benchmark-сборки показал 1,83 FPS, поэтому сравнивать его с этой парой напрямую нельзя; оба финальных прогона выполнены на одной APK и подтверждают результат около 15 FPS.
На компьютере прошли тесты состояния (70), эволюции (555), оптимизаций симуляции (364), индикаторов (63) и жизни (25). Полный набор всё ещё сообщает о двух отказах в `test_descriptions.gd` при обновлении выбранного описания и смене языка; оба относятся к UI-описаниям, а не к модели этик. В логах Android ошибок GDScript/Godot за прогон не найдено.
## Непрерывная модель цивилизаций — 2026-10-06
Сравнены исходная симуляция из коммита `6ee66a6` и новая модель потоков. Оба запуска используют один диагностический JSON, скорость 6, 100 последовательных полных циклов с запросом 0,1 секунды каждый и включённый CPU-профиль. Подготовка каталога и чтение JSON не включены в длительность цикла. Запуски выполнены последовательно, без параллельных тестов. Сохранение игрока не читалось и не изменялось.
| Полный цикл и пропускная способность | До | После |
|---|---:|---:|
| Среднее время полного цикла | 811,292 мс | 401,796 мс |
| Минимум / максимум | 488,914 / 963,141 мс | 323,427 / 435,607 мс |
| Завершённых полных циклов в секунду | 1,233 | 2,489 |
| Обработанных секунд симуляции на секунду CPU | 0,123 | 0,249 |
| Применено игровых лет за 100 циклов | 1 000 000 | 1 000 000 |
Полный цикл ускорился в **2,02 раза**, среднее время сократилось на **50,5%**. Цель **100 мс / 10 полных циклов в секунду не достигнута**: для неё требуется ещё примерно 4,02-кратное ускорение текущей версии. При непрерывном запросе времени на шестой скорости и шаге 0,1 секунды этот стресс-сценарий продолжит накапливать долг. Это измерение полных завершённых шагов симуляции, без показателя FPS.
Текущие внешние интервалы CPU-профиля, по убыванию среднего времени на цикл:
| Расчёт | Среднее за цикл |
|---|---:|
| Поколения звёзд и биологической жизни | 151,6 мс |
| Подготовка непрерывных потоков цивилизаций | 98,5 мс |
| Применение потоков к количествам и владельцам | 53,2 мс |
| Производство за период | 28,7 мс |
| Тренды | 18,1 мс |
| Дрейф, проверка вместимости и поклонение после потоков | 8,8 мс |
| Инициализация жизни | 6,1 мс |
| Ограничение потоков ресурсными бюджетами | 5,8 мс |
| Применение колонизации | 5,5 мс |
Внутри подготовки потоков разреженный оператор занимает 24,5 мс на цикл; этот вложенный интервал нельзя прибавлять к 98,5 мс. Внешние интервалы не покрывают всё время: остальная работа включает копирование транзакции, построение физических снимков и обновление представления.
Модель C0.2–C4.4 теперь использует точные целые количества и шесть долей float без возрастных партий. Оператор учитывает несколько последовательных переходов за интервал. Конечные количества и ресурсные потолки сохраняются точно; пропорции потоков и владельцев приближены float и квантованием долей до 15 десятичных знаков. Изменяется распределение событий во времени, поэтому тесты проверяют законы новой модели, сохранение количества, владение, ресурсные ограничения и воспроизводимое продолжение сохранения.
Регрессия: 27 из 28 наборов прошли. Новые переходы — 1895 проверок; арифметика распределения и кеши — 1889; кадровое выполнение — 24. В `test_descriptions.gd` сохраняются две ранее обнаруженные ошибки обновления выбранного описания и языка; этот UI-код не изменён в данном рефакторинге.
Повторение из папки `Owniverse.GI`:
```sh
godot --headless --path . --script res://tests/benchmark_civilization_flows.gd -- tests/artifacts/all_objects_speed6.adventure.json 0.1 profile cycles=100
```
## Фиксированные пять циклов в секунду — 2026-10-07
Текущая версия после отката агрегации и возврата 40 возрастных групп.
Планировщик использует шаг 0,2 реальной секунды на всех скоростях. Замер:
диагностическое сохранение со всеми объектами и цивилизациями, скорость 6,
100 полных синхронных циклов с CPU-профилем, без отрисовки интерфейса.
Проверка сохранения: OK. Исходное сохранение не изменялось.
| Метрика | Результат |
|---|---:|
| Среднее время полного цикла | 439,228 мс |
| Минимум / максимум | 340,370 / 483,152 мс |
| Завершённых полных циклов в секунду | 2,277 |
| Требуется циклов в секунду | 5 |
| Обработано игровых лет | 2 000 000 |
| Запрошенное время сценария | 20 с |
| Время расчёта 100 циклов | 43,923 с |
| Пропускная способность | 0,455 с симуляции / с расчёта |
Цель 200 мс на полный цикл не достигнута: по среднему времени требуется
ускорение примерно в 2,20 раза. Увеличение шага с 0,1 до 0,2 секунды улучшило
отношение обработанного времени к затратам, но при непрерывном поступлении
времени этот стресс-сценарий продолжит накапливать долг. Это измерение
пропускной способности симуляции, без оценки FPS. Один прогон не задаёт
гарантированную производительность для других сохранений или устройств.
Внешние интервалы CPU-профиля, по убыванию среднего времени на цикл:
| Расчёт | Среднее на цикл |
|---|---:|
| Поколения звёзд и биологической жизни | 168,294 мс |
| Подготовка непрерывных потоков цивилизаций | 111,835 мс |
| Применение потоков к количествам и владельцам | 59,516 мс |
| Производство за период | 29,248 мс |
| Тренды | 17,787 мс |
| Завершение цивилизационных потоков | 8,864 мс |
| Ограничение потоков вместимостью | 6,439 мс |
| Инициализация жизни | 6,172 мс |
| Колонизация | 6,111 мс |
Вложенные интервалы нельзя прибавлять к внешним: построение физических
снимков — 27,845 мс/цикл; изъятие партий — 42,015 мс/цикл; решение оператора
цивилизаций — 31,835 мс/цикл. Проверки кадрового планировщика:
35 проверок, 0 ошибок, включая все шесть скоростей, сохранение долга,
возобновление расчёта и пять завершённых циклов на одну секунду запроса.
```sh
godot --headless --path . --script res://tests/benchmark_civilization_flows.gd -- tests/artifacts/all_objects_speed6.adventure.json 0.2 profile cycles=100
```
## Новые звёздные партии с целым переходом за цикл — 2026-10-07
На скоростях 4–6 новые звёзды одного типа объединяются по общей границе
завершения жизни и переходят целиком. Временная сетка равна одному полному
циклу (200/2000/20000 игровых лет). Старые постепенные партии из сохранения
не преобразуются; SN/GRB сохраняют прежнюю обработку.
Повторён тот же замер: диагностическое сохранение, скорость 6, шаг 0,2 с,
100 полных циклов с CPU-профилем. Проверка сохранения OK.
| Метрика | До | После |
|---|---:|---:|
| Среднее время полного цикла | 439,228 мс | 445,690 мс |
| Минимум / максимум | 340,370 / 483,152 мс | 345,276 / 486,647 мс |
| Полных циклов в секунду | 2,277 | 2,244 |
| Пропускная способность | 0,455 | 0,449 |
| Обработано игровых лет | 2 000 000 | 2 000 000 |
| Поколения, среднее на цикл | 168,294 мс | 171,039 мс |
| Обработка партий новорождённых, среднее на цикл | 7,768 мс | 6,199 мс |
| Вызовы обработки партий новорождённых | 16 147 | 13 885 |
Общего ускорения на этой выборке нет: среднее выросло примерно на 1,5%.
Обработка новорождённых занимает на 20% меньше времени, но это небольшая
доля полного цикла. Замер включает существующие постепенные партии;
он не доказывает ускорения вселенной, целиком созданной по новой схеме.
Цель пяти полных циклов в секунду остаётся недостигнутой.
Проверки: границы партий — 109, звёздные правила — 333, короткие события —
841, укрупнённые поколения — 28, кадровое выполнение — 35; все без ошибок.
Тестируются точные большие количества, целый однократный переход,
распределённые рождения, сохранения и интеграл производства.
## Первоначальный замер больших сохранений до исправления сетки — 2026-10-07
Созданы `large_star_cohorts_legacy.adventure.json` и
`large_star_cohorts_cycle.adventure.json`: по 6×10^60 звёзд каждого из 15
типов (главная последовательность и красные гиганты), остальные объекты,
жизнь и цивилизации взяты из диагностического сценария. Возраст — 10^12 лет.
Для каждого типа заново сформирована одинаковая история рождения длиной
`min(эффективный срок жизни, 2 млн лет)` перед началом завершения жизни.
Исходные физические количества и этические профили совпадают строго.
Сохранения валидируются и проходят точное сравнение состояния после записи
и чтения JSON с полной точностью float. Сохранение игрока не изменялось.
Старая схема измеряется переключателем `batches.cycle_stars = false`, новая
включена по умолчанию. В обоих вариантах одинаковый остальной код симуляции,
скорость 6, шаг 0,2 с и CPU-профиль. Два прогона по 50 полных циклов на модель,
порядок запусков: старая → новая → новая → старая. Перед каждым прогоном
восстанавливается исходное состояние; каждый обрабатывает 1 млн игровых лет.
| Метрика | Старая схема | Новая схема |
|---|---:|---:|
| Среднее первого прогона | 417,265 мс | 423,419 мс |
| Среднее второго прогона | 431,081 мс | 427,011 мс |
| Среднее всех 100 циклов на модель | 424,173 мс | 425,215 мс |
| Полных циклов в секунду | 2,358 | 2,352 |
| Пропускная способность | 0,472 | 0,470 |
| Звёздных партий в исходном сохранении | 118 | 1 300 |
| Пиковое число звёздных партий | 132 | 1 300 |
| Поколения, среднее на цикл | 157,711 мс | 147,906 мс |
| Производство, среднее на цикл | 28,692 мс | 34,704 мс |
| Применение потоков цивилизаций, среднее на цикл | 58,642 мс | 62,160 мс |
| Изъятие партий, вложенное в поколения | 37,015 мс | 41,379 мс |
| Партии новорождённых, вложенное в поколения | 7,648 мс | 4,248 мс |
**Устойчивого выигрыша полного цикла не обнаружено.** Разница средних —
около +0,25% у новой схемы; в первом парном сравнении она медленнее, во втором
быстрее. Поколения занимают примерно на 6,2% меньше времени, но производство
стало дороже примерно на 21%. Пять полных циклов в секунду не достигнуты.
Причина роста числа партий: для долгоживущих звёзд сетка одного цикла
значительно мельче `lifespan / 40`. Например, у RD прежняя ширина — 1 млрд
лет, новая на скорости 6 — 20 тыс. лет. Поэтому изменение не всегда
укрупняет партии: на таком наборе исходных рождений их стало в 11 раз больше.
Итоговое временное распределение переходов у моделей различается; совпадение
их конечных состояний не является условием этого замера.
Для дальнейшего упрощения следует сохранять широкие группы долгоживущих
звёзд и применять целый переход только к партиям, уже укладывающимся в один
цикл. Это предложение в данном замере не реализовано.
```sh
godot --headless --path . --script res://tests/benchmark_large_star_cohorts.gd -- cycles=50 repeats=2
```
Полные результаты первоначального замера: `large_star_cohorts_before_dynamic_fix_results.json`.
Набор с 1300 партиями сохранён в `large_star_cohorts_before_dynamic_fix_cycle.adventure.json`.
Последующие файлы без этого суффикса относятся к исправленной динамической схеме.
## Исправленное динамическое укрупнение без дробления — 2026-10-07
Ошибка первоначальной реализации устранена: циклическая сетка больше не
заменяет широкие возрастные окна долгоживущих звёзд. При создании новая сетка
используется только если прежнее окно не шире цикла. Иначе используется
прежнее широкое окно. Из существующих партий объединяются две или более
одного типа, чей оставшийся интервал завершения целиком лежит в общем цикле.
Партии, пересекающие границу циклов или занимающие несколько циклов, не делятся.
Повторён парный замер на отдельных больших сохранениях, с теми же исходными
количествами и входными интервалами рождения: скорость 6, шаг 0,2 с,
два прогона по 50 циклов на модель в порядке старая → новая → новая → старая.
Каждый прогон обрабатывает 1 млн игровых лет; состояния валидируются до и
после, записанные файлы проходят точное сравнение после чтения.
| Метрика | Старая схема | Исправленная динамическая |
|---|---:|---:|
| Исходных звёздных партий | 118 | 113 |
| Пиковое число партий | 132 | 127 |
| Число партий после 50 циклов | 130 | 125 |
| Среднее первого прогона | 420,388 мс | 424,307 мс |
| Среднее второго прогона | 431,605 мс | 428,498 мс |
| Среднее всех 100 циклов на модель | 425,996 мс | 426,402 мс |
| Полных циклов в секунду | 2,347 | 2,345 |
| Поколения, среднее на цикл | 158,622 мс | 157,606 мс |
| Партии новорождённых, вложенный интервал | 7,679 мс | 6,693 мс |
На этом наборе партиям стало меньше примерно на 4,2%, вместо прежнего
ошибочного роста до 1300. Проверено, что долгая группа RD остаётся одной
широкой партией и её окно не меняется при добавлении новых звёзд.
Новый тест запрещает рост числа исходных партий в диагностическом сценарии.
Устойчивого ускорения полного цикла по этим прогонам нет: разница средних
около +0,10%; знак разницы в отдельных парных сравнениях меняется.
Обработка партий новорождённых занимает примерно на 13% меньше времени,
но её доля недостаточна для заметного выигрыша всего расчёта.
Цель пяти циклов в секунду по-прежнему не достигнута.
Проверки: границы партий — 117, звёздные правила — 333, короткие события —
841, кадровое выполнение — 35; все без ошибок. Дополнительные проверки
охватывают сохранение широких окон, объединение старых партий с точными
количествами и остатками, соседние циклы и повторное укрупнение.
Актуальные сохранения: `large_star_cohorts_legacy.adventure.json` и
`large_star_cohorts_cycle.adventure.json`; результаты: `large_star_cohorts_results.json`.
## Новая вселенная с множеством объектов и мелких звёздных партий — 2026-10-07
Создано отдельное состояние с нуля по текущим таблицам: 150 типов объектов,
все 44 стадии этических цивилизаций (включая Ct), 15 типов живых звёзд.
Запасы большинства объектов — 10^60 каждого типа; планет и цивилизаций —
10^28. Жизнь размещена у четырёх типов карликов, четверть звёзд каждого типа
связана со структурами. Этические профили различаются между стадиями.
Высокий запас пространства сохраняет жизнь при бластах. Интерфейс не отрисовывался.
Для проверки укрупнения заданы валидные синтетические исторические партии:
40 последовательных циклов завершения × 8 узких партий × 15 типов звёзд.
Все восемь партий типа целиком завершаются в общем цикле; это целевой
стресс-сценарий большого числа партий, а не утверждение, что обычное создание
с неизменным временем жизни обязательно порождает такую фрагментацию.
Исходный состав и интервалы одинаковы для обеих моделей. Долгоживущие звёзды
не дробились алгоритмом: ему переданы уже существующие узкие партии.
До укрупнения — 4800 звёздных партий. Старая схема сохраняет 4560,
исправленная динамическая — 600. Созданы два отдельных диагностических файла,
проверены запись/чтение без изменения состояния и валидация до и после каждого
прогона. Сохранение игрока не затрагивалось.
Два прогона по 40 полных циклов на модель; порядок старая → новая → новая →
старая. Скорость 6, фиксированный шаг 0,2 с, CPU-профиль включён.
Каждый прогон восстанавливает исходное состояние и обрабатывает 800 тыс. лет.
| Метрика | Старая схема | Динамическое укрупнение |
|---|---:|---:|
| Исходных звёздных партий после укрупнения | 4 560 | 600 |
| Пиковое число партий | 4 560 | 607 |
| Среднее первого прогона | 612,606 мс | 530,285 мс |
| Среднее второго прогона | 624,625 мс | 532,578 мс |
| Среднее всех 80 циклов на модель | 618,616 мс | 531,431 мс |
| Полных циклов в секунду | 1,617 | 1,882 |
| Обработанных секунд симуляции / секунду расчёта | 0,323 | 0,376 |
| Поколения, среднее на цикл | 211,916 мс | 138,339 мс |
| Производство, среднее на цикл | 51,201 мс | 38,038 мс |
| Подготовка потоков цивилизаций | 113,371 мс | 113,270 мс |
| Применение потоков цивилизаций | 114,343 мс | 113,820 мс |
| Колонизация | 55,284 мс | 55,291 мс |
| Обработка партий новорождённых, вложенная в поколения | 29,464 мс | 2,967 мс |
**Выигрыш полного цикла подтверждён обоими парными сравнениями:** время
сократилось на 14,1%, ускорение около 1,16 раза. Поколения занимают на 34,7%
меньше времени. Механизм даёт эффект при множестве подходящих для объединения
партий; в предыдущем сценарии с небольшим числом широких партий эффект был
незаметен. Изменение моментов переходов допускается моделью: конечные состояния
двух схем не обязаны совпадать, но обе полностью обработали запрошенный интервал.
Пять циклов в секунду не достигнуты: для данного сценария требуется ещё
примерно 2,66-кратное ускорение. Главные оставшиеся затраты — поколения и
подготовка/применение цивилизационных потоков; колонизация также заметна.
Сохранения: `many_objects_fragmented_stars_legacy.adventure.json` и
`many_objects_fragmented_stars_cycle.adventure.json`.
Полные результаты: `many_objects_fragmented_stars_results.json`.
```sh
godot --headless --path . --script res://tests/benchmark_many_objects.gd -- cycles=40 repeats=2
```
## Консолидация применения потоков и колонизации — 2026-10-08
Первый этап: исходное население распределяется по строкам владельцев одной таблицы переходов. Свободные стадии применяют готовые целые квоты напрямую. При колонизации списания планет объединяются по владельцам; каждая стадия колоний получает одну суммарную выдачу. Общие целые количества и статистика сохранены. Изменён порядок распределения единичных остатков между владельцами; полного совпадения состояния с прежним порядком округления не заявляется. Ct остаётся свободной от привязок.
До и после загружались одни и те же диагностические файлы с теми же количествами и партиями. Скорость 6, полный интервал 0,2 секунды (20 000 игровых лет), CPU-профилирование включено, UI отсутствует. По два прогона из исходного состояния, каждый по 20 циклов: до → после → после → до. На каждую модель и сохранение обработано 800 000 игровых лет. Валидация начальных и конечных состояний прошла; SHA-256 входных файлов до и после совпали. Сохранение игрока не использовалось.
| Сохранение | До, мс | После, мс | Сокращение времени | Полных циклов/с после |
|---|---:|---:|---:|---:|
| Все объекты | 385,263 | 377,222 | 2,09% | 2,651 |
| Много объектов и партий | 506,888 | 443,303 | 12,54% | 2,256 |
Для тяжёлого сохранения:
| Участок | До, мс/цикл | После, мс/цикл |
|---|---:|---:|
| Применение переходов | 113,011 | 91,591 |
| Колонизация | 53,487 | 11,520 |
| Подготовка потоков | 114,808 | 114,742 |
| Поколения звёзд и жизни | 116,085 | 115,999 |
Первый этап сокращает полный тяжёлый цикл на 12.54%, но цель пяти циклов в секунду не достигнута. До 200 мс нужно ещё примерно 2.22-кратное ускорение. Следующие крупные затраты — подготовка цивилизационных потоков, поколения и оставшееся применение переходов.
Проверки: целочисленные квоты и владельцы, включая 10^400 + 103 — 1068; цивилизационные потоки — 1895; состояние цивилизаций — 70; кадровый планировщик — 38. Всего 3071 проверка без ошибок. Проверены сохранение населения каждого владельца при планетных переходах, точные поступления по стадиям, замена планет колониями, статистика и Ct.
Полные профили, отдельные прогоны и контрольные суммы: `flow_commit_step1_results.json`. Базовая версия: `413f2be9044090c878c2909dd9d0646f77513a5f`.
Для замера текущей версии на тех же входных файлах:
```sh
godot --headless --path . --script res://tests/benchmark_civilization_flows.gd -- res://tests/artifacts/all_objects_speed6.adventure.json 0.2 profile cycles=20
godot --headless --path . --script res://tests/benchmark_civilization_flows.gd -- res://tests/artifacts/many_objects_fragmented_stars_cycle.adventure.json 0.2 profile cycles=20
```
## Повторное использование общих количеств — 2026-10-08
Второй этап: общий точный снимок передаётся между фазами цивилизационных потоков, колонизации и коррекции ёмкости. Переходы и выдачи обновляют только затронутые количества; перенос между владельцами сохраняет общую численность. Периоды стадий, дрейф и поклонение используют актуальные количества этого интервала. Автоматическое создание разных типов звёзд также использует общий снимок: успешная пробная операция вычитает расходы, отказ сохраняет исходный снимок. При внешних изменениях используется обычный пересчёт. Снимки не записываются в сохранения.
Сравнение с версией после первого этапа. На двух одинаковых диагностических сохранениях выполнены пары до → после → после → до: по 20 циклов на прогон, по 40 циклов на модель и сохранение. Скорость 6, интервал 0,2 секунды, CPU-профиль включён, UI отсутствует. Каждый прогон полностью обработал 400 000 игровых лет. Состояния валидны, входные SHA-256 не изменились.
| Сохранение | До, мс | После, мс | Сокращение | Полных циклов/с после |
|---|---:|---:|---:|---:|
| Все объекты | 377,185 | 367,326 | 2,61% | 2,722 |
| Много объектов и партий | 443,163 | 422,973 | 4,56% | 2,364 |
Тяжёлое сохранение:
| Метрика | До | После |
|---|---:|---:|
| Полных сборок общих количеств за цикл | 15 | 7 |
| Сборка общих количеств, мс/цикл | 37,498 | 17,767 |
| Производство, мс/цикл | 37,554 | 20,316 |
| Применение потоков, мс/цикл | 91,626 | 89,259 |
| Завершение потоков, мс/цикл | 9,821 | 6,881 |
Время сборки общих количеств вложено в остальные фазы и не прибавляется к ним повторно. Проверка цивилизационной части отдельно дала небольшой выигрыш; основную экономию обеспечивает исключение повторных сборок при автоматическом создании звёзд.
Полные состояния обеих версий совпали после 10 последовательных сравнений: по пять на каждое сохранение, интервалы 0,2 / 0,53 / 0,31 / 0,2 / 0,2 секунды. Дополнительные проверки сравнивают снимки с полным пересчётом, контролируют неизменность входных снимков, отказ производства и каскадную деградацию. Выполнено 4321 целевая проверка без ошибок; полная регрессия всех наборов не запускалась.
Пять полных циклов в секунду пока не достигнуты: тяжёлый цикл составляет 423.0 мс; до 200 мс нужно ещё около 2.11-кратного ускорения. Следующая крупная статья — подготовка потоков цивилизаций, около 115.2 мс/цикл.
Полные результаты и контрольные суммы: `physical_totals_step2_results.json`. Базовая версия: `9357f757a95db96274d4e115c7e498b58eca6902`. Сохранение игрока не использовалось.
## Упрощение расчёта наград потоков цивилизаций — 2026-10-08
Третий этап убирает промежуточное динамическое число при умножении точного целого населения на float-ставку награды. Частное и дробный остаток вычисляются напрямую, а дробный перенос сохраняет прежнее округление. Это применяется к наградам войны, урона и колонизации; размеры населения остаются точными целыми.
Сравнение с коммитом `c429403` (после второго этапа): те же два диагностических сохранения, скорость 6, интервал 0,2 секунды, CPU-профиль включён. Порядок пар — до → после → после → до; два прогона по 20 циклов на версию и сохранение. Каждый прогон обработал 400 000 игровых лет, валидация сохранений прошла, SHA-256 входов совпали. Сохранение игрока не использовалось.
| Сохранение | До, мс | После, мс | Сокращение времени | Полных циклов/с после |
|---|---:|---:|---:|---:|
| Все объекты | 380,579 | 357,026 | 6,19% | 2,801 |
| Много объектов и партий | 432,912 | 409,268 | 5,46% | 2,443 |
Подготовка потоков уменьшилась с 111,980 до 87,832 мс на сохранении со всеми объектами и со 117,004 до 92,100 мс на тяжёлом сохранении — примерно на 21% в обоих случаях. Остальные основные участки остались в пределах погрешности замера.
Полные состояния до и после совпали после пяти последовательных интервалов на каждом сохранении (включая дробные интервалы). Тест оптимизаций прошёл: 1889 проверок без ошибок. Цель пяти полных циклов в секунду ещё не достигнута: тяжёлому циклу требуется ускорение примерно в 2,05 раза, чтобы уложиться в 200 мс.
Полные профили и SHA-256 входов: `civilization_flow_prepare_step3_results.json`.
## Проверка оптимизации частичного изъятия партий — 2026-10-08
Перенос связанного содержимого уже агрегируется по типам внутри поколения. Проверен вариант частичного изъятия, исключающий промежуточное сложение квоты с дробным переносом и последующее вычитание целой части. Возрастные интервалы и порядок поколений сохранялись.
Парный замер на тех же сохранениях: скорость 6, интервал 0,2 секунды, CPU-профиль, без UI; до → после → после → до, по 20 циклов на прогон (40 циклов на версию и сохранение).
| Сохранение | До, мс/цикл | После, мс/цикл |
|---|---:|---:|
| Все объекты | 350,516 | 349,835 |
| Много объектов и партий | 404,255 | 404,390 |
Изъятие партий на тяжёлом сохранении: 40,919 → 40,837 мс/цикл. Изменения полного цикла меньше 0,2%; подтверждённого выигрыша нет. Вариант **откачен**, код симуляции оставлен прежним. Полные состояния совпали в 10 последовательных сравнениях; границы партий — 117 проверок без ошибок. Входные файлы не изменены.
Результаты отклонённого варианта: `batch_withdrawal_step4_results.json`. Этот замер не доказывает достижение пяти полных циклов в секунду.
## Адаптивное упрощение симуляции — 2026-10-08
Добавлен runtime-контроллер качества, который измеряет сглаженное CPU-время полного цикла. Он повышает уровень упрощения при превышении бюджета 200 мс и снимает его после 30 циклов с запасом. Режим не сохраняется в файл: после загрузки точность постепенно подстраивается заново.
При нагрузке цивилизационный поток заменяется приближением не более чем с одним переходом на стадию за интервал. На наиболее грубом уровне типы возрастных партий делятся на две чередующиеся группы: каждая обрабатывается раз в два цикла. Временные группы при этом расширяются. Это сохраняет количества, но сдвигает сроки отдельных переходов и исключает несколько последовательных переходов цивилизации за один интервал.
Проверены два синтетических сохранения на Apple M4 Pro, Godot 4.7.2, headless, с CPU-профилем и интервалом 0,2 секунды. Каждый замер — 60 последовательных полных циклов; каждый запуск начинается в точном режиме и адаптируется по ходу серии.
| Скорость | Все объекты, мс/цикл (циклов/с) | Много объектов и партий, мс/цикл (циклов/с) |
|---:|---:|---:|
| 1 | 165,0 (6,06) | 128,5 (7,78) |
| 2 | 181,4 (5,51) | 131,8 (7,59) |
| 3 | 175,2 (5,71) | 145,0 (6,90) |
| 4 | 159,7 (6,26) | 177,1 (5,65) |
| 5 | 174,9 (5,72) | 185,6 (5,39) |
| 6 | 190,6 (5,25) | 184,4 (5,42) |
Среднее время на всех прогонах ниже 200 мс. Отдельные циклы всё ещё бывают длиннее: максимумы составили 203–367 мс на скоростях 3–6, включая первые циклы до срабатывания адаптации. Значит, замеры подтверждают требуемую среднюю пропускную способность на этом компьютере, но не гарантируют отсутствие кратковременных задержек. Android и работа с UI отдельно не проверялись.
Проверки: адаптивное качество — 18, хронология поколений — 28, границы партий — 117, оптимизации симуляции — 1889, планировщик кадров — 39; ошибок нет. Все 12 конечных диагностических состояний прошли валидацию. Хеши входных файлов: `44bee3b3753fa51615f766d8f800a10cc2b70c8e7fb4ea12b6e18da7f07a7d67` и `1e95ef398923f26b912a305c84f9b3eb502d24cb14e8ae687a4becccf047324a`.
Детали уровней, минимумы/максимумы и воспроизводимые результаты: `adaptive_quality_results.json`. Штатный benchmark принимает параметр `speed=1..6`.
## Адаптивная частота циклов 5 → 4 → 3 — 2026-10-17
Частота запуска полного цикла теперь снижается при устойчивой нагрузке: пороги шага — 0,2, 0,25 и 0,333 секунды. EMA времени расчёта переключает частоту вниз, когда цикл занимает больше 90% текущего интервала; возврат на одну ступень происходит после 30 циклов быстрее 65% интервала. Уровень частоты временный и после загрузки начинается с 5 Гц. Игровые часы продолжают накапливать весь прошедший интервал. Временное объединение партий масштабируется с выбранным интервалом, при этом при 5 Гц прежняя точность остаётся прежней.
Проверка сцены на диагностическом сохранении `all_objects_speed6.adventure.json`, скорость 6, Godot 4.7.2, Mac16,8. Сравнивались фиксированные 5 Гц и адаптивные 5/4/3 Гц, два прогона каждого режима в чередующемся порядке, по 10 секунд реального времени. Последняя транзакция каждого прогона завершалась до снятия результата.
| Метрика | Фиксированные 5 Гц | Адаптивно, установилось 3 Гц | Изменение |
|---|---:|---:|---:|
| Завершённые циклы/с | 4,64 | 2,96 | −36% |
| Средний FPS сцены | 22,60 | 64,35 | ×2,85 |
| p95 времени кадра | 115,6 мс | 66,5 мс | −42% |
| Средний максимум кадра | 227 мс | 205 мс | −10% |
| Опубликованные игровые годы/с | 99 017 | 98 049 | −1,0% |
На этих замерах реальное игровое время почти не замедлилось: симуляция завершала около трёх более крупных циклов вместо примерно 4,6 меньших. Средний FPS заметно вырос, но отдельные кадры всё ещё превышали 200 мс; это не гарантия отсутствия коротких задержек. UI-замер выполнен в headless-сцене на компьютере, поэтому его FPS не переносится напрямую на телефон.
Отдельно прогнан синхронный benchmark полного CPU-цикла на тех же двух тяжёлых сохранениях (скорость 6, 30 циклов × 2 повтора). При фиксированном шаге 0,2 секунды и адаптивном шаге итоговая обработка игрового времени за CPU-секунду выросла с 1,099 до 1,656 на сохранении со всеми объектами (+50,7%) и с 1,036 до 1,697 на сохранении со множеством объектов и партий (+63,9%). В каждом адаптивном прогоне частоты установились на 3 Гц; интервалы игровых часов сверены с запрошенными, все конечные состояния прошли проверку сохранения. Синхронный показатель показывает пропускную способность расчёта, а UI-прогон — фактический темп транзакций сцены.
Повторяемые результаты: `dynamic_cadence_results.json` (CPU-прогоны) и `dynamic_cadence_ui_results.json` (сцена и UI). Запуски выполняются скриптами `benchmark_dynamic_cadence.gd` и `benchmark_dynamic_cadence_ui.gd`; исходные диагностические сохранения не изменялись.