Back in 2014 (http://www.wildfiregames.com/forum/index.php?showtopic=18466&p=300323), Yves noted that we were dumping JIT code a lot, and that we could gain a lot of performance by not doing that. This has been implemented since SM31, first in hacky ways, then with a flag in ScriptInterface.
However, we were running regular Shrinking GCs (every 500 turns), under the assumption that the memory benefit was good enough that it was worth the pain of dumping JITted code.
Following some better profiling, some talk with the SM guys, and a deeper look into the engine, I think these assumptions were wrong.
Essentially, the main benefit of a shrinking GC is that it dumps JIT code (memory gain), and it defragments memory (compacting in SM), allowing momre memory to be cleared. But this ultimately just means that we spend more time allocating / deallocating memory, since overall:
- Our JIT code was probably valid - we don't change pages or anything, it's basically the same exact stuff from start to finish.
- we will create new objects that will fill 'somewhat empty' arenas, so we will need to allocate new arenas anyways.
To summarise, an SM dev says that Shrinking GCs are intended to be used to 'save memory when the page is idle and we won't allocate much more stuff', which is basically 0% of the 0 A.D. use case.
The main consequence is that basically 100% of our code is JITted all the time. COmbined with removing Spectre mitigations, this really makes our JS quite fast. This will depend on the map, but overall we spend about 10% time in pure JIT code and 90% in C++ code, which is unlikely to get much better. In contrast, pre-spectre and with shrinking GCs, this is about 70% C++. We also spend less time parsing and compiling JS in side-threads, which is good since we're using those for pathfinding.
Note that these benefits are more obvious with the Spectre mitigations removed, because the spectre mitigations are only in 'full' JIT code, e.g. ionMonkey/Warp, and not in 'baseline' JIT code. Since most of our JS usecases are 'call C++', we actually take a huge performance hit and JIT code is not much faster than baseline code without it in general.
'What if we OOM'? Well the JS engine will do a last-ditch full shrinking GC then, so we don't gain much by having our own logic for that. I should point that OOM, in this instance, literally means that all arenas are allocated and full. THis is basically territory that we can't recover from, and a shrinking gc that dumps JIT code will only make the game run terribly slow, as we won't have room to compile more JIT code anyways.
Furthermore, this revamps the GC logic. We do not need, nor want, GC slices to take a long time. So this cuts the budget down, simplifies the logic, and lets em run.
This outdates D4816 and D4758.
We should still try and run those slices in non-sim-turns in visual mode, but that can be done later.