performance - Inconsistent execution times in Javascript -


note: have checked mike brandt's answer if have since caught dumb mistake on dead/live pixel ratio. ken gets nod advice.

i'm trying debug performance issues conway's game of life in canvas element , i'm getting strange performance issues.

i'm getting 4-12 fps , benchmarking of drawing functions indicates overall performance should able go 60 fps.

below canvas drawing code. updatebgcanvas being called @ 30fps requestanimationframe. whole thing being run , perf tested in chrome 28.0.1500.70.

(my apologies messy code, i've been hacking code smaller subunits greater granularity in performance profiler without regard coding technique)

unsurprisingly, canvas drawing functions (filldead , filllive biggest cpu hogs here's gets bizarre. filllive consumes 5-6% of cpu time (about expect fillrect benchmarking did) , filldead eats whopping 36-38% of cpu time. these identical functions except conditional test against 1 or 0.

i've tried swapping calling order in parent function , colors being used fill , filldead consistently takes 6-7 times longer call identical filllive. i'm @ loss why be.

any suggestions?

  window.bgvars = {      "about": "the background famous conway game of life",      "_canvas": {},      "_ctx": {},      "xblocksize": 5,      "yblocksize": 5,      "xblocks": 0,      "yblocks": 0,      "bornvals": [3],      "stayalivevals": [2, 3],      "cgrid": [],      "cgrid2": [],      "cl": 0,      "initbgvars" : function(icanvas, ictx){         console.log(this.xblocksize);         this._canvas = icanvas;         this._ctx = ictx;         this.cgrid = [];         this.cgrid2 = [];         this.xblocks = math.round(mycanvas.width/this.xblocksize) + 1;         this.yblocks = math.round(mycanvas.height/this.yblocksize) + 1;         for(var rep=0;rep<(this.xblocks * this.yblocks);rep++){            this.cgrid.push(math.round(math.random()*0.8));         }         this.cgrid2.length = this.cgrid.length;      },      "cirind": function(index){         //returns modulus, array-wrapping value implement circular array         if(index<0){index+=this.cgrid.length;}         return index%this.cgrid.length;      },      "calcneighbors": function(rep){         var foo = this.xblocks;         var neighbors = this.cgrid[this.cirind(rep-foo-1)] + this.cgrid[this.cirind(rep-foo)] + this.cgrid[this.cirind(rep-foo+1)] + this.cgrid[this.cirind(rep-1)] + this.cgrid[this.cirind(rep+1)] + this.cgrid[this.cirind(rep+foo-1)] + this.cgrid[this.cirind(rep+foo)] + this.cgrid[this.cirind(rep+foo+1)];         return neighbors;      },      "refreshgrid": function(){         for(var rep=0;rep<this.cgrid.length;rep++){            if(math.random()<0.0002){this.cgrid2[rep] = 1;}            this.cgrid[rep] = this.cgrid2[rep];         }      },      "liferules": function(rep, neighbors){            if(this.cgrid[rep] == 1){  //stay alive rules               for(var rep2=0;rep2<this.stayalivevals.length;rep2++){                  if(neighbors==this.stayalivevals[rep2]){this.cgrid2[rep] = 1;}               }            }            if(this.cgrid[rep] == 0){  //'born' rules               for(var rep2=0;rep2<this.bornvals.length;rep2++){                  if(neighbors==this.bornvals[rep2]){this.cgrid2[rep] = 1;}               }            }                },      "filldead": function(){         for(var rep=0;rep<this.cgrid.length;rep++){            if(this.cgrid[rep] == 0){               this._ctx.fillrect((rep%this.xblocks)*this.xblocksize, math.floor(rep/this.xblocks)*this.yblocksize, this.xblocksize, this.yblocksize);            }         }                },      "filllive": function(){         for(var rep=0;rep<this.cgrid.length;rep++){            if(this.cgrid[rep] == 1){               this._ctx.fillrect((rep%this.xblocks)*this.xblocksize, math.floor(rep/this.xblocks)*this.yblocksize, this.xblocksize, this.yblocksize);            }         }                },      "updatebgcanvas": function(){         //fill live squares         this._ctx.fillstyle = 'rgb(130, 0, 0)';         this.filllive();         //fill dead squares         this._ctx.fillstyle = 'rgb(100, 0, 0)';         this.filldead();         //calculate next generation buffer         for(var rep=0;rep<this.cgrid.length;rep++){            //add live squares in 8 neighbor blocks            var neighbors = this.calcneighbors(rep);            this.cgrid2[rep] = 0;            //implement gol ruleset            this.liferules(rep, neighbors);         }         //seed random noise keep dynamic , copy display buffer         this.refreshgrid();      }   } 

edits math functions suggested ken, copying parent object vars local vars, giving 16% perf gain in math functions, 4% overall:

     "cirind": function(index, mod){         //returns modulus, array-wrapping value implement circular array         if(index<0){index+=mod;}         return index%mod;      },      "calcneighbors": function(rep){         var foo = this.xblocks;         var grid = this.cgrid;         var mod = grid.length;         var neighbors = grid[this.cirind(rep-foo-1, mod)] + grid[this.cirind(rep-foo, mod)] + grid[this.cirind(rep-foo+1, mod)] + grid[this.cirind(rep-1, mod)] + grid[this.cirind(rep+1, mod)] + grid[this.cirind(rep+foo-1, mod)] + grid[this.cirind(rep+foo, mod)] + grid[this.cirind(rep+foo+1, mod)];         return neighbors;      }, 

to give example of can improve performance try replace filldead function modifcation:

"filldead": function(){     /// localize vars interpreter doesn't    /// have walk of branches time:    var cgrid = this.cgrid, ctx = this._ctx,        xblocks = this.xblocks, xblocksize = this.xblocksize,        yblocksize = this.yblocksize,        rep = cgrid.length - 1;     /// while loops faster loops    while(rep--)        if(cgrid[rep] == 0){          ctx.fillrect((rep%xblocks) * xblocksize, ((rep/xblocks)|0) * yblocksize, xblocksize, yblocksize);       }    } }, //... 

how perform ? if 1 or 2 grid elements won't see difference more grid elements better performance should (cannot test don't have full code).

if see improves performance should apply other functions well. should see if can put of this.* local vars instead in parent scope , pass them in parameters functions.


Comments

Popular posts from this blog

javascript - Count length of each class -

What design pattern is this code in Javascript? -

hadoop - Restrict secondarynamenode to be installed and run on any other node in the cluster -