Skip to content

Instantly share code, notes, and snippets.

@dieseltravis
Created August 20, 2009 15:46
Show Gist options
  • Select an option

  • Save dieseltravis/171149 to your computer and use it in GitHub Desktop.

Select an option

Save dieseltravis/171149 to your computer and use it in GitHub Desktop.
Benchmarking JS with and without Firebug's console
(function (w) {
var console = w.console,
BenchLog = "",
Bench = {},
BenchLogWrite = function (message) {
if (console && console.log) {
console.log(message);
} else { // no console logger
BenchLog += message;
}
},
BenchStart = function (benchName) {
if (console && console.time) {
console.time(benchName);
} else { // no console timer
Bench[benchName] = w.performance.now();
}
},
BenchEnd = function (benchName) {
if (console && console.time) {
console.timeEnd(benchName);
} else { // no console timer
Bench[benchName + "End"] = w.performance.now();
BenchLog += benchName + ":\t" + (Bench[benchName + "End"] - Bench[benchName]) + "ms\n";
}
},
BenchFunction = function (benchName, testTimes, benchFunction) {
// lower is better
BenchStart(benchName);
for (var i = testTimes; i--; ) {
benchFunction();
}
BenchEnd(benchName);
},
TimedBench = function (benchName, timeToRunMs, benchFunction, hideTime) {
// from John Resig, higher is better
var start = w.performance.now();
var time = 0;
var score = 0;
while (time < timeToRunMs) {
benchFunction ();
time = w.performance.now() - start;
score++;
}
var status;
if (hideTime) {
status = benchName + ":\t" + score + "\n";
} else {
status = benchName + ":\tscore for " + timeToRunMs + "ms:\t" + score + "\n";
}
BenchLogWrite(status);
},
FlushBenches = function () {
if (!(console && console.time && console.log) && BenchLog && (BenchLog.length > 0)) {
w.alert(BenchLog);
BenchLog = "";
}
},
// loop functions for determining the fastest way to enumerate an array
TestArrayLoop = function (arrayToBenched, benchName, units, arrayFunction, benchFunction, hideTime) {
// try various loops on array, variations from Steve Souders
// NOTE: don't modify arrayToBench in arrayfunction (arrayToBench[i]) - it would be "bad"
if (hideTime) {
BenchLogWrite(benchName + " (score for " + units + "ms):\n");
} else {
BenchLogWrite(benchName + ":\n");
}
benchFunction(benchName + ": Standard", units, function () {
for (var i = 0; i < arrayToBenched.length; i++) {
arrayFunction(arrayToBenched[i]);
}
}, hideTime);
benchFunction(benchName + ": length var", units, function () {
for (var i = 0, iLength = arrayToBenched.length; i < iLength; i++) {
arrayFunction(arrayToBenched[i]);
}
}, hideTime);
/* unnecessary
benchfunction (benchName + ": Reverse", units, function () {
for (var i = arrayToBenched.length; i > 0; i--) {
arrayfunction (arrayToBenched[i]);
}
}, hideTime);
*/
benchFunction(benchName + ": Reverse short", units, function () {
for (var i = arrayToBenched.length; i--; ) {
arrayFunction(arrayToBenched[i]);
}
}, hideTime);
// duff's device loop unrolling variations
benchFunction(benchName + ": Duff's", units, function () {
var iLength = arrayToBenched.length;
var iter = Math.ceil(iLength / 8);
var start = iLength % 8;
var i = 0;
do {
switch (start) {
case 0: arrayFunction(arrayToBenched[i++]);
case 7: arrayFunction(arrayToBenched[i++]);
case 6: arrayFunction(arrayToBenched[i++]);
case 5: arrayFunction(arrayToBenched[i++]);
case 4: arrayFunction(arrayToBenched[i++]);
case 3: arrayFunction(arrayToBenched[i++]);
case 2: arrayFunction(arrayToBenched[i++]);
case 1: arrayFunction(arrayToBenched[i++]);
}
start = 0;
} while (--iter > 0);
}, hideTime);
benchFunction(benchName + ": Duff's modified", units, function () {
var iLength = arrayToBenched.length;
var iter = Math.ceil(iLength / 8);
var left = iLength % 8;
var i = 0;
if (left > 0) {
do {
arrayFunction(arrayToBenched[i++]);
} while (--left > 0);
}
do {
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
arrayFunction(arrayToBenched[i++]);
} while (--iter > 0);
}, hideTime);
benchFunction(benchName + ": for...in", units, function () {
for (var i in arrayToBenched) {
arrayFunction(arrayToBenched[i]);
}
}, hideTime);
},
BenchArrayLoop = function (arrayToBenched, benchName, testTimes, arrayFunction) {
TestArrayLoop(arrayToBenched, benchName, testTimes, arrayFunction, BenchFunction);
},
TimedBenchArrayLoop = function (arrayToBenched, benchName, timeToRunMs, arrayFunction) {
// from John Resig, higher is better
TestArrayLoop(arrayToBenched, benchName, timeToRunMs, arrayFunction, TimedBench, true);
};
// thx http://gent.ilcore.com/2012/06/better-timer-for-javascript.html
w.performance = w.performance || {};
performance.now = (function () {
return performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function() { return new Date().getTime(); };
})();
// expose functions:
w.BenchLogWrite = BenchLogWrite;
w.BenchStart = BenchStart;
w.BenchEnd = BenchEnd;
w.BenchFunction = BenchFunction;
w.TimedBench = TimedBench;
w.FlushBenches = FlushBenches;
w.BenchArrayLoop = BenchArrayLoop;
w.TimedBenchArrayLoop = TimedBenchArrayLoop;
})(window);
// sample USAGE: (see http://jsbin.com/ogike/4 & http://jsbin.com/ehawud/6 for demos)
// adjust iteration count depending on length of task
var testTimes = 1000;
BenchFunction("trial1", testTimes, function () {
$(".captionWrapper > .inlineWrapOuter > .inlineWrap > img");
});
BenchFunction("trial2", testTimes, function () {
$(".captionWrapper img");
});
FlushBenches();
/* results are output to Firebug's console if it's available, otherwise it alerts them
On the example above I get the following:
Firefox w/o Firebug will alert:
trial1: 61ms
trial2: 57ms
Firefox w/ Firebug console:
trial1: 66ms
trial2: 63ms
IE6 will alert:
trial1: 672ms
trial2: 2094ms
In this specific case any minute perf gains in Firefox are canceled out by IE6 sucking.
*/
// timed bench example
var testLengthMs = 1000;
TimedBench("trial3", testLengthMs, function () {
$(".captionWrapper > .inlineWrapOuter > .inlineWrap > img");
});
TimedBench("trial4", testLengthMs, function () {
$(".captionWrapper img");
});
FlushBenches();
/* results: (with jQuery 1.4.2)
Firefox 3.6:
trial3: score for 1000ms: 18942
trial4: score for 1000ms: 20828
IE 8.0.6001.18882:
trial3: score for 1000ms: 10085
trial4: score for 1000ms: 10723
IE 8.0.6001.18882 64-bit:
trial3: score for 1000ms: 10081
trial4: score for 1000ms: 11212
Chrome 4.0.249.89 unknown (38071):
trial3: score for 1000ms: 34148
trial4: score for 1000ms: 36843
Safari 4.0.4 (531.21.10):
trial3: score for 1000ms: 39166
trial4: score for 1000ms: 43815
Opera 10.10:
trial3: score for 1000ms: 22655
trial4: score for 1000ms: 27130
*/
// array-loop example
var iconArray = [];
// *snip* add a bunch of items to array
BenchArrayLoop(iconArray, "iconArray", 10000, function (arrayItem) {
var x = arrayItem;
});
FlushBenches();
/* results:
Firefox:
iconArray: Standard: 310ms
iconArray: length var: 287ms
iconArray: Reverse: 145ms
iconArray: Reverse short: 124ms
iconArray: Duff's: 189ms
iconArray: Duff's modified: 252ms
IE6:
iconArray: Standard: 1078ms
iconArray: length var: 734ms
iconArray: Reverse: 750ms
iconArray: Reverse short: 578ms
iconArray: Duff's: 688ms
iconArray: Duff's modified: 593ms
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment