Duff's device

JavaScript performance comparison

Revision 29 of this test case created by Esailija

Info

Simple test of variations of loop unrolling/unwinding based on the original Duff's Device.

Result may vary based on the number of iterations, browser, OS and external influences...

Usually Fast Duff's Device #2, #3, #4 runs faster when the number of iterations is bigger or when the test is executed multiple times without browser refresh - bitwise operations have a really strange behavior in JS, sometimes they are really fast and other times they run slower than the Math methods.

Make sure you test each approach using real application code (since results may vary) and just use this kind of optimization if you really need it! Try to combine techniques and avoid property lookups!

PS: It's over 9000 iterations!

Preparation code

<script>
  var iterations = 50;

  function regularLoop() {
      var testVal = 0;
      var n = iterations;
      while (n-- > 0) {
          testVal++;
      }
      return testVal;
  }

var l = 200;
while(l--) {
   regularLoop();
}

iterations = 10000;
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Regular Loop
var testVal = regularLoop();

if( testVal !== iterations ) throw new Error("invalid");
pending…
Duff's Device
/**
 * Duff's Device
 * http://home.earthlink.net/~kendrasg/info/js_opt/jsOptMain.html#duffsdevice
 */

var testVal = 0;
var n = iterations / 8;
var caseTest = iterations % 8;

do {
 switch (caseTest) {
 case 0:
  testVal++;
 case 7:
  testVal++;
 case 6:
  testVal++;
 case 5:
  testVal++;
 case 4:
  testVal++;
 case 3:
  testVal++;
 case 2:
  testVal++;
 case 1:
  testVal++;
 }
 caseTest = 0;
}
while (--n > 0);

if( testVal !== iterations ) throw new Error("invalid");
pending…
Fast Duff's Device #1
/**
 * Fast Duff's Device
 * @author Jeff Greenberg
 * http://home.earthlink.net/~kendrasg/info/js_opt/jsOptMain.html#fastDuffsdevice
 */

var testVal = 0;
var n = iterations % 8;
while (n--) {
 testVal++;
}

n = parseInt(iterations / 8);
while (n--) {
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
}

if( testVal !== iterations ) throw new Error("invalid");
pending…
Fast Duff's Device #2
/*
 * Fast Duff's Device
 * @author Miller Medeiros <http://millermedeiros.com>
 * @version 0.1 (2010/08/25)
 */

var testVal = 0;
var n = iterations % 8;
while (n--) {
 testVal++;
}

n = Math.floor(iterations / 8);
while (n--) {
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
}

if( testVal !== iterations ) throw new Error("invalid");
pending…
Fast Duff's Device #3
/*
 * Fast Duff's Device
 * @author Miller Medeiros <http://millermedeiros.com>
 * @version 0.2 (2010/08/25)
 */

var testVal = 0;
var n = iterations % 8;
while (n--) {
 testVal++;
}

n = (iterations / 8) ^ 0; //`value ^ 0` is the same as `Math.floor` for positive numbers and `Math.ceil` for negative numbers
while (n--) {
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
}

if( testVal !== iterations ) throw new Error("invalid");
pending…
Fast Duff's Device #4
/*
 * Fast Duff's Device
 * @author Miller Medeiros <http://millermedeiros.com>
 * @version 0.3 (2010/08/25)
 */

var testVal = 0;
var n = iterations % 8;
while (n--) {
 testVal++;
}

n = (iterations * 0.125) ^ 0; //multiplication is faster than division in some cases
while (n--) {
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
 testVal++;
}

if( testVal !== iterations ) throw new Error("invalid");
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment