7
\$\begingroup\$

Ok! I solved the problem.

Chapter One - Multiple Canvases

I started to make pong utilizing requestAnimationFrame and I noticed that the ball was stuttering and slowing down every 3-4 seconds. So I implemented a crude FPS function to write the current fps to the screen and realized that the slow down was accompanied by an fps drop to 30fps. I thought it had something to do with my collision detection function, but it was not the case.

MarkR noticed that I had two canvases drawing and updating the player/ball separately, he suggested that I combine the two canvases into one. This produced better performance and now I could only see the slow-down/stuttering every 15~ seconds. The problem was, the stuttering was still happening.

Chapter Two - Vsync, Chrome Developer Tools

In comes Dreta! Dreta said that the fps was dropping to 30fps because canvas is trying to Vsync. I had no idea what he was talking about, so I asked Mr. Google and found a really good explanation of how Vsync/double-buffering/triple-buffering works. It's a medium read, but it it definitely worth checking out if you want to learn more about how your graphics card/monitor works.

He also told me that I can look at the fps of the game in Chrome by using the Developer Tool(which can be accessed by right-clicking -> inspect element -> Timeline tab and clicking on the black circle at the bottom-- the circle will turn red when recording). You can also look at the memory usage and I noticed that it was periodically shooting up to 4mbs of memory used. Dreta suggested it was a memory leak--

Chapter Three - Memory Leaks

To locate a memory leak, use the following process: Found at microsoft site (http://msdn.microsoft.com/en-us/library/ms859415.aspx)

  • Find the memory leak – Detect the presence of a memory leak in the system, given a particular reproducible sequence. You should be able to identify a specific process, but demonstrating an overall increase in committed system memory can qualify a memory leak as well.
  • Isolate the memory leak – Determine the exact location in the source code where the un–freed allocation occurs. This can be a lengthy and tedious process, requiring specific tools, trial–and–error, and teamwork with the original author of the code.
  • Fix the memory leak – After the first two steps are completed, this is easy. Fixing the memory leak usually involves adding some code to free the memory in the questionable code path.
  • Dreta suggested that I use heap profiling to find memory leaks. I personally have not read up on it yet, but here's a link to chrome's explanation of heap profiling developers.google.com/chrome-developer-tools/docs/heap-profiling.

    He said:

    Each time you update the player, you're creating a function. You probably want to change the Player class from:

    this.update = function() {
    $("#c").mousemove(function(event) {
      tempY = event.pageY;
    });
    this.y = tempY;
    }
    

    which creates a function every 16ms I update the player

    to:

    var that = this;
    
    $("#c").mousemove(function(event) {
      that.y = event.pageY;
    });
    

    This helped optimize the game further.

    Chapter Four - I'm stupid, yeah... Chrome Tabs + Memory

    I remembered that there was an issue with chrome with multiple tabs open, and I decided to quit out of and restart chrome anew. Behold! Constant 60fps and 1-2.5 mb memory usage(where it was 2-4mb memory usage before).

    Moral of the story... close down all tabs and restart chrome before determining the problem, and use heap profiling to locate memory leaks.

    Thank you everyone for your help! I really do appreciate it.

    Here's the code on github. Please let me know if you find more stupid mistakes or you have general tips on working with canvas/programming.

    Feel free to email me [email protected]

    \$\endgroup\$
    14
    • \$\begingroup\$ I can see no Slow Down. Initial Though was garbage collection, but I doubt it with that little code. Try and add a Frame-Per-Second-Counter on the game to monitor the FPS :) \$\endgroup\$ Jan 19, 2013 at 5:31
    • \$\begingroup\$ I'll try that. I'll also try running this on a different browser and see if there's a difference. For me, the slow down happens only on the ball every 3-4 seconds, without fail. \$\endgroup\$ Jan 19, 2013 at 5:35
    • \$\begingroup\$ Ok, the game doesn't even show up on firefox D: more problems to fix. Ok, the fps drops to 30fps when the ball slows down. I didn't notice the slow down on the paddle before. I'll upload the new game with fps to the server now. \$\endgroup\$ Jan 19, 2013 at 5:46
    • \$\begingroup\$ Use CHROME in my opinion ^^ I have steady 60/59 frames. Damn I can't wait them to make browsers go Beyond 60 fps ^^ \$\endgroup\$ Jan 19, 2013 at 6:46
    • 3
      \$\begingroup\$ I think you have fundamentally misunderstood how to use Canvas. You don't need to use 1 canvas for each object in the scene. It is sufficient to use a single canvas, redrawing the scene in the canvas on every frame. This way we can avoid using JQuery to move the elements around (and thus you can completely remove Jquery), or other similar techniques. If you want to use the DOM, you don't need to use canvas - and vice versa. They're mutually exclusive techniques. \$\endgroup\$
      – MarkR
      Jan 19, 2013 at 14:45

    1 Answer 1

    6
    \$\begingroup\$

    An FPS counter doesn't do much for you if you're using requestAnimationFrame. If you go over the 60 FPS budget, the browser might drop you straight to 30 FPS because it's trying to vsynch. You can check your frame budget in Chrome in the Timeline tab of the Developer Tools. There's plenty of tutorials for that, so i won't go into detail.

    I can see that most of the time, you're well in budget. The issue is that you're leaking memory. Quite heavily, i might add. Just take a few heap snapshots. I'm sure the hiccups are because of that.

    My guess is that this is the issue:

      this.update = function() {
        $("#c").mousemove(function(event) {
          tempY = event.pageY;
        });
        this.y = tempY;
      }
    

    Each time you update the player, you're creating a function. You probably want to change the Player class to something like this:

    function Player(y) {
      this.x = 20;
      this.y = y;
      this.width = 20;
      this.height = 60;
    
      var that = this;
    
      $("#c").mousemove(function(event) {
        that.y = event.pageY;
      });
    
      //remove the update function from your code
    
    }
    

    I can't really see anything else being a glaring issue. jQuery is using the DOM level 2 events here probably, which means that you're creating and assigning to a mouse event a new callback function each 16ms which never gets cleaned up. This should be the issue and the change i suggested should fix it.

    \$\endgroup\$
    6
    • \$\begingroup\$ Thank you for your response. I totally forgot that I had another jquery event in the update function. I'll try implementing the change and I'll get back to you. \$\endgroup\$ Jan 19, 2013 at 20:00
    • \$\begingroup\$ Ok! I found the problem. It was.... MY STUPIDITY. I always knew chrome tabs were a memory hog... the game runs smoothly at 60fps now that I restarted chrome. It was a combination of everyone's optimization help and me getting a brain, thanks everyone! I'll post up everything I found out from this headache D: \$\endgroup\$ Jan 19, 2013 at 20:41
    • \$\begingroup\$ I'll choose your answer since it was the timeline hint that led me to believe chrome was culprit. \$\endgroup\$ Jan 19, 2013 at 20:42
    • \$\begingroup\$ @DanielSunYang The demo you linked had a massive memory leak, i sincerely doubt that Chrome's the issue here. I'm just saying, if all you did was restart Chrome then your problem is not fixed. \$\endgroup\$
      – dreta
      Jan 19, 2013 at 21:42
    • \$\begingroup\$ I implemented the change you suggested, was that not the main problem? \$\endgroup\$ Jan 19, 2013 at 21:46

    You must log in to answer this question.

    Not the answer you're looking for? Browse other questions tagged .