Profiling Performance Sensitive Codes

I have a function that receives 2 arguments and 1 additional optional argument. The function should return trueif the first argument is greater than the second, falseif not, except that the third argument true(the third argument can only be true or false, false by default), in which case the function should return true if the first argument is greater than or equal to (strict comparison) with the second argument.

The function does not guarantee the receipt of arguments of the same type or even arguments that make any sense (the function can be called with null, undefined). In any case, the function must obey javascript behavior to compare the arguments received.

I have two functions, and I believe that the second should be faster, but neither my own tests nor jsperf results say this. In fact, the first function is 30-35% faster, which is quite a lot.

How can I track slow code paths inside each function? How to find out why the second function is slower?

This is my guideline:

var microtime = require('microtime');

/* Helper functions */

function maybeBool() {
    if(Math.round(Math.random() * 1)) {
        return true;
    } else {
        return false;
    }
}

function maybeNullUndef() {
    if(Math.round(Math.random() * 1)) {
        return null;
    } else {
        return undefined;
    }
}

function randomString() {
    return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}

function randomDate() {
    var y = Math.round(Math.random() * 100);
    return new Date(y);
}

function something() {
    var x = Math.round(Math.random()*3);

    switch(x) {
        case 0:
            return maybeBool();
            break;

        case 1:
            return maybeNullUndef();
            break;

        case 2:
            return randomString();
            break;

        case 3:
            return randomDate();
            break;
    }
}

var things_to_compare = [];

for(i = 0; i < 500000; i++) {
    var a = something();
    var b = something();
    things_to_compare.push([a, b]);
}

/* First function */

function gtHelper(prop1, prop2, equal) {

    // 'falsy' and Boolean handling
    if (!prop1 || !prop2 || prop1 === true || prop2 === true) {
    if ((prop1 === true || prop1 === false) && (prop2 === true || prop2 === false)) {
        if (equal) {
        return prop1 === prop2;
        } else {
        if (prop1) {
            return !prop2;
        } else {
            return false;
        }
        }
    }

    if (prop1 === undefined || prop1 === null || prop1 === false || prop2 === true) {
        return !!equal || false;
    }
    if (prop2 === undefined || prop2 === null || prop1 === true || prop2 === false) {
        return true;
    }

    if (prop1 > prop2) {
        return true;
    }

    if (prop1 < prop2) {
        return false;
    }

    // not lt and and not gt so equality assumed-- this ordering of tests is date compatible
    return equal;
    }

    if (prop1 > prop2) {
    return true;
    }

    if (prop1 < prop2) {
    return false;
    }

    // not lt and and not gt so equality assumed-- this ordering of tests is date compatible
    return equal;
}


/* Second function */

function gtHelper2 (prop1, prop2, equal) {

    equal = !!equal;

    //If 'prop1' is any of those, the result will be always 'false',
    //unless 'equal' is true.
    switch (prop1) {
            case "":
            case null:
            case false:
            case undefined:
                    return (prop1 === prop2 && equal);
    }

    //If 'prop2' is any of those, the result will be always 'true'
    switch (prop2) {
            case "":
            case null:
            case false:
            case undefined:
                    return true;
    }

    if (prop1 > prop2 || (prop1 === prop2 && equal)) {
            return true;
    } else if (prop1 < prop2) {
            return false;
    } else {
            return equal;
    }
}

/* Benchmark */

var res1 = 0;
for(n = 0; n < 30; n++) {
var now = microtime.now();
    for(i = 0; i < 500000; i++) {
        gtHelper(things_to_compare[i][0], things_to_compare[i][1]);
    }
var now1 = microtime.now();

res1 += now1 - now;
}



var res2 = 0;
for(n = 0; n < 30; n++) {
var now = microtime.now();
    for(i = 0; i < 500000; i++) {
        gtHelper2(things_to_compare[i][0], things_to_compare[i][1]);
    }
var now1 = microtime.now();

res2 += now1 - now;
}

console.log("gtHelper:", res1/30);
console.log("gtHelper2:", res2/30);

Edit:

I continued to work on the second function, I achieved it a little faster, but it lags behind the first function.

Here's what it looks like now:

function gtHelper2 (prop1, prop2, equal) {

    //If 'prop1' is any of those, the result will be always 'false',
    //unless 'equal' is true.
    if (!prop1) {
        return (prop1 === prop2 && !!equal);
    }

    //If 'prop2' is any of those, the result will be always 'true'
    if (!prop2) {
        return true;
    }

    if (prop1 > prop2) {
        return true;
    } else if (prop1 < prop2) {
        return false;
    } else if (prop1 === prop2 && !!equal) {
        return true;
    } else {
        return !!equal;
    }
}
+4
source share
1 answer

Your two functions do not return the same thing.

gtHelper(true, 'string')         // true
gtHelper2(true, 'string')        // false

gtHelper('string', new Date())  // undefined
gtHelper2('string', new Date()) // false

gtHelper(new Date(), 'string')  // undefined
gtHelper2(new Date(), 'string') // false

If you can make these functions behave the same way, I'm sure you will see more meaningful results.

, , , , switch . ECMA switch, , . , Firefox , switch . - V8.

0

All Articles