valueerror

game is getting slower over time - already reusing everything (functions, sprites, tweens) - help ?

Recommended Posts

in my game (an endless runner) there are only 10 sprites and i'm constantly killing and resetting them.. it's simple.. if they passed the world height they get killed and reset on top of the world..  then they fall down again..

 

now i am searching for the reason why my game drops down from 60fps to 5 fps after running for 20 minutes .. (it's always the same state that is running)

 

 

first i suspected one or two sprites that are created and destroyed in some rare cases.. so i got rid of them and started reusing the same sprites

then i suspected all those anonymous functions that are created in a loop timer that runs over 3 groups (forEach) and always creates new anonymous functions. i got rid of them and now use predefined functions 

 

the game is still gettting slower and slower.. so there is only one thing left that comes to my mind..

 

game.add.tween

 

this is also called 4 times when a sprite is killed and revived because the sprite dies with 2 tweens and gets reborn with 2 tweens...  i got rid of them by defining them once and just starting the same tween again when it's needed..

 

now i'm stuck..

 

 

what else should i look out for?   

thx in advance :)

Share this post


Link to post
Share on other sites

chrome dev tools are always open here..    the memory consumption rises over time... starts with 15-35 and when fps are as low as 5fps it resides at 50-70 mb..  but this is still ok IMHO..

all functions that need 2ms at the beginning need 25ms or even more after 30 minutes..  it just doesn't make sense..  

 

the rest of the system is snappy as ever, other browser tabs are also not affected

 

restarting the state gets everything back to normal..  60fps steady.. not a single framedrop..

 

i also tried with firefox.. but after several minutes the same thing happens...

 

:wacko:

Share this post


Link to post
Share on other sites

post-6912-0-27220400-1428774405_thumb.jp

oke..  profiling got me at least somewhere ...  the heap size starts with 12  goes up to 22 then the GC kicks in and it goes back to 12  - after 2000 meters (it's an endless runner ^^)  the heap size is at 20 goes up to 36...  this is slowly rising over time but is not the source of the problem just one side effect..

 

the one thing i noticed is that somehow the amount of listeners is rising very fast.. i start with 20 and after 2000 meters i already am at 1250 listeners..   

 

i'm going to investigate that (i thought i am not creating new listeners but maybe i overlooked something.

 

could this be the problem ?????

Share this post


Link to post
Share on other sites

listeners are added by .add()   right? 

 

the only thing that is constantly recurring is the following..  nothing else is ever added to the game in the update loop but this:

game.time.events.add(randomtime, resetobject, this);

these "timeouts" make sure that the objects are reset after random time-periods so the whole thing feels more natural..  

 

these events should be removed right after the event is fired as far as i know..   

 If true, the timer will automatically destroy itself after all the events have been dispatched (assuming no looping events).

 

 

how else should i implement a timeout ??

Share this post


Link to post
Share on other sites

I don't believe the game.time.events (timer) will ever destroy itself, that would be bad.

 

I myself would implement my own timing logic and random time periods from the update(), not a fan of the whole phaser timing thing, it's clunky.

Share this post


Link to post
Share on other sites

i'm going to try that too (using my own timing method) 

the crazy thing is.. i removed those timers and listeners are still getting more and more..  wuahhaa.. this is making me crazy...

 

i'm going for the "brute force" method now..  commenting out everything and then slowly adding it back while constantly observing the whole thing

Share this post


Link to post
Share on other sites

pfffffffffft...  you know what ads those listeners (or at least most of them - could still be something else too)

game.sound.play('moo1',0.2);

every time a sound is played .. a listener is added ??? wtf ??  

 

going to uncomment ALL sounds for a test and then report back ...

 

 

EDIT:  ALL listeners that chrome logs are added by game.sound.play..  all of them..  if i comment out all sounds the listener number stays at 23

 

now i have to let the game run for 20 minutes to see if this has some effect on the performance over time  :huh:

Share this post


Link to post
Share on other sites

GOT IT !!!

game.sound.play('something');

is the cause of the constantly growing amount of "listeners" AND the cause for the performance loss over time..  

 

the JS HEAP is still growing slowly over time (from 16-26mb maximum to 20-35mb maximum) but it stays there..  

the game just ran for 6000 meters and is still at 60fps :)

 

 

soooooo...  this is a phaser bug - isn't it ?

Share this post


Link to post
Share on other sites

Hmmm.  I may be seeing the same thing.  I don't understand how to use the Chrome timeline debugging tools all that well, but I see a steady rise of listeners every time I record a session in which I am playing a the game I am developing - as I play, sounds also play upon certain actions.  If I just record a session where I play a little bit at first and then let it sit idle, I see that listeners have climbed only during the time I was actively playing and causing sounds.

 

This seems to support the assertion of valueerror.  If it is indeed a Phaser bug, I hope Rich does his usual magic and gets it fixed pretty quickly.  I was planning to submit the game to the Apple store this weekend.  :mellow:

Share this post


Link to post
Share on other sites

You are using the soundManager in a wrong way. I don't know if it will solve all the problems, but I hope it will.

game.sound is a reference to the soundManager. When you call its play method, it adds a new sound object and starts playing it; so each time you play a sound you are actually adding a new sound without deleting the previous one. That method actually returns a sound object, so you could use it to create all the sounds that you need to play right away and keep a reference to them so you can play them again:

var moo1 = game.sound.play('moo1');//and when you want to play it again.moo1.play();
Personally, I think it is a bad practice; most of the sounds you usually need shouldn't play right away. So I suggest using the gameObjectFactory to add any sound or any other instance of an asset you need; it will be much less confusing. For example, for audio you could do:
var moo1 =  game.add.audio('moo1'); //or "game.add.sound('moo1');", it's exactly the same.moo1.play();
Phaser has too many ways of doing the same things and some ways are a lot better than others. It is one of it's main flaws in my opinion, but i believe it will be fixed in Phaser 3. In the mean time, one has to be careful to use it the best way. I hope it helps.

Share this post


Link to post
Share on other sites

I should be more precise.  I don't experience the slow down issue, but I do see an increase of listeners as I play more and more sounds.  I'll present a quick summary of how I am currently handling sound - maybe valueerror or Oscar or whomever can glean something from it.

 

* I load sounds in Preloader.js.  Here is an example: GNS.levelSucceededSound = this.game.add.audio('level_succeeded');.  Note that I load them as property variables in a single global namespace object.  I swap between Game state and Menu state a lot in my game and I scope some objects as globally defined so I only have to create them once, sounds being one type of these.

 

* I have a function, also scoped to this same single global GNS object (so I can use the function from both Menu and Game states, defined like this:

GNS.playSound = function (sound) {
  sound.volume = GNS.SOUND_VOLUME_CURRENT;
  sound.play();
};
 
* When I want to play a sound, I do it like this: GNS.playSound(GNS.levelSucceededSound);.  The line with volume allows me to adjust volume or shut off sound by altering yet another GNS global, a sound volume variable.
 
Sure, there are more elegant ways to do this, but this is simple, and I thought, effective.  However, there is this apparent leak with listeners, though again, it does not seem to negatively affect my FPS.  As I write this, I'm wondering if my usage of sound.volume on every playSound call might be contributing to my apparent problem.

Share this post


Link to post
Share on other sites

@oscar abraham:   if you read the github issue i opened you'll find out that i am already doing it the "right" way..   play();  still adds a listener :(

 

i'm only experiencing this problem because i'm running the same state for 30 minutes..  the moment i switch the state (or restart the same state) 60fps are back again and the number of listeners is down to 23 again..

Share this post


Link to post
Share on other sites

Per your last post valueerror, I can see why perhaps I don't tend to reach a scenario in which my FPS drops, even though I do see listener buildup.  For most players, my game tends to have a fair amount of state switching.  It's level based, and when you fail a level, you switch back to the Menu state.

Share this post


Link to post
Share on other sites

oke.. it looks like this is not a phaser bug after all ...  

 

it's just that chromes profiler is totally misleading here and i don't know why..  sorry :(  i'll try to explain :)

 

explode = game.add.audio('explosion',1,false);
or
explode = game.sound.add('explosion',1,false);

(seems to be the same)   is used to add a sound to the game ONCE!

 

if you need the sound you can start it with the following line..   this should not add an additional sound to the sound manager.. just play it 

explosion.play();  

nevertheless chromes profiler shows one added listener when i call explosion.play();   (screenshot) exactly the same as before when i used game.sound.play('explosion');

post-6912-0-56838600-1428852734_thumb.jp

 

the funny thing is though..  when i start profiling again.. the amount of listeners is back to it's original number (in distinction to the former method where those "listeners" remain in the game state forever and accumulate.

 

so the outcome of all this noise i made is:

 

don't use game.sound.play();  use test = game.sound.add('something'); and then when needed test.play(); 

and don't trust the chrome profiler.. or at least stop and restart it and compare values carefully!

 

why aren't those listeners removed during the profiling but obviously right after the profiling stops ?????  :wacko:

 

i didn't test it yet but i will do so in the next hour and report back if the problem of collecting more and more listeners is gone completely with the right usage of the sound manager ^^ 

 

btw.: @oscar abraham..   seems you had it right from the beginning - and i was already on the right track in my bug report.. thank you !

 

 

Share this post


Link to post
Share on other sites

post-6912-0-04824000-1428855537_thumb.jp

as you can see in this screenshot the listeners are getting more and more and more during profiling.. every sound played adds one.. BUT when i start profiling again i am NOW back to my initial number of listeners which is 34 at the moment..

 

 

so in distinction to the headline i actually wasn't reusing everything..  the sounds got created over and over again and were not reused - even if they already existed with the exact same setting phaser was creating a new one..

 

so with the proper usage of the sound manager this problem is gone completely..  game is running for an hour now with perfect 60fps

:ph34r:

solved :) 

 

thx to all of you 

Share this post


Link to post
Share on other sites

wow...  i just rechecked my latest version of the same game and listeners are rising again.. (and this time they stay)   i am quite sure that i didn't change anything...  (maybe i did a chrome update)

 

every time a sound is played..  a listener is added...  WTF ???  !!!

 

a already do it the "right" way..  so i am definitely NOT adding a new sound to the soundmanager this time and i am 100% sure that it is mysound.play(); that adds the Listener chrome is logging...

 

i tend to not believe chrome this time because it behaved strange the last time and i did a little experiment and played 20 sounds every 300ms and had 6000 listeners in a very short time but no performance loss at all...

Share this post


Link to post
Share on other sites

I have had a performance over time issue for months. The game starts at 60FPS and gradually goes down. After about 30 min, it will be down to 30FPS. 

I used the "brute force" method you described, valueerror, and eventually narrowed it down to the bullet sprites. In my game, when a bullet is fired, it is killed after it reaches its target and when used again, revived (with sprite.reset). If I prevent all bullets from firing, the FPS drop never happens. I've tried this with bullets that use physics and bullets that don't (tweened bullets) and the problem persists.

After examining my bullet code long enough, I realized what the problem was. Sure enough, before a bullet is fired, a sound is played with game.sound.play. I disabled all sounds and let a simulation of the game run for 8 hours. When I woke up, it was running at 40FPS. But with sounds playing, it could get that bad within an hour. Without sounds, I suspect the drop in FPS to be caused by sprites being destroyed and new ones being created. My sprite creation/destruction isn't nearly as efficient as bullets (where dead bullets are revived). I'm going to try it again tonight with sprites being recycled as well. 

Even so though, running at 40 FPS with non-stop action (bullets firing, sprites dying/spawning) for 8 hours is pretty damn good. I wonder how well other game software (something in Unity or Unreal for example) will fair in the same game state, with constant action, for an extended period of time. There's only so much you can recycle/ clean up. 

I expect players to remain in a single game state for 1 hour at most, so it's pretty much a solved problem for me. Still, I would like to see what I can do to have zero frame rate reduction after running a game simulation for 8 hours :). 

Share this post


Link to post
Share on other sites

All in all this whole sound thing confuses the hell out of me. Is this:

        if (gameSounds[key] == undefined) {
            gameSounds[key] = game.sound.add(key);

        }

        var sound = gameSounds[key].play(undefined, undefined, volume, loop);

A better way of doing it than this?

        var sound = game.sound.play(key, volume, loop);


Guess I'll have to run a game simulation for an hour to see. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.