Search code examples
javascriptperformancefirefox

Strange result when speed testing Math() in Firefox


I got a strange result from a test I did (Firefox specific), and I would like to know more about how/why this is the result.

A typical result looks like this (10 million list items) (I have run it several times manually, I didn't feel like making a full on "statistics module").

Results for Firefox 72.0.2 (64-bit) on Windows 7

iteration:  40 ms - timer stopped
__rounding: 14 ms - timer stopped
______ceil: 16 ms - timer stopped
_____floor: 15 ms - timer stopped

What I find most strange is the iteration test.

The "effective" iteration code looks like this: arrNumbers[index] = arrNumbers[index]; and this code is part of ALL the tests, but the other parts have a Math function wrapped around the right part.

So it seams like the iteration test should dictate the speed for all other tests, I expected this part to be fastest, not slowest.

First I thought this was a "problem" with floating point numbers possibly being slower to process than integers, so I tried to just assign a 1 (int) so every function works on equal data, but the result is still the same.


Code: (will probably not run here since I'm using console.time() I guess. But you can just copy it as is, to a text file & change the file extension to .html & open it with Firefox, press F12 to open the inspection tool & switch to the Console tab if needed).

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Title</title>
    </head>
    <body>
        <script>

            function makeNrArray(loopSize) {
                var arrNumbers = [];
                for (let index = 0; index < loopSize; index++) {
                    arrNumbers[index] = 1; //Math.random();
                }
                return arrNumbers ; 
            }

            function testIterationSpeed(arrNumbers) {
                var arrLength = arrNumbers.length;

                console.time("iteration");
                for (let index = 0; index < arrLength; index++) {
                    arrNumbers[index] = arrNumbers[index];
                }
                console.timeEnd("iteration");
            }

            function testRoundingSpeed(arrNumbers) {
                var arrLength = arrNumbers.length;

                console.time("rounding");
                for (let index = 0; index < arrLength; index++) {
                    arrNumbers[index] = Math.round(arrNumbers[index]);
                }
                console.timeEnd("rounding");
            }

            function testCeilingSpeed(arrNumbers) {
                var arrLength = arrNumbers.length;

                console.time("ceil");
                for (let index = 0; index < arrLength; index++) {
                    arrNumbers[index] = Math.ceil(arrNumbers[index]);
                }
                console.timeEnd("ceil");
            }

            function testFlooringSpeed(arrNumbers) {
                var arrLength = arrNumbers.length;

                console.time("floor");
                for (let index = 0; index < arrLength; index++) {
                    arrNumbers[index] = Math.floor(arrNumbers[index]);
                }
                console.timeEnd("floor");
            }


            var loopSize = 10000000; // <---- Settings ;)

            let arrNumbers = makeNrArray(loopSize);
            testIterationSpeed(arrNumbers);

            arrNumbers = makeNrArray(loopSize);
            testRoundingSpeed(arrNumbers)

            arrNumbers = makeNrArray(loopSize);
            testCeilingSpeed(arrNumbers);

            arrNumbers = makeNrArray(loopSize);
            testFlooringSpeed(arrNumbers);
        </script>
    </body>
</html>


Other results:

Results for Firefox 72.0.2 (64-bit) (Same as above, just for completeness & ease of comparison)

iteration:  40 ms - timer stopped
__rounding: 14 ms - timer stopped
______ceil: 16 ms - timer stopped
_____floor: 15 ms - timer stopped

Firefox again, but now assigned 1.5 (float) as input data (instead of int, as above) (Math.random() gives a similar result)

iteration:  67 ms - timer stopped
__rounding: 33 ms - timer stopped
______ceil: 34 ms - timer stopped
_____floor: 32 ms - timer stopped

Results for Google Chrome Version 80.0.3987.106 (64 bit)

iteration:  11.7060546875   ms
__rounding: 12.194091796875 ms
______ceil: 11.73681640625  ms
_____floor: 11.551025390625 ms

Results for Internet Explorer 11.0.9600..... Update: 11.0

iteration:   37,3 ms
__rounding: 203,5 ms
______ceil:  85,9 ms
_____floor:  85,7 ms

Solution

  • It's actually the order you are running the tests, I believe.

    First of all, the results aren't that dramatic for me. In Chrome they're almost identical, and in Firefox I see a small--but consistent--increase in time on your iteration test. Usually it's around 5-15ms longer, but it's consistent, so I'll give it to you that it's real.

    If you add a Math.floor() to the iteration test, you'll still see higher numbers here.

    But if you move the iteration test to the end, like this:

    let arrNumbers = makeNrArray(loopSize);
    testRoundingSpeed(arrNumbers)
    
    arrNumbers = makeNrArray(loopSize);
    testCeilingSpeed(arrNumbers);
    
    arrNumbers = makeNrArray(loopSize);
    testFlooringSpeed(arrNumbers);
    
    arrNumbers = makeNrArray(loopSize);
    testIterationSpeed(arrNumbers);
    

    Then you'll see the testIterationSpeed result go down to the range of the others, while the testRoundingSpeed will go up.

    I suspect it has something to do with the allocation of memory, since the subsequent results use the same variable (well, the same let). I don't know the details. Regardless, it is less about what you are doing and more about when.