public
Description: Profile calls to jQuery selectors.
Homepage:
Clone URL: git://github.com/osteele/jquery-profile.git
jquery-profile / jquery.profile.js
100644 118 lines (113 sloc) 4.085 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* JQuery Profile Plugin
* Version 1.0
* http://plugins.jquery.com/project/profile
*
* Copyright 2008 by Oliver Steele
* Dual licensed under the MIT and GPL Licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
 
/**
* Log calls to jQuery(selector), and display their timings.
*
* Usage:
* jQuery.profile.start();
* // do some stuff
* jQuery.profile.done();
*
* Or, include ?jquery.profile.start in the url to start profiling when the
* this script is loaded. You will still need to call .done() to see the
* report.
*
* @type jQuery
* @name profile
* @author Oliver Steele (steele@osteele.com)
*/
(function($) {
    var profile = $.profile = start;
    
    var stats,
        statsIndex,
        savedInit;
    $.extend(profile, {
        done: function() { this.stop(); this.report() },
        start: start, // $.extend ignores this, so we set it below
        reset: reset,
        report: function(options) {
            options = options || {};
            stats.sort(function(a, b) {return b.total - a.total});
            var rows = [],
                ellipsisPattern = new RegExp('(.{'+(options.maxSelectorLength||20)+'}).*');
            rows.push(['Selector', 'Count', 'Total', 'Avg+/-stddev']);
            for (var i = 0; i < Math.min(options.limit || 10, stats.length); i++) {
                var entry = stats[i],
                    n = entry.count,
                    x = entry.total / n,
                    sd = Math.sqrt((n*entry.squares - x*x) / (n*(n-1)));
                rows.push([entry.selector.replace(ellipsisPattern, '$1...'),
                           n,
                           entry.total + 'ms',
                           (x + (n > 1 ? 'ms+/-' + sd : 'ms')).replace(/(\.\d\d)\d+/g, '$1')]);
            }
            this.printTable(rows, {0:{align:'left'}, 3:{align:'left'}});
        },
        printTable: function(rows, options) {
            var widths = [], padstr = ' ';
            for (var i = 0; i < rows.length; i++)
                for (var j = 0; j < rows[i].length; j++)
                    widths[j] = Math.max(widths[j]||0, String(rows[i][j]).length);
            for (var i = 0; i < rows.length; i++) {
                var row = rows[i], fields = [];
                for (var j = 0; j < row.length; j++) {
                    var padlen = widths[j] - String(row[j]).length;
                    while (padstr.length < padlen) padstr += padstr;
                    var pad = padstr.slice(0, padlen),
                        left = (options[j]||{}).align == 'left';
                    left || fields.push(pad);
                    fields.push(row[j]);
                    left && fields.push(pad);
                }
                console.info(fields.join(' '));
            }
        },
        stop: function() {
            if (savedInit) {
                jQuery.fn.init = savedInit;
                savedInit = null;
            }
        }
    });
    profile.start = start;
    
    function start() {
        reset();
        savedInit = jQuery.fn.init;
        jQuery.fn.init = init;
        function init(selector, context) {
            var t0 = new Date,
                result = savedInit.call(jQuery.fn, selector, context),
                dt = new Date - t0;
            if (typeof selector == 'string') {
                var entry = statsIndex[selector];
                if (!entry) {
                    entry = statsIndex[selector] = {
                        selector : selector,
                        count : 0,
                        total : 0,
                        squares : 0
                    }
                    stats.push(entry);
                }
                entry.count += 1;
                entry.total += dt;
                entry.squares += dt*dt;
            }
            return result;
        }
    }
    function reset() {
        stats = [];
        statsIndex = {};
    }
})(jQuery);
 
if (window.location.search.match(/[\?&]jquery.profile.start\b/))
    jQuery.profile();