Разделить частоту обновления часов и расчёта симуляции

Счётчик времени UI обновляется до 10 Гц по запрошенному времени, а тяжёлые циклы по-прежнему запускаются с адаптивным интервалом и обрабатывают весь накопленный промежуток. Обновить тесты и описание модели.
This commit is contained in:
Kirill
2026-10-17 23:41:18 +03:00
parent 00b6192d19
commit 273093bd9e
14 changed files with 853 additions and 10 deletions
@@ -496,3 +496,23 @@ godot --headless --path . --script res://tests/benchmark_civilization_flows.gd -
Проверки: адаптивное качество — 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`; исходные диагностические сохранения не изменялись.
@@ -0,0 +1,172 @@
{
"cycles_per_run": 30,
"godot": {
"build": "official",
"hash": "ed1daf0bf001b61586d9930840f2f1394092c079",
"hex": 263938,
"major": 4,
"minor": 7,
"patch": 2,
"status": "stable",
"string": "4.7.2-stable (official)",
"timestamp": 0
},
"input_saves_unchanged": true,
"machine": "Mac16,8",
"repeats": 2,
"results": [
{
"applied_game_years": "600000",
"cadence_steps": {
"0.2": 30
},
"cpu_cycles_per_second": 5.5818824005294605,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"max_ms": 351.156,
"mean_ms_per_cycle": 179.15103333333334,
"mode": "fixed_5",
"p95_ms": 188.985,
"repeat": 0,
"requested_simulation_seconds": 6.000000000000003,
"save": "all_objects_speed6.adventure.json",
"simulated_seconds_per_cpu_second": 1.1163764801058926
},
{
"applied_game_years": "978333",
"cadence_steps": {
"0.2": 1,
"0.25": 1,
"0.33333333333333": 28
},
"cpu_cycles_per_second": 5.126867760649103,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 3.0,
"max_ms": 349.806,
"mean_ms_per_cycle": 195.05086666666668,
"mode": "adaptive_5_4_3",
"p95_ms": 214.441,
"repeat": 0,
"requested_simulation_seconds": 9.783333333333333,
"save": "all_objects_speed6.adventure.json",
"simulated_seconds_per_cpu_second": 1.671928541945013
},
{
"applied_game_years": "978333",
"cadence_steps": {
"0.2": 1,
"0.25": 1,
"0.33333333333333": 28
},
"cpu_cycles_per_second": 5.029407785556781,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 3.0,
"max_ms": 340.747,
"mean_ms_per_cycle": 198.83056666666667,
"mode": "adaptive_5_4_3",
"p95_ms": 233.775,
"repeat": 1,
"requested_simulation_seconds": 9.783333333333333,
"save": "all_objects_speed6.adventure.json",
"simulated_seconds_per_cpu_second": 1.6401457611787948
},
{
"applied_game_years": "600000",
"cadence_steps": {
"0.2": 30
},
"cpu_cycles_per_second": 5.403485464263869,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"max_ms": 351.698,
"mean_ms_per_cycle": 185.06573333333333,
"mode": "fixed_5",
"p95_ms": 195.396,
"repeat": 1,
"requested_simulation_seconds": 6.000000000000003,
"save": "all_objects_speed6.adventure.json",
"simulated_seconds_per_cpu_second": 1.0806970928527742
},
{
"applied_game_years": "600000",
"cadence_steps": {
"0.2": 30
},
"cpu_cycles_per_second": 5.218331511555821,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"max_ms": 373.477,
"mean_ms_per_cycle": 191.63213333333334,
"mode": "fixed_5",
"p95_ms": 250.5,
"repeat": 0,
"requested_simulation_seconds": 6.000000000000003,
"save": "many_objects_fragmented_stars_cycle.adventure.json",
"simulated_seconds_per_cpu_second": 1.0436663023111648
},
{
"applied_game_years": "978333",
"cadence_steps": {
"0.2": 1,
"0.25": 1,
"0.33333333333333": 28
},
"cpu_cycles_per_second": 5.21296979935453,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 3.0,
"max_ms": 373.168,
"mean_ms_per_cycle": 191.82923333333332,
"mode": "adaptive_5_4_3",
"p95_ms": 258.047,
"repeat": 0,
"requested_simulation_seconds": 9.783333333333333,
"save": "many_objects_fragmented_stars_cycle.adventure.json",
"simulated_seconds_per_cpu_second": 1.7000073734561718
},
{
"applied_game_years": "978333",
"cadence_steps": {
"0.2": 1,
"0.25": 1,
"0.33333333333333": 28
},
"cpu_cycles_per_second": 5.195109254879333,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 3.0,
"max_ms": 372.878,
"mean_ms_per_cycle": 192.48873333333333,
"mode": "adaptive_5_4_3",
"p95_ms": 254.848,
"repeat": 1,
"requested_simulation_seconds": 9.783333333333333,
"save": "many_objects_fragmented_stars_cycle.adventure.json",
"simulated_seconds_per_cpu_second": 1.694182851452316
},
{
"applied_game_years": "600000",
"cadence_steps": {
"0.2": 30
},
"cpu_cycles_per_second": 5.137478056546851,
"cycles": 30,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"max_ms": 375.784,
"mean_ms_per_cycle": 194.64803333333333,
"mode": "fixed_5",
"p95_ms": 255.446,
"repeat": 1,
"requested_simulation_seconds": 6.000000000000003,
"save": "many_objects_fragmented_stars_cycle.adventure.json",
"simulated_seconds_per_cpu_second": 1.0274956113093707
}
],
"speed": 6
}
@@ -0,0 +1,359 @@
{
"godot": {
"build": "official",
"hash": "ed1daf0bf001b61586d9930840f2f1394092c079",
"hex": 263938,
"major": 4,
"minor": 7,
"patch": 2,
"status": "stable",
"string": "4.7.2-stable (official)",
"timestamp": 0
},
"machine": "Mac16,8",
"results": [
{
"commits": 48,
"completed_cycles_per_second": 4.743091908967023,
"cpu_profile_usec_calls": {
"assign_homes": [
51095,
170
],
"civilization_flow_capacity": [
111005,
48
],
"civilization_flow_colonies": [
131724,
48
],
"civilization_flow_finish": [
325933,
48
],
"civilization_flow_ledger": [
928271,
48
],
"civilization_flow_plan": [
825706,
48
],
"civilization_operator_build": [
148485,
48
],
"civilization_operator_solve": [
104924,
2064
],
"enforce_capacity": [
626179,
170
],
"generation_products": [
235626,
74
],
"generation_withdrawal": [
455348,
97
],
"generations": [
3654469,
48
],
"initialize": [
215278,
48
],
"newborn_batches": [
237070,
3088
],
"physical_amounts_build": [
630353,
437
],
"production": [
1115470,
48
],
"trends": [
865132,
48
]
},
"elapsed_seconds": 10.119981,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"frames": 246,
"mean_render_fps": 24.584772192104204,
"mode": "fixed_5",
"published_to_requested": 0.9943600000000001,
"published_years": "1006667",
"render_max_ms": 237.132,
"render_p95_ms": 111.449,
"requested_years": "1012372"
},
{
"commits": 21,
"completed_cycles_per_second": 2.085573876935847,
"cpu_profile_usec_calls": {
"assign_homes": [
30276,
75
],
"civilization_flow_capacity": [
51694,
21
],
"civilization_flow_colonies": [
52773,
21
],
"civilization_flow_finish": [
142952,
21
],
"civilization_flow_ledger": [
309711,
21
],
"civilization_flow_plan": [
435139,
21
],
"civilization_operator_build": [
74385,
21
],
"civilization_operator_solve": [
87284,
903
],
"enforce_capacity": [
414865,
75
],
"generation_products": [
105449,
33
],
"generation_withdrawal": [
152279,
43
],
"generations": [
1503309,
21
],
"initialize": [
255626,
21
],
"newborn_batches": [
114834,
1633
],
"physical_amounts_build": [
274341,
193
],
"production": [
685165,
21
],
"trends": [
377582,
21
]
},
"elapsed_seconds": 10.069171,
"final_adaptive_quality": 3,
"final_cadence_hz": 2.0,
"frames": 879,
"mean_render_fps": 87.80117977216634,
"mode": "adaptive_5_4_3_2",
"published_to_requested": 0.9889800000000001,
"published_years": "989844",
"render_max_ms": 203.26,
"render_p95_ms": 42.712,
"requested_years": "1000874"
},
{
"commits": 21,
"completed_cycles_per_second": 2.0775335521668676,
"cpu_profile_usec_calls": {
"assign_homes": [
31004,
76
],
"civilization_flow_capacity": [
51172,
21
],
"civilization_flow_colonies": [
52782,
21
],
"civilization_flow_finish": [
142851,
21
],
"civilization_flow_ledger": [
309607,
21
],
"civilization_flow_plan": [
431321,
21
],
"civilization_operator_build": [
74854,
21
],
"civilization_operator_solve": [
86348,
903
],
"enforce_capacity": [
423638,
76
],
"generation_products": [
105537,
34
],
"generation_withdrawal": [
151611,
43
],
"generations": [
1516916,
21
],
"initialize": [
261806,
21
],
"newborn_batches": [
112492,
1621
],
"physical_amounts_build": [
278871,
195
],
"production": [
696352,
21
],
"trends": [
377969,
21
]
},
"elapsed_seconds": 10.10814,
"final_adaptive_quality": 3,
"final_cadence_hz": 2.0,
"frames": 880,
"mean_render_fps": 88.00051040296032,
"mode": "adaptive_5_4_3_2",
"published_to_requested": 0.9933700000000001,
"published_years": "994002",
"render_max_ms": 201.104,
"render_p95_ms": 42.207,
"requested_years": "1000640"
},
{
"commits": 47,
"completed_cycles_per_second": 4.646829581875308,
"cpu_profile_usec_calls": {
"assign_homes": [
50139,
165
],
"civilization_flow_capacity": [
108674,
47
],
"civilization_flow_colonies": [
129977,
47
],
"civilization_flow_finish": [
323458,
47
],
"civilization_flow_ledger": [
911542,
47
],
"civilization_flow_plan": [
807459,
47
],
"civilization_operator_build": [
147856,
47
],
"civilization_operator_solve": [
96154,
2021
],
"enforce_capacity": [
619397,
165
],
"generation_products": [
234744,
71
],
"generation_withdrawal": [
451797,
95
],
"generations": [
3665554,
47
],
"initialize": [
217827,
47
],
"newborn_batches": [
265766,
3178
],
"physical_amounts_build": [
623211,
428
],
"production": [
1142731,
47
],
"trends": [
856364,
47
]
},
"elapsed_seconds": 10.114423,
"final_adaptive_quality": 3,
"final_cadence_hz": 5.0,
"frames": 239,
"mean_render_fps": 23.87480014844331,
"mode": "fixed_5",
"published_to_requested": 0.9904200000000001,
"published_years": "992039",
"render_max_ms": 201.438,
"render_p95_ms": 114.211,
"requested_years": "1001635"
}
],
"save": "all_objects_speed6.adventure.json",
"speed": 6,
"wall_seconds_per_run": 10.0
}