Turns out i discovered that actor destruction was very slow and i suspect that it still is with the GC. Howeven Odamex is fast in nuts.wad, it still has DObject::EndFrame but not DObject::DestroyScan nor player_s::FixPointers. And i don't know why. I've noticed it calls DThinker::DestroyAllThinkers() in DObject::::StaticShutdown tough.
Also in DObject::RemoveFromArray it adds "if(Inactive) return;"
According to randi on the GC:
randi wrote:this code only affects when thinkers are destroyed, not created. Previously, whenever a thinker was destroyed, it had to do a lot of work directly proportional to the total number of thinkers every tic. Now, that same work is still done, but it's aggregated and spread out across several tics.
None of this code was present in Doom originally. It was all added by me to make the engine more robust. (And also because saving a game would almost always crash without it due to significant changes between ZDoom's savegame format and Doom's savegame format.)
The old way
When an object's Destroy method is called, it gets added to a list of objects to delete. At the end of each tic, if there is anything in that list, the engine steps through every object in the game, looking for pointers to objects in the list. Any such pointers it finds are nulled, and then the objects are all deleted.
The new way
When an object's Destroy method is called, it sets a flag indicating that this object wants to die. Most pointers to objects are wrapped inside a template class that checks for this flag and nulls the pointer if it's set. In addition, while the collector is running through the mark phase, it also nulls any pointers to objects with this flag set. Eventually, there will be no more pointers to the object left, and it will be collected as normal, unreachable garbage.
It would be cool to speed up this old version, DObject::DestroyScan nulls the pointers but it's not in Odamex yet it somehow works.
Some profiling, versions above 1.19 were very slow in nuts.
- Code: Select all • Expand view
Function Name Exclusive Samples Exclusive Samples % Inclusive Samples Inclusive Samples % Source Line Begin Source Character Begin Source Line End Source Character End
DObject::EndFrame 10.426 35,65 % 10.426 35,65 % 429 0 429 0
PIT_CheckThing 994 3,40 % 994 3,40 % 826 0 826 0
P_BlockThingsIterator 930 3,18 % 930 3,18 % 739 0 739 0
Function Name Exclusive Samples Exclusive Samples % Inclusive Samples Inclusive Samples % Source Line Begin Source Character Begin Source Line End Source Character End
[ntdll.dll] 8.318 13,67 % 8.318 13,67 % 0 0 0 0
FMultiBlockThingsIterator::Next 3.626 5,96 % 3.626 5,96 % 1.099 0 1.099 0
FBlockThingsIterator::Next 2.582 4,24 % 2.582 4,24 % 987 0 987 0
FThinkerCollection::RunThinkers 2.010 3,30 % 35.002 57,50 % 114 0 114 0
FThinkerIterator::Next 1.728 2,84 % 1.728 2,84 % 965 0 965 0
[openal32.dll] 1.619 2,66 % 1.904 3,13 % 0 0 0 0
I was looking at the wall near the start in software, the second one is from modern GZDoom. The mayority of calls to functions in ntdll.dll were from _malloc_base and _free_base and that looked suspicious. I mean i don't think that work to destroy the thinkers is free now. BTW i tried with 2.3.1 and that one doesn't have portals, FPS oscillated between 10 and 1 vs 1 all the time in 2.1.7. Just some thoughts but i'd really like to speed up that old version anyway.