Reusing pooled FSM allocates memory whereas BT doesn't

NodeCanvas Forums Support Reusing pooled FSM allocates memory whereas BT doesn't

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #11345
    jakko
    Participant

    Hi,
    I pool and reuse most of the objects in the game and found that when I restart a FSM (using StartBehaviour()) it keeps allocating memory every time I do that, causing noticeable frame rate drops. I expected it to only do that the first time I start it.

    I created a BT doing the same thing using the exact same actions, variables and condition checks and found that the BT doesn’t allocate memory after the first start. However, I’d rather use the FSM because it is better suited for the things it needs to do, the BT gets too complex.

    Could you fix this in the State Machines, so that they only allocate memory the first time you start it? At the moment they are not usable because of the performance impact.

    Best,
    Jakko

    #11355
    Gavalakis
    Keymaster

    Hello,

    I’ve made some considerable improvement to that for the next version.
    Thanks for your input.

    Join us on Discord: https://discord.gg/97q2Rjh

    #11362
    jakko
    Participant

    That sounds great, looking forward to that!

    I also found that most of the actions and conditions interfacing with the agent’s code allocate memory every tick. Making them unusable for me. Probably because of the boxing and unboxing of parameters, I didn’t dive that deep into the code to figure that out.
    So I have created a set of ActionsTasks and ConditionTasks that use delegates and typed parameters that don’t allocate the additional memory when used. Also they are a bit faster as the interface is less abstract.

    The drawback is that they are not as flexible as the included Script Control tasks, but 9 out 10 times I’m interfacing with fairly simple methods using no parameters, or just one. So far I’ve used them on desktop, iOS (Mono and IL2CPP) and WebGL without any problems.

    I could send them to you if you like.

    Best,
    Jakko

    #11363
    Gavalakis
    Keymaster

    Hey,

    For your information, the parameters used in Tasks, are generic (BBParameter) and designed to work in a way that there is no value boxing/unboxing to avoid allocations throughout the whole pipeline that they are used.

    The Script Control Tasks in the “Standalone” category specifically, already turn methods and properties into delegates and everything is strongly typed, so that once again boxing/unboxing is totally avoided. Please take a look at the ReflectedAction and ReflectedFunction for example on what is going on behind the scenes if you want.

    The only exception to the above is when using the Script Control Tasks under the “Multiplatform” category, within which there is no delegation because (as you probably already know) AOT compilers like iOS, need to know the all the delegates type signature that will be used, “ahead-of-time”, and which is practically impossible to foresee for all possible combinations of parameter/return types that exist in a multi-parameter method for example.

    If you interface only with methods with one or no parameters (or properties), you can still use the Script Control Tasks under the “Standalone” category to take advantage of the strongly typed delegation that already takes place to avoid value boxing/unboxing even in AOT platforms.

    Thanks.

    Join us on Discord: https://discord.gg/97q2Rjh

    #11375
    jakko
    Participant

    Okay, thanks for the info.
    There must be something else going on then, I found that using the included standalone actions allocate memory on very call. Both in the game and in additional test I’ve run. Also the standalone actions didn’t work on iOS when I tested them, while the delegates in the actions I’ve created do work.

    Best,
    Jakko

    #11376
    jakko
    Participant

    Just to verify that I’m not seeing things that are not there I’ve created a test project that instantiates 100 state machines that call a “public NodeCanvas.Status NCUpdate(int value)” method on the agent until it returns Success. Three different ways are used to call that method.
    These are the results. (Simplified delegate action is my own implementation)

    Unity 5.4.1f1, 100 fsm’s in editor:
    Standalone Only/Implemented Action: 2 kb per frame
    Multiplatform/Implemented Action: 27 kb per frame
    Simplified delegate action: 0 kb per frame

    Unity 5.4.1f1, 100 fsm’s on iOS device (IL2CPP)
    Standalone Only/Implemented Action: DOES NOT WORK
    Multiplatform/Implemented Action: 17 kb per frame
    Simplified delegate action: 0 kb per frame

    Where the memory allocations come from when using the included script actions I don’t know, but they do definitely happen! And this happens with most of the Script Control actions and conditions, not just the ones that return a Status.
    The implementation I have created shows that it is possible to create an interface with scripts that don’t have this overhead and can work on AOT platforms. So I think there is room for improvement for the included Script Control actions.

    Best,
    Jakko

    #11384
    Gavalakis
    Keymaster

    Hello Jakko,

    Thanks for performing the tests.
    The “Standalone” versions of Script Control tasks will only work in iOS after you have created the AOTClasses.cs file through the Preferred Types Editor as explained at the top of the ReadMe file as well as in the documentation. This is not directly relevant to these tasks but rather required for the whole framework to work correctly in iOS (or other AOT platforms).

    Regarding the tests, there is value boxing taking place in the return value of a method for ValueTypes such as Status is. This is not happening for parameters though.

    If your custom Script Control task and your way of creating delegates can work with all methods/properties regardless of return/parameter types and number of those parameters, by all means I would be more than happy to learn how you do it and to improve the existing Script Control tasks with your own implementation! 🙂
    Does your way of doing this, supports all return/parameter types, as well as most importantly, different number of parameters?

    Let me know.
    Thanks!

    Join us on Discord: https://discord.gg/97q2Rjh

    #11393
    jakko
    Participant

    Hi,

    No, there is no boxing with return values like Status, or for ConditionTasks. I haven’t looked at supporting more than one parameter yet as I don’t need it at the moment. I just wanted them to be as lean as possible and took a different approach. So to support certain return types and parameter types, you first need to declare them. E.g. “public class CheckFunctionBoolFloat : CheckFunctionDelegate<bool, float>” adds a ConditionTask that supports “public bool CheckMe(float value)” methods.

    Not as flexible as your one size fits all implementation, but easy enough to use in practice. And in my case adding multi-platform support with a low performance footprint and without any additional memory allocations was far more important than ease of use.

    I can send you the code (not sure how, didn’t see an option to pm you on this forum), maybe there is something in it that you can use for your flexible implementation.

    Best,
    Jakko

    #11394
    Gavalakis
    Keymaster

    Hey,

    Thanks. I would be more than glad to take a look at your implementation and see if something can be made into the current one to improve it in any way. Indeed though, the currently included implementation is meant to be an easy -fit all- way to call any method without coding, hence why with some coding like you are doing, things can of course be made faster. 🙂

    If you don’t want to post them public, please feel free to email them to support_AT_paradoxnotion.com.

    Thanks again for your time!

    Join us on Discord: https://discord.gg/97q2Rjh

Viewing 9 posts - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.