Add comprehensive tests and optimizations for simulation and UI performance

- Introduced a new benchmark save script to create a stress test scenario with extreme values for simulation performance.
- Added a full UI benchmark script to measure frame rates and performance metrics during UI interactions.
- Implemented tests for coarse generations to ensure population transitions are handled correctly.
- Created tests for extra parameters to validate the loading and application of configuration settings.
- Developed simulation optimization tests to verify the efficiency of population drift and rounding mechanisms.
- Added split optimization tests to ensure accurate allocation and rounding behavior in population management.
- Included startup parameter tests to confirm the correct initialization of global parameters before scene readiness.
- Enhanced the audit rounding ledger to compare selective and full rounding results for consistency.
This commit is contained in:
Kirill
2026-10-05 22:16:59 +03:00
parent 6f6a1be3bd
commit e48d4bbe88
57 changed files with 37279 additions and 784 deletions
+109
View File
@@ -1,5 +1,24 @@
# Проверки поэтапного переноса из Owniverse.U
`test_simulation_optimizations.gd` сравнивает прямые формулы дрейфа с прежней
матрицей, включая целые количества больше E27 и накопленные остатки.
Тестовый ledger сверяет выборочное округление с полным на каждом поколении
нагруженной симуляции. `test_ui_updates.gd` проверяет обновление по публикации,
выбору объекта и изменению параметров мира, а также пропуск повторных расчётов
для неизменившегося состояния.
Динамический размер партий проверяется в `test_batch_boundaries.gd`: скорости
1–6, сохранение больших целых количеств и дробных остатков, повторное
укрупнение и снижение скорости. Высокие скорости допускают приближение
времени переходов; сравнение со старым состоянием целиком не является
проверкой эквивалентности такого режима.
`test_coarse_generations.gd` проверяет отсутствие повторного перехода C0.0,
C0.1 и C0.2 внутри одного интервала, старое смещение сетки партий,
продолжение эволюции в следующем интервале, большие целые количества и
дробные остатки. `test_frame_evolution.gd` сравнивает целый и разбитый по
кадрам расчёт, включая возобновление сохранённого незавершённого шага.
## Производительность на сохранении
```sh
@@ -205,3 +224,93 @@ Stage вызывает `evolute_frame`: транзакция получает б
15.9 FPS (максимальный кадр 98 мс), большие количества 17.5 FPS (106 мс),
много партий 16.3 FPS (97 мс).
Это FPS отрисовки, а не число завершённых транзакций симуляции в секунду.
Индекс партий переиспользуется внутри одной транзакции, отдельно для каждого
массива партий. Замена массива при изъятии или переход к другому состоянию
сбрасывает индекс. Сортировка выполняется при нарушении порядка новых окон,
а не после каждого добавления в уже существующее окно. `test_batch_boundaries`
проверяет объединение, раннюю вставку, замену массива и изоляцию состояний.
На копии текущего сохранения с 785 партиями шесть шагов на скорости 6:
среднее время 167 → 145 мс; полное состояние после шести шагов совпало точно.
Следующий этап исключает арифметическую работу при прибавлении нуля,
временные знаменатели при умножении целых блоков и нулевые вклады этик.
На той же копии сохранения среднее время шага скорости 6 снизилось с 145
до 138 мс; полный результат после шести шагов совпал с исходным состоянием.
Тест появления разума задаёт свой progress явно, поскольку проверяет
сохранение хозяина планеты, а не актуальное значение коэффициента баланса.
Следующие шесть оптимизаций: однократное изъятие умирающих партий;
поверхностные снимки неизменяемых таблиц связей; пропуск планирования
цивилизаций без переходов; кэш нормализованных этик и произведений поклонения;
пропуск укрупнения для нуля/одной партии; кэш вероятностей переходов.
Кэши принадлежат миру и не входят в сохранение. Изменение количества,
этик, коэффициентов правил или модификаторов обнаруживается по значениям.
Суммирование поклонения сохраняет прежний порядок дробных операций.
`test_simulation_optimizations` проверяет также обновление этих кэшей.
Полное состояние совпало с реализацией до этих шести изменений после каждого
из восьми шагов на скоростях 1, 4 и 6, отдельно на большом фрагментированном
сценарии и на диагностической копии сохранения (48 сравнений).
На M4 Pro шесть шагов по 0.1 секунды скорости 6: 103.3 мс первый,
70.9–76.0 мс последующие; пропускная способность без UI 1.278.
Замер 600 кадров с реальным UI: 12.24 FPS, p95 97.16 мс, максимум 104.86 мс,
520 завершённых транзакций, отношение обработанного времени к поступившему
1.057. Замер включает сокращение накопленного отставания сохранения;
это результат конкретного сценария на Mac, а не гарантия для Android.
Адаптивный шаг на скоростях 4–6 выбирает 0.1, 0.2 или 0.5 реальной секунды.
Долг больше двух шагов повышает ступень, меньше половины шага понижает её.
Шаг ограничен доступным запрошенным временем. Скорости 1–3 сохраняют 1/60;
смена скорости сбрасывает ступень. Возобновляемая транзакция сохраняет точную
границу из checkpoint, адаптация применяется к следующей транзакции.
Бюджет кадра остаётся 40 мс; ширина временных партий не меняется.
`test_frame_evolution` проверяет ступени, гистерезис, сохранение долга,
переключение скорости, возобновление и совпадение с прямым расчётом того же шага.
На свежей диагностической копии сохранения с долгом 407.79 млн лет:
600 кадров реального UI на M4 Pro дали 18.05 FPS (p95 92.91 мс,
максимум 122.45 мс), поступило 3.335 млн лет, обработано 6.480 млн:
пропускная способность 1.943 вместо 0.787 при фиксированном шаге 0.1.
Разбиение времени влияет на дискретные производство и глобальные параметры;
адаптивные шаги не обещают совпадения результата с последовательностью 0.1.
Дипломатический drift использует шесть взвешенных вкладов вместо матрицы
пар этик: вес = сумма вкладов + 195 × свой вклад − противоположный вклад.
Для колониальной матрицы коэффициенты 9, 951 и 5 соответственно.
Целая численность и механизм сохранения ошибок распределения не меняются,
но порядок операций над дробными весами отличается от матричного варианта.
Тест сравнивает с матрицей на точно представимых коэффициентах и проверяет
целочисленное сохранение популяций до 1e40 на десятичных коэффициентах.
Пустые популяции пропускают drift; численность выходов суммируется один раз.
На профильной копии при шаге 0.5 число вызовов снизилось 1038 → 849
за шесть шагов, но время drift осталось около 303 мс суммарно;
заметного ускорения полного расчёта в этом сценарии не зафиксировано.
`test_split_optimizations.gd` сравнивает распределение и все сохранённые
остатки с прежним scalar split в последовательных вызовах: пустые ветви,
единственная ветвь, равные веса, десятичные веса, положительные/отрицательные
остатки, количества до 1e80. Также проверяет grouped mul_div против scalar.
Split переиспользует разложение количества и знаменателя между ветвями,
кэширует ключи остатков (не более 512 наборов) и получает веса дрифта массивом.
Вторая нормализация пропускается только при целых долях с нужной суммой:
при дробях даже единичное отношение может изменить округление, поэтому
прежний путь сохраняется. Единственная положительная ветвь обрабатывается
напрямую только при целом количестве, неотрицательных весах и нулевых остатках.
На профильной копии время drift за шесть шагов 0.5 снизилось примерно
303 → 287 мс, но общее время осталось около 1.31 секунды.
Обычный drift сокращает целое количество из отношения
count*weight/(200*count), колониальный — из отношения с 1000.
Целая часть делится на малый знаменатель; для дроби используются исходные
масштабированные числитель и знаменатель, чтобы сохранить float округление.
`test_split_optimizations` проверяет совпадение со scalar mul_div до 1e80.
Производство новорождённых сохраняет только created_from → amount вместо
глубокой копии партий. Повторное мгновенное рождение с теми же сроками,
длительностью и сеткой сразу добавляется в найденную партию.
Индекс ближайшей границы позволяет повторным проходам пропускать будущие
партии; замена массива, добавление и масштабирование сбрасывают индекс.
Тест границ проверяет объединение и сброс обоих индексов.
Адаптивный шаг дополнительно учитывает сглаженное отношение реальной
длительности транзакции к обработанному времени. Если отношение выше 0.85
и долг больше одного шага, ступень увеличивается раньше порога двух шагов.
Долг и граница сохраняются как прежде; измерения являются временным кэшем.