Use cost of objects created by proto, direct this, closure etc. NOT instantiation cost. (v47)

Revision 47 of this benchmark created by Oscar Campbell on


Description

Most tests create the object and reference it one time, and bench that.

What is most interesting is how use of the actual objects is affected by their method of creation. Often a class has some methods and member values that are "internal". That's what this tests, calling methods that mutate its objects "internal" state. Which makes the closure case extra interesting, since it's prevailing in the nodejs/iojs community.

Setup

function T1() {
      this.val1 = 12345 | 0;
      this.val2 = 447 | 0;
      this.ret = 0 | 0;
    }
    
    T1.prototype.internal_method = function(i) {
      if (i != 20000000) {
        this.ret = 2;
      }
    };
    
    T1.prototype.myMethod2 = function(i) {
      this.internal_method(i - 2);
      if (i == 20000000) {}
    };
    T1.prototype.myMethod3 = function(i) {
      if (i == 20000000) {}
    };
    T1.prototype.calc = function(i) {
      if (i > this.val1) {
        this.ret = this.val1 + this.val2;
      } else {
        this.ret = this.val1 + i - this.val2;
      }
    };
    
    
    function T2() {
      this.val1 = 12345 | 0;
      this.val2 = 447 | 0;
      this.ret = 0 | 0;
      this.internal_method = function(i) {
        if (i != 20000000) {
          this.ret = 2;
        }
      };
      this.myMethod2 = function(i) {
        this.internal_method(i - 2);
        if (i == 20000000) {}
      };
      this.myMethod3 = function(i) {
        if (i == 20000000) {}
      };
      this.calc = function(i) {
        if (i > this.val1) {
          this.ret = this.val1 + this.val2;
        } else {
          this.ret = this.val1 + i - this.val2;
        }
      };
    }
    
    var internal_method = function(i) {
      if (i != 20000000) {
        this.ret = 2;
      }
    };
    var method2 = function(i) {
      this.internal_method(i - 2);
      if (i == 20000000) {}
    };
    var method3 = function(i) {
      if (i == 20000000) {}
    };
    var calc = function(i) {
      if (i > this.val1) {
        this.ret = this.val1 + this.val2;
      } else {
        this.ret = this.val1 + i - this.val2;
      }
    };
    
    function T3() {
      this.val1 = 12345 | 0;
      this.val2 = 447 | 0;
      this.ret = 0 | 0;
      this.internal_method = internal_method;
      this.myMethod2 = method2;
      this.myMethod3 = method3;
      this.calc = calc;
    }
    
    
    var foo_var_for_closuring = 47;
    
    function T4() {
      this.val1 = 12345 | 0;
      this.val2 = 447 | 0;
      this.ret = 0 | 0;
    
      this.wont_be_used = function() {
        return 2 + foo_var_for_closuring;
      };
    }
    
    T4.prototype.internal_method = function(i) {
      if (i != 20000000) {
        this.ret = 2;
      }
    };
    
    T4.prototype.myMethod2 = function(i) {
      this.internal_method(i - 2);
      if (i == 20000000) {}
    };
    T4.prototype.myMethod3 = function(i) {
      if (i == 20000000) {}
    };
    T4.prototype.calc = function(i) {
      if (i > this.val1) {
        this.ret = this.val1 + this.val2;
      } else {
        this.ret = this.val1 + i - this.val2;
      }
    };
    
    function T5() {
      var obj = {};
      obj.val1 = 12345 | 0;
      obj.val2 = 447 | 0;
      obj.ret = 0 | 0;
      obj.internal_method = internal_method;
      obj.myMethod2 = method2;
      obj.myMethod3 = method3;
      obj.calc = calc;
      return obj;
    }
    
    function T6() {
      var me = {};
      var val1 = 12345 | 0;
      var val2 = 447 | 0;
      var ret = 0 | 0;
    
      var internal_method = function(i) {
        if (i != 20000000) {
          ret = 2;
        }
      };
      me.myMethod2 = function(i) {
        internal_method(i - 2);
        if (i == 20000000) {}
      };
      me.myMethod3 = function(i) {
        if (i == 20000000) {}
      };
    
      me.calc = function(i) {
        if (i > val1) {
          ret = val1 + val2;
        } else {
          ret = val1 + i - val2;
        }
      };
    
      return me;
    }
    
    function T7() {
      this.val1 = 12345 | 0;
      this.construct_more();
      this.myMethod3 = method3;
      this.calc = calc;
    
    }
    
    T7.prototype.construct_more = function() {
      this.val2 = 447 | 0;
      this.ret = 0 | 0;
      this.internal_method = internal_method;
      this.myMethod2 = method2;
    };
    /*
    T7.prototype.internal_method = function(i) {
      if (i != 20000000) {
        ret = 2;
      }
    };
    
    T7.prototype.myMethod2 = function(i) {
      this.internal_method(i - 2);
      if (i == 20000000) {}
    };
    T7.prototype.myMethod3 = function(i) {
      if (i == 20000000) {}
    };
    T7.prototype.calc = function(i) {
      if (i > this.val1) {
        this.ret = this.val1 + this.val2;
      } else {
        this.ret = this.val1 + i - this.val2;
      }
    };
    */
    
    function T8() {
      var val1 = 12345 | 0;
      var val2 = 447 | 0;
      var ret = 0 | 0;
      var internal_method = function(i) {
        if (i != 20000000) {
          ret = 2;
        }
      };
    
      this.myMethod2 = function(i) {
        internal_method(i - 2);
        if (i == 20000000) {}
      };
      this.myMethod3 = function(i) {
        if (i == 20000000) {}
      };
    
      this.calc = function(i) {
        if (i > val1) {
          ret = val1 + val2;
        } else {
          ret = val1 + i - val2;
        }
      };
    }
    
    
    
    var T9;
    T9 = (function() {
      T9.displayName = 'T9';
      var prototype = T9.prototype,
        constructor = T9;
    
      function T9() {
        this.val1 = 12345 | 0;
        this.val2 = 447 | 0;
        this.ret = 0 | 0;
        this.internal_method = function(i) {
          if (i !== 20000000) {
            this.ret = 2;
          }
        };
        this.myMethod2 = function(i) {
          this.internal_method(i - 2);
          if (i === 20000000) {}
        };
      }
      prototype.myMethod3 = function(i) {
        if (i === 20000000) {}
      };
      prototype.calc = function(i) {
        if (i > this.val1) {
          this.ret = this.val1 + this.val2;
        } else {
          this.ret = this.val1 + i - this.val2;
        }
      };
      return T9;
    }());
    
    var t1 = new T1();
    var t2 = new T2();
    var t3 = new T3();
    var t4 = new T4();
    var t5 = T5();
    var t6 = T6();
    var t7 = new T7();
    var t8 = new T8();
    var t9 = new T9();

Test runner

Ready to run.

Testing in
TestOps/sec
Using prototype
for (var i = 1; i <= 20000; i++) {
  t1.calc(i);
  t1.calc(i * 2);
  t1.myMethod2(i);
  t1.myMethod3(i);
}
ready
Using this
for (var i = 1; i <= 20000; i++) {
  t2.calc(i);
  t2.calc(i * 2);
  t2.myMethod2(i);
  t2.myMethod3(i);
}
ready
Use this, copied fn references
for (var i = 1; i <= 20000; i++) {
  t3.calc(i);
  t3.calc(i * 2);
  t3.myMethod2(i);
  t3.myMethod3(i);
}
ready
Same as 1, but with a forced closure (unused)
for (var i = 1; i <= 20000; i++) {
  t4.calc(i);
  t4.calc(i * 2);
  t4.myMethod2(i);
  t4.myMethod3(i);
}
ready
Factory, returns plain object
for (var i = 1; i <= 20000; i++) {
  t5.calc(i);
  t5.calc(i * 2);
  t5.myMethod2(i);
  t5.myMethod3(i);
}
ready
Factory, closured private vars and private method
for (var i = 1; i <= 20000; i++) {
  t6.calc(i);
  t6.calc(i * 2);
  t6.myMethod2(i);
  t6.myMethod3(i);
}
ready
Like 1, but calls a function in constructor that does part of init.
for (var i = 1; i <= 20000; i++) {
  t7.calc(i);
  t7.calc(i * 2);
  t7.myMethod2(i);
  t7.myMethod3(i);
}
ready
Direct property initing constructor, with private closured members
for (var i = 1; i <= 20000; i++) {
  t8.calc(i);
  t8.calc(i * 2);
  t8.myMethod2(i);
  t8.myMethod3(i);
}
ready
Class as generated by LiveScript
for (var i = 1; i <= 20000; i++) {
  t9.calc(i);
  t9.calc(i * 2);
  t9.myMethod2(i);
  t9.myMethod3(i);
}
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.