Anyone have a good Instance pooling demo?

Discussion in 'Programming' started by csanyk, Dec 14, 2016.

  1. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    Looking for a well-coded demo showing how to do instance pooling in GMS.

    For the uninitiated, instance pools are a design pattern that is useful for performance optimization when you are constantly creating/destroying lots of intstances. Rather than creating and destroying instances every step of the game, you create a "pool" of (deactivated) instances, as many as you would need for the game, ahead of time, which you manage by activating/deactivating as needed. When you'd ordinarily destroy the instance, you simply deactivate it, to re-use it when you need another one.

    As long as activation/deactivating is cheaper than creation/destruction in terms of CPU, it is beneficial to performance.
     
  2. Mike

    Mike nobody important GMC Elder

    Joined:
    Apr 12, 2016
    Posts:
    2,288
    Just deactivate, and then use the instance ID as the "handle" to allocate/deallocate


    https://books.google.co.uk/books?id=iYALAAAAQBAJ&pg=PA393&lpg=PA393&dq=Stack+Allocation+game+programming+gems&source=bl&ots=ZZQX1ZggO0&sig=6k4y1JxNYcmcfmFMelIXv8YAlsY&hl=en&sa=X&ved=0ahUKEwjT04fi9fPQAhVHIsAKHYSeBxcQ6AEIHzAB#v=onepage&q=Stack Allocation game programming gems&f=false

    Basically, create a ds_stack, then anything you free you deactivate and push on the stack.

    When allocating, if the stack isn't empty, pop off the ID. If it IS empty, do an instance_create() on it. When it gets free'd it'll go back into the stack list. You can even decide that if you go over a certain number of "free" items, to delete it. So you only ever keep a max stack of "N" free ones.

    This is the fastest allocation system I've come up with.
     
    csanyk likes this.
  3. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    Thanks for the suggestion to use a ds_stack.... I had been working on a demo implementation using an array to track the pool, and was finding that the overhead to manage the array and track which instances were active was nullifying any advantage I gained by pooling vs. newing. As soon as you suggested a stack, I realized it was a lot more self-managing due to the nature of the data structure. I'll have to try this approach and see how much of a difference it makes.
     
  4. obscene

    obscene Member

    Joined:
    Jun 21, 2016
    Posts:
    2,197
    I've been considering how to do this too so glad you asked and Mike answered. :D

    I'm trying to do it with sparks that emit from lasers and bounce on the floors and fade away, so each time they are activated I also need to reset their speed, direction, size, color, alpha, etc. When changing rooms I'm assuming deactivated sparks would be destroyed and I'll need to recreate them again right quick and deactivate them to have them ready for use?
     
  5. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    Yes, non-persistent instances are destroyed when the room charges.
     
    obscene likes this.
  6. Mike

    Mike nobody important GMC Elder

    Joined:
    Apr 12, 2016
    Posts:
    2,288
    pretty sure deactivated persistent ones are too.... But you'd have to check.
     
  7. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    Good to know... I don't use persistent objects or rooms much/ever, but if I did that would surely have tripped me up!
     
  8. AdventurousDrake

    AdventurousDrake Member

    Joined:
    Sep 11, 2016
    Posts:
    12
    Total noob to Game Maker here, but in GameSalad they solved it by creating the needed objects off-screen and just moving them in and out of view as needed. Not sure if this is possible in GMS or if it's a good solution.
     
  9. FrostyCat

    FrostyCat Member

    Joined:
    Jun 26, 2016
    Posts:
    3,240
    You can sweep these instances under the rug the same way in GM, but the problem is that they would still take up CPU cycles by processing its Step and Draw events, being counted in collision checking, etc. The point of deactivating the unused instances is to stop all that until they're needed again.
     
    foxtails and csanyk like this.
  10. obscene

    obscene Member

    Joined:
    Jun 21, 2016
    Posts:
    2,197
    I just finished my sparks scripts, first time trying pooling, it was easy and efficient. :) Only thing I did different from what Mike suggested was I make a pool of 200 of them on Room Start (after clearing the stack of cours) so I never have to create them on the fly. When I normally destroyed the sparks I now execute a user event that pushes their IDs onto the stack and deactivates them.
     
  11. AdventurousDrake

    AdventurousDrake Member

    Joined:
    Sep 11, 2016
    Posts:
    12
    Ah ok, so deactivating them is even more efficient then, good to know.
     
  12. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    I've written an article on my experimentation with instance pooling:

    https://csanyk.com/2016/12/gms-instance-pooling-performance-optimization/

    Curiously, I did not find that it offered a great boost in performance, at least not on my system, unless the Create/Destroy events were heavy.

    Using the profiler on my demo project, which you can download from the above article, I found that when my instances are simple and light weight, calling Create/Destroy incurs about the same amount of overhead as does managing the stack, activating/deactivating, and resetting the state of the instances for re-use.

    This only appears not to be the case if the instance has a lot of work to do at Create (or Destroy, I suppose), which does not need to be repeated if the instance is deactivated and reused.

    Pretty interesting findings. I'd love to know whether this changes on different build targets. If anyone would like to download my demo projects and test them on Mac OS X, Android, iOS, etc., I'd love to hear your findings.
     
  13. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,824
    Because you are deactivating instances possibly. also I think I saw russel say they improved the speed of instance create/destroy somewhere



     
  14. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    376
    There's a nice implicit benefit of instance pooling: It makes handling multiplayer netcode for complicated scenes easier if you can refer to instances by a common index across all machines.
     
    csanyk likes this.
  15. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    I hadn't even contemplated that... but that's a good point.

    From running the demo project in the code profiler, I was able to see that the GML code I wrote only uses about 10% of the overall CPU time, while the Engine takes about 90%.

    So, it turns out that the Create-Destroy approach and the Instance Pool approach were using about the same amount of CPU, just with different approaches. In the instance pool, Activating/Deacting was only part of the overhead -- there was also popping/pushing id's to the ds_stack, as well as re-setting some variables in the instances when they were re-used. It turns out that the sum of all of the above is about equal to the overhead taken up by Create-Destroying bullet instances.

    If I didn't have to reset the state of a re-cycled instance, or if doing so could be done much more cheaply than creating a new instance, it would be advantageous to use pooling.

    I'll probably update my article on the blog later with some figures that I gleaned from the profiler.
     
    Juju likes this.
  16. Mike

    Mike nobody important GMC Elder

    Joined:
    Apr 12, 2016
    Posts:
    2,288
    I'd also consider that memory allocation is slow - done by the engine, and that constant freeing and reallocating will fragment memory, and cause more cache misses overall. Pooling keeps things much more local, and it'll stay in the cache.
     
    csanyk likes this.
  17. csanyk

    csanyk Member

    Joined:
    Jun 20, 2016
    Posts:
    812
    Appreciate that input, I think I speculated to this effect in my article, but now I can update it with confirmation :) Thank you!
     
    Last edited: Dec 20, 2016

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice