title: Why is Firefox 30 times slower than Chrome, when calculating Perlin noise?
body: <p>I have written a map generator in javascript, using classical perlin noise scripts I have found in various places, to get the functionality I want. I have been working in chrome, and have not experienced any problems with the map. However, when I tested it in firefox, it was incredibly slow - almost hanging my system. It fared better in the nightly build, but still 30 times slower than Chrome.</p>
  
  <p>You can find a test page of it here:
  <a href="http://jsfiddle.net/7Gq3s/" rel="noreferrer">http://jsfiddle.net/7Gq3s/</a></p>
  
  <p>Here is the html code:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  
  &lt;html&gt;
  &lt;head&gt;
  &lt;title&gt;PerlinMapTest&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
  
  &lt;canvas id="map" width="100" height="100" style="border: 1px solid red"&gt;My Canvas&lt;/canvas&gt;
  
  &lt;script src="//code.jquery.com/jquery-2.0.0.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;
  $(document).ready(function(){
      //Log time in two ways
      var startTime = new Date().getTime();
      console.time("Map generated in: ");
  
      var canvas = $("#map")[0];
      var ctx = canvas.getContext("2d");
      var id = ctx.createImageData(canvas.width, canvas.height); 
  
      var noiseMap = new PerlinNoise(500);
  
      var startx = 0;
      var starty = 0;
  
      var value = 0;
  
      for(var i = startx; i &lt; canvas.width; i++){
          for(var j = starty; j &lt; canvas.height; j++){
              value = noiseMap.noise(i,j, 0, 42);
              value = linear(value,-1,1,0,255);
              setPixel(id, i, j, 0,0,0,value);
          }
      }
  
      ctx.putImageData(id,0,0);
  
      var endTime = new Date().getTime();
      console.timeEnd("Map generated in: ");
      alert("Map generated in: " + (endTime - startTime) + "milliseconds");
  
  });
  
  function setPixel(imageData, x, y, r, g, b, a) {
      index = (x + y * imageData.width) * 4;
      imageData.data[index+0] = r;
      imageData.data[index+1] = g;
      imageData.data[index+2] = b;
      imageData.data[index+3] = a;
  }
  
  //This is a port of Ken Perlin's "Improved Noise"
  //http://mrl.nyu.edu/~perlin/noise/
  
  //Originally from http://therandomuniverse.blogspot.com/2007/01/perlin-noise-your-new-best-friend.html
  //but the site appears to be down, so here is a mirror of it
  
  //Converted from php to javascript by Christian Moe
  //Patched the errors with code from here: http://asserttrue.blogspot.fi/2011/12/perlin-noise-in-javascript_31.html
  
  var PerlinNoise = function(seed) {
  this._default_size = 64;
  this.seed = seed;       
  
  //Initialize the permutation array.
  this.p = new Array(512);
  
  this.permutation = [ 151,160,137,91,90,15,
  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
  ];
  
  for (var i=0; i &lt; 256 ; i++) {
  this.p[256+i] = this.p[i] = this.permutation[i];
  }
  };
  
  PerlinNoise.prototype.noise = function(x,y,z,size) {
  
  if (size == undefined) 
  {
  size = this._default_size;
  }
  
  //Set the initial value and initial size
  var value           = 0.0; 
  var initialSize     = size;
  
  //Add finer and finer hues of smoothed noise together
  while(size &gt;= 1) 
  {
  value += this.smoothNoise(x / size, y / size, z / size) * size;
  size /= 2.0;
  }
  
  //Return the result over the initial size
  return value / initialSize;
  
  };
  
  //This function determines what cube the point passed resides in
  //and determines its value.
  PerlinNoise.prototype.smoothNoise = function(x, y, z){
  //Offset each coordinate by the seed value
  x += this.seed; 
  y += this.seed; 
  z += this.seed;
  
  var orig_x = x;
  var orig_y = y;
  var orig_z = z;
  
  var X = Math.floor(x) &amp; 255,                  // FIND UNIT CUBE THAT
      Y = Math.floor(y) &amp; 255,                  // CONTAINS POINT.
      Z = Math.floor(z) &amp; 255;
  
  x -= Math.floor(x);                                // FIND RELATIVE X,Y,Z
  y -= Math.floor(y);                                // OF POINT IN CUBE.
  z -= Math.floor(z);
  
  var    u = this.fade(x),                                // COMPUTE FADE CURVES
        v = this.fade(y),                                // FOR EACH OF X,Y,Z.
        w = this.fade(z);
  
  var A = this.p[X  ]+Y, AA = this.p[A]+Z, AB = this.p[A+1]+Z,      // HASH COORDINATES OF
     B = this.p[X+1]+Y, BA = this.p[B]+Z, BB = this.p[B+1]+Z;      // THE 8 CUBE CORNERS,
  
  return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(this.p[AA  ], x  , y  , z   ),  // AND ADD
             this.grad(this.p[BA  ], x-1, y  , z   )), // BLENDED
             this.lerp(u, this.grad(this.p[AB  ], x  , y-1, z   ),  // RESULTS
                     this.grad(this.p[BB  ], x-1, y-1, z   ))),// FROM  8
                     this.lerp(v, this.lerp(u, this.grad(this.p[AA+1], x  , y  , z-1 ),  // CORNERS
                             this.grad(this.p[BA+1], x-1, y  , z-1 )), // OF CUBE
                             this.lerp(u, this.grad(this.p[AB+1], x  , y-1, z-1 ),
                                     this.grad(this.p[BB+1], x-1, y-1, z-1 ))));
  };
  
  PerlinNoise.prototype.fade = function(t) { 
  return t * t * t * ( ( t * ( (t * 6) - 15) ) + 10);
  };
  
  PerlinNoise.prototype.lerp = function(t, a, b) { 
  //Make a weighted interpolaton between points
  return a + t * (b - a); 
  };
  
  PerlinNoise.prototype.grad = function(hash, x, y, z) {
  h = hash &amp; 15;                      // CONVERT LO 4 BITS OF HASH CODE
  u = h&lt;8 ? x : y;                 // INTO 12 GRADIENT DIRECTIONS.
  v = h&lt;4 ? y : (h==12||h==14 ? x : z);
  
  return ((h&amp;1) == 0 ? u : -u) + ((h&amp;2) == 0 ? v : -v);
  };
  
  PerlinNoise.prototype.scale = function(n) { 
  return (1 + n)/2; 
  };
  
  function linear(int, s1, s2, t1, t2)
  {
  t = [t1, t2];
  s = [s1, s2];
  
  rangeS = s1 - s2;
  rangeT = t1 - t2;
  
  if((s1 &lt; s2 &amp;&amp; t1 &gt; t2) || (s1&gt;s2 &amp;&amp; t1&lt;t2))
  {
          interpolated = ((int - s1) / rangeS*rangeT) + t1;
  }
  else
  {
          interpolated = ((int - s1) / rangeS)*rangeT + t1;
  }
  
  if(interpolated &gt; Math.max.apply(Math, t))
  {
          interpolated = Math.max.apply(Math, t);
  }
  
  if(interpolated &lt; Math.min.apply(Math, t))
  {
          interpolated = Math.min.apply(Math, t);
  }
  
  return interpolated;
  
  }
  &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>I get 33 ms on Chrome, and 1051ms on Firefox 24 Nightly </p>
  
  <p>The results are inconsistent though. Sometimes the Nightly results is as fast as chrome...</p>
  
  <p>Do you know why there is so much variation in this particular instance?
  I don't know enough about the theory of perlin noise to try optimizing the code, so don't know what to do.</p>