Reduce realloc() count in 4.2 beta #2325
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hello.
I have several improves for the function spSkeletonBinary_readSkeletonData() which should improve the allocation for spSkeletonData* struct data as a whole.
In our games, we actively use spine graphics in all aspects, including UI, core gameplay, and even in metagame maps. At some point, we found that the default allocator (malloc/realloc/free) wasn't fitting our needs very well.
In a special test project (a clone of a real game), I logged the allocation of 211.18Mb in RAM in total after the game loaded for all spSkeletonData structures, and this is about 2 million+ allocates, mostly 16-32 or 64 bytes each. Clearly, we need our own game allocator in such a situation :)
I worked on the custom allocator, which is a regular linear allocator that simply allocates a large block of memory at the beginning and then moves its internal pointer, giving spine lib the requested bytes bit by bit.
For such an allocator, it was critical not to receive frequent realloc or free, so I also decided to study the possible call sites of REALLOC in spSkeletonBinary_readSkeletonData() and potential improvements.
So, in this patch, I tried to improve the situation, slightly modifying the spine runtime code, this does not lead to any major modifications, or problems, it just significantly reduces the amount of REALLOC.
Here are the improvements:
In spAnimation_create(), I calculate exactly how many timelineIds I need in the totalCount variable. Up to 1/3 of all reallocs were here, I also checked the performance it turns out that to calculate 1 additional for() is much faster on average than several realloc calls (for our spine objects, the typical totalCount value was about 600-1k bytes). Thus, by calculating exactly how much is needed, you can avoid realloc here at all.
In the SkeletonBinary.c _readVertices() function, you can just allocate weights and bones of the right size right away, we already have all the information for this. Maybe there used to be some other code here that was removed, and now all the logic can be greatly simplified, while also removing reallocs.
Also directly in spSkeletonBinary_readSkeletonData() there are several /* TODO Avoid copying of name */ for bone, slots, and constraints. However, the refinement requires modification of spBoneData_create, spSlotData_create etc. Where now no MALLOC_STR is done, but simply taking the string through CONST_CAST.
Well, of course, this requires also to fix SkeletonJson.c where now MALLOC_STR is done.
That is, before there were: 2 copies of names for SkeletonBinary and 1 copy if SkeletonJson, and now 1 copy in SkeletonBinary and also 1 copy in SkeletonJson. This doesn't give much gain in terms of extra malloc/free but still good, and trivial to fix /TODOs/
After a series of tests, I found that previously about 12.42% of the memory allocated by the linear allocator was lost due to realloc work in a new place (not so much actually, I thought there would be more), now with such improvements the figure became only 4.61%
I hope you will find such improvements interesting.
Best regards,
Dmitriy Sechin | Programmer in G5 Games