10

Edit After spending several hours on this and working with @pst, it turns out the issue was completely different.

Inside the code, you can see I used a timestamp shortcut of "+new Date()". This returns a timestamp as does the standard "new Date().getTime()".

However, +new Date() performs very, very badly when used with mathematical operations (+,-,/). Although the typeof() for the 'start' variable says 'number', something happens that makes it bloody slow. When using the standard getTime() method, there is no performance penalty when doing the timing subtractions.

Take a look at this jsperf detailing the problem, http://jsperf.com/new-date-timing.

In regards to @pst's very detailed answer and the efforts I made to replicate the linked question, use his answer as the canonical answer to that question.

I am going to change the title of this question to accurately reflect @pst's answer and my original intent, but will leave the original title and question for future reference.

New Question

Do javascript arrays utilize branch prediction on arrays of random sorted and unsorted data?

See @pst's answer below.

Original Title and Question below

Title: Array iterations taking 2x as long on the same data

I was looking at this question earlier, Why is it faster to process a sorted array than an unsorted array?, and wanted to try setting up the same test in javascript.

This has lead me to something unexpected. In the tests linked in the following fiddle, simply iterating over the same array of randomly generated number values with the same code results in vastly different response times.

I've tested this in Chrome, Safari, Firefox, and node.js.

In Chrome & node, the first iteration is faster than the 2nd iteration. In Safari and Firefox, the first iteration is slower than the 2nd iteration.

Here's the fiddle, http://jsfiddle.net/9QbWB/6/

In the linked fiddle, I've disabled sorting (thinking that was originally the issue, but it wasn't). Sorting the data made the looping even longer.

I've gone through the code pretty thoroughly to make sure I've removed anything that could be affecting the results. I feel like a particular set of scientists announcing FTL neutrinos, where I can't find a problem in my experiment and the data is unexpected.

In the code I'm including below, a few things like initial setTimeout, jQuery DOM visualizations, etc are for displaying data visually in jsfiddle.net. The core functions are the same.

    //javascript test of https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array

setTimeout(function(){

    var unsorted_list = $('#unsorted'),
        sorted_list = $('#sorted');


    var length = 32768,
        data = [];

    for(var i=0; i<length; i++){
        data[i] = Math.floor( Math.random()*256); 
    }


    var test = function(){
        var sum = 0,
            start = +new Date();

        for(var i=0; i<1000; i++){
            for(var c=0; c<length; c++){
                if( data[c] >= 128 ){
                    //sum += data[c];
                }
            }
        }

        return +new Date() - start;
    }


    //Unsorted
    var results = 0;
    for( var i=0; i<10; i++){
        var x = test();
        console.log(x);
        unsorted_list.append('<div>'+x+'</div>');
        results += x;
    }
    unsorted_list.append('<div>Final:'+(results/10)+'</div>');
    console.log( 'Unsorted: ', results/10 );


    //Sort array
    //data.sort();

    //Sorted
    var results = 0;
    for( var i=0; i<10; i++){
        var x = test();
        console.log(x);
        sorted_list.append('<div>'+x+'</div>');

        results += x;
    }
    sorted_list.append('<div>Final:'+(results/10)+'</div>');
    console.log( 'Sorted: ', results/10 );

},5000);
Community
  • 1
  • 1
Geuis
  • 41,122
  • 56
  • 157
  • 219
  • Good points @pst. I'll setup a jsperf as well and append it to the question in a few minutes. In regards to the other bits, I agree but they don't affect the performance issues in the question. I'll make the corrections in the jsperf though. – Geuis Oct 10 '12 at 23:09
  • Made the changes. Clean code is next to Dawkins, as they say. – Geuis Oct 10 '12 at 23:15
  • I believe the initial conclusion is flawed: http://jsfiddle.net/9QbWB/7/ - it is just that *Chrome starts running "much slower" (x2) after the first 10 iterations*; the fact that there are 2 outer loops does not affect this. The other browsers (FF and IE) do not seem affected - and IE actually gets a benefit from a warmup. FF is just mediocre and steady. –  Oct 11 '12 at 00:09
  • I believe there is some internal JIT threshold in Chrome that is being hit; but I do not know how or in which way. (Note that in my test I increased the outer loop from 10 to 20.) –  Oct 11 '12 at 00:13

1 Answers1

4

(Apparently this answer misses the question - left here for related reasons.)


Here is my jsperf case - http://jsperf.com/sorted-loop/2 - perhaps enough something will be revealed with more browsers. I have also included a test case using only bit-wise operations, as taken from the linked post (and I have not verified the validity in JS).

CONCLUSION: the performance appears to be related to branch prediction.

  1. The "+bitwise" test pair that does not use a condition are equivalent in speed (for the same browser) across all major browser runs. (Chrome is just faster than FF which just faster than IE at bit-wise operations; see other SO posts.)

  2. The "+cond" test pair that uses the condition is greatly affected and the sorted data is highly favored. This is the result that would be expected if branch prediction is a factor.

  • There's a couple of issues in your tests though. While I started out trying to replicate the original test, it actually moved into finding out why looping over the same array twice leads to vastly different iteration times. In your tests, the 'data' array is being regenerated *for each test run* and thus negates my original intent. Also, looping over 2 different arrays (data and sorted) doesn't test this iteration timing problem. – Geuis Oct 10 '12 at 23:41
  • Also, I'm not trusting jsperf at this point. Its providing ops/second, but not giving timing data. Here's the jsperf I have at the moment, http://jsperf.com/array-iteration-timing-differences – Geuis Oct 10 '12 at 23:45
  • @Geuis I might have missed what was really being tested .. however, even with re-using the same array the results appear consistent: http://jsperf.com/sorted-loop/3 - remember that without enough runs the JIT's do not get enough time to wake up; so it might just come down to when the threshold is met and/or implementation phases. –  Oct 10 '12 at 23:49
  • I think your tests better reflect the original intent, to replicate the other question. What I've just noticed about my question is that its not related to the array, but rather the function containing the loop over the array. I replicated the function 'test' in the jsfiddle and called it 'test2'. The timing results with 2 functions on data[] yields consistent times. Its *only* when test() gets called again that the iteration times go up. – Geuis Oct 10 '12 at 23:56
  • This is interesting. Turns out the timing problem I ran into isn't related to the array or function calls. The little timestamp shortcut I used performs horribly when used with mathematical operations. See this jsperf, http://jsperf.com/new-date-timing – Geuis Oct 11 '12 at 00:40
  • https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array/11227902#11227902 –  May 26 '19 at 13:48