118

Is there a package that helps me benchmark JavaScript code? I'm not referring to Firebug and such tools.

I need to compare 2 different JavaScript functions that I have implemented. I'm very familiar with Perl's Benchmark (Benchmark.pm) module and I'm looking for something similar in JavaScript.

Has the emphasis on benchmarking JavaScript code gone overboard? Can I get away with timing just one run of the functions?

4castle
  • 28,713
  • 8
  • 60
  • 94
Ionic Walrus
  • 1,455
  • 4
  • 13
  • 10

8 Answers8

121

jsperf.com is the go-to site for testing JS performance. Start there. If you need a framework for running your own tests from the command line or scripts use Benchmark.js, the library upon which jsperf.com is built.

Note: Anyone testing Javascript code should educate themselves on the pitfalls of "microbenchmarks" (small tests that target a specific feature or operation, rather than more complex tests based on real-world code patterns). Such tests can be useful but are prone to inaccuracy due to how modern JS runtimes operate. Vyacheslav Egorov's presentation on performance and benchmarking is worth watching to get a feel for the nature of the problem(s).

Edit: Removed references to my JSLitmus work as it's just no longer relevant or useful.

broofa
  • 35,170
  • 11
  • 65
  • 70
  • 3
    Update: Just use jsperf.com - it's gotten a lot better, and works really well for this sort of thing. jslitmus still works, but hasn't been actively developed for quite some time. – broofa Sep 02 '11 at 00:30
  • This is the superior answer. +1 – Justin Force Jan 04 '12 at 19:44
  • 1
    I wanted to use jsperf, but it seems to be counting how many times it can run the code for a time period, rather than timing the actual call for N loops. I wish they had an option to choose. – Jeach Feb 21 '13 at 15:56
  • 1
    @Jeach - jsperf gives "operations/second". Just multiply that value by the time (in seconds) you're code will run for. – broofa Dec 21 '13 at 13:44
  • 5
    Update: jsperf is no longer online, and there is no word when it will be back online. See [this github thread](https://github.com/jsperf/jsperf.com/issues/18) for more info. – James Gould Jul 24 '15 at 16:59
  • Update: jsperf is back! – John Feb 25 '17 at 01:12
  • @Jeach What's the difference ? – doubleOrt May 08 '18 at 18:57
  • @doubleOrt I think he means he wants a way to see "this snippet takes, on average, X milliseconds to run". (it can be done by calculating `1000/ops-per-sec` in address-bar, but would be nice to have it displayed on the page itself) – Venryx Apr 04 '19 at 23:23
79

Just adding a quick timer to the mix, which someone may find useful:

var timer = function(name) {
    var start = new Date();
    return {
        stop: function() {
            var end  = new Date();
            var time = end.getTime() - start.getTime();
            console.log('Timer:', name, 'finished in', time, 'ms');
        }
    }
};

Ideally it would be placed in a class, and not used as a global like I did for example purposes above. Using it would be pretty simple:

var t = timer('Some label');
// code to benchmark
t.stop(); // prints the time elapsed to the js console
Kenny
  • 1,410
  • 1
  • 12
  • 13
74

Just simple way.

console.time('test');
console.timeEnd('test');
stadnik0ff
  • 902
  • 5
  • 4
  • 5
    This should be the accepted answer. Using a third party service sometimes is not convenient, and just using a simple built in feature is excellent. – brainbag Mar 19 '19 at 23:54
  • 1
    @brainbag - The question was about benchmarking, which involves more than simply timing how long a bit of code runs. Also, console timers are only useful if the code in question takes more than 1 millisecond (the limit of their resolution). – broofa Apr 14 '19 at 13:55
  • You may also want to run your benchmark in a test suite, which require to have access to the timer value. – Robin Goupil Dec 17 '19 at 15:13
38

Just time several iterations of each function. One iteration probably won't be enough, but (depending on how complex your functions are) somewhere closer to 100 or even 1,000 iterations should do the job.

Firebug also has a profiler if you want to see which parts of your function are slowing it down.

Edit: To future readers, the below answer recommending JSPerf should be the correct answer. I would delete mine, but I can't because it has been selected by the OP. There is much more to benchmarking than just running many iterations, and JSPerf takes care of that for you.

Sasha Chedygov
  • 116,670
  • 26
  • 98
  • 110
  • 12
    Simply timing a pre-defined number of iterations of your code is [not bulletproof at all](http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/). Also, having Firebug open disables Firefox’s Just-In-Time (JIT) compiler, which means the tests will be running in the interpreter, i.e. much slower than they would otherwise. Using Firebug’s profiler won’t give you the results you’d expect. – Mathias Bynens Feb 16 '11 at 11:28
  • 1
    @Mathias: Well, to be fair, this answer is really old. – Sasha Chedygov Feb 16 '11 at 22:58
  • 2
    Sure, no offense mate. I just thought I’d comment for future reference now that more research has been done on the subject. – Mathias Bynens Feb 24 '11 at 10:24
  • 4
    Or use http://jsben.ch since jsperf is down – EscapeNetscape Nov 06 '16 at 19:58
20

I have been using this simple implementation of @musicfreaks answer. There are no features, but it is really easy to use. This bench(function(){return 1/2;}, 10000, [], this) will calculate 1/2 10,000 times.

/**
 * Figure out how long it takes for a method to execute.
 * 
 * @param {Function} method to test 
 * @param {number} iterations number of executions.
 * @param {Array} args to pass in. 
 * @param {T} context the context to call the method in.
 * @return {number} the time it took, in milliseconds to execute.
 */
var bench = function (method, iterations, args, context) {

    var time = 0;
    var timer = function (action) {
        var d = Date.now();
        if (time < 1 || action === 'start') {
            time = d;
            return 0;
        } else if (action === 'stop') {
            var t = d - time;
            time = 0;    
            return t;
        } else {
            return d - time;    
        }
    };

    var result = [];
    var i = 0;
    timer('start');
    while (i < iterations) {
        result.push(method.apply(context, args));
        i++;
    }

    var execTime = timer('stop');

    if ( typeof console === "object") {
        console.log("Mean execution time was: ", execTime / iterations);
        console.log("Sum execution time was: ", execTime);
        console.log("Result of the method call was:", result[0]);
    }

    return execTime;  
};
fncomp
  • 5,630
  • 2
  • 30
  • 41
9

It’s really hard to write decent cross-browser benchmarks. Simply timing a pre-defined number of iterations of your code is not bulletproof at all.

As @broofa already suggested, check out jsPerf. It uses Benchmark.js behind the scenes.

Mathias Bynens
  • 130,201
  • 49
  • 208
  • 240
2

if writing a custom benchmark script be sure to note that some browsers apply dom manipulations only after function in which they are defined is ended. More details here http://www.quirksmode.org/blog/archives/2009/08/when_to_read_ou.html

lukins
  • 21
  • 1
1

If you need something simple you can do like this:

'use strict'
console.clear()

const powerOf = x => y => Math.pow(x, y)
const powerOfThree = powerOf(3)

function performanceCalc(fn, ...params) {
    const start = +new Date()
    const result = fn(...params)
    const end = +new Date()

    console.log(`Result: ${result}. Execution Time: ${end - start} ms`)
}

performanceCalc(powerOfThree, 2)

Here is an example of the code

Vlad Bezden
  • 59,971
  • 18
  • 206
  • 157
  • Simple was definitely the best option in my case... writing some tests to benchmark response times for API (no need for extremely accurate times). – kashiraja Sep 15 '17 at 23:42