I have started looking at performance with StrangeIoC, because I am invoking quite a lot of simple commands in the game loop.
My first concern is per-frame overhead (esp. gc alloc) necessary for the strangeIoC infrastructure.
Disclaimer:
I know I am overusing strangeIoC in ways it was not primarilly ment to be used.
I am not criticizing how strangeIoC works, I am just trying to find ways to make it run with less overhead.
Findings below apply to stuff that is called ~hundred times per second, if you call something once per second, you would not probably notice it.
I have found following:
- a lot of strangeIoC code uses foreach, which is known to allocate memory, converting those to for loops will fix it (simple editor command)
- at some places, dictionary access can be simplified by using TryGetValue, this also reduces memory alloc a lot (Binder.GetBinding)
- command pooling did not fix much of the gc allocation, but helped (don't have exact numbers, sorry, no time for proper measurements)
- passing data to commands via signal seems to be more costly than injection from the context (see SignalCommandBinder.createCommandForSignal), so pass only those things, that are not obtainable any simpler way
- Injector.armorAgainstInfiniteLoops seems to consume memory a lot as well
- the main issue with GC allocation for me now is the use of reflection and object allocation
I have tried moving my frequent commands from setter injection to construction injection, which seems to use less memory (skips reflection for every property), but (stupid me), now you can't use pooling of course. So this is no-go for me.
As an alternative, I tried using a single method with [PostConstruct] and then inside calling injectionBinder.GetInstance<MyType>(); for each injected property. However, this also uses reflection to find the postconstruct method and costs some allocation.
One way to get rid of the reflection would be to introduce a special interface e.g. "BindingInitializer" interface with a postConstruct() method. This could be checked prior to the reflection.
The most extreme solution would be to leave all the setup, injections, unprocessed signal data, etc. to the Command directly.
To sum up:
- there is room for optimization in code
- I would gladly send you the changes I made in the, however, I am not familiar with the github contribution process :-(
- there should be a single way to setup a command for performance (even if not as flexible and code-pretty as current solutions)
- I would suggest to also review the injectionBinder.GetInstance<>() method and make it as optimized as possible
Thanks,
Josef