b2c05a149980d9a0da108e215b5ec46cfdef8b24
[jquery.git] / build / speed / benchmarker.js
1   jQuery.benchmarker.tests = [
2                 "*",
3                 "body", "body div", "div", 
4                 "div div div", "div div", ".dialog", "div.dialog", "div .dialog",
5                 "#speech5", "div#speech5", "div #speech5", "div > div", "div.scene div.dialog",
6                 "div#scene1.scene div.dialog div.direction", "#scene1 #speech1", "body > div.dialog div div#speech5",
7                 "div:not(#speech5)", "div:not(.dialog)",
8                 "div:nth-child(even)", "div:nth-child(odd)",
9                 "div:nth-child(1)", "div:nth-child(2n)",
10                 "div:nth-child(2n+3)", "div:first-child",
11                 "div:last-child", "div:only-child",
12                 "div:contains(CELIA)",
13                 "div ~ div", "div + div",
14                 "div[class]", "div[class=dialog]", "div[class!=dialog]", 
15                 "div[class^=dialog]", "div[class$=dialog]", "div[class*=dialog]"
16                 ]
17
18   jQuery.fn.benchmark = function() {
19     this.each(function() {
20       try {
21         jQuery(this).parent().children("*:gt(1)").remove();
22       } catch(e) { }
23     })
24     // set # times to run the test in index.html
25     var times = parseInt(jQuery("#times").val());
26     jQuery.benchmarker.startingList = this.get();
27     benchmark(this.get(), times, jQuery.benchmarker.libraries);
28   }
29
30   jQuery(function() {
31     for(i = 0; i < jQuery.benchmarker.tests.length; i++) {
32       jQuery("tbody").append("<tr><td class='test'>" + jQuery.benchmarker.tests[i] + "</td></tr>");
33     }
34     jQuery("tbody tr:first-child").remove();
35     jQuery("td.test").before("<td><input type='checkbox' checked='checked' /></td>");
36     jQuery("button.runTests").bind("click", function() {
37       jQuery('td:has(input:checked) + td.test').benchmark();
38     });
39
40     jQuery("button.retryTies").bind("click", function() { jQuery("tr:has(td.tie) td.test").benchmark() })
41
42     jQuery("button.selectAll").bind("click", function() { jQuery("input[type=checkbox]").each(function() { this.checked = true }) })
43     jQuery("button.deselectAll").bind("click", function() { jQuery("input[type=checkbox]").each(function() { this.checked = false }) })
44
45     jQuery("#addTest").bind("click", function() {
46       jQuery("table").append("<tr><td><input type='checkbox' /></td><td><input type='text' /><button>Add</button></td></tr>");
47       jQuery("div#time-test > button").each(function() { this.disabled = true; })
48       jQuery("tbody tr:last button").bind("click", function() {
49         var td = jQuery(this).parent();
50         td.html("<button>-</button>" + jQuery(this).prev().val()).addClass("test");
51         jQuery("div#time-test > button").each(function() { this.disabled = false; })
52         jQuery("button", td).bind("click", function() { jQuery(this).parents("tr").remove(); })
53       })
54     })
55
56     var headers = jQuery.map(jQuery.benchmarker.libraries, function(i,n) {
57       var extra = n == 0 ? "basis - " : "";
58       return "<th>" + extra + i + "</th>"
59     }).join("");
60
61     jQuery("thead tr").append(headers);
62
63     var footers = "";
64     for(i = 0; i < jQuery.benchmarker.libraries.length; i++)
65       footers += "<th></th>"
66
67     var wlfooters = "";
68     for(i = 0; i < jQuery.benchmarker.libraries.length; i++)
69       wlfooters += "<td><span class='wins'>W</span> / <span class='fails'>F</span></th>"
70
71     jQuery("tfoot tr:first").append(footers);
72     jQuery("tfoot tr:last").append(wlfooters);
73
74   });
75
76    benchmark = function(list, times, libraries) {
77      if(list[0]) {
78        var times = times || 50;
79        var el = list[0];
80        var code = jQuery(el).text().replace(/^-/, "");
81          var timeArr = []
82          for(i = 0; i < times + 2; i++) {
83            var time = new Date()
84            try {
85              window[libraries[0]](code);
86            } catch(e) { }
87            timeArr.push(new Date() - time);
88          }
89          var diff = Math.sum(timeArr) - Math.max.apply( Math, timeArr )
90                 - Math.min.apply( Math, timeArr );
91          try {
92            var libRes = window[libraries[0]](code);
93            var jqRes = jQuery(code);
94            if(((jqRes.length == 0) && (libRes.length != 0)) ||
95              (libRes.length > 0 && (jqRes.length == libRes.length)) ||
96              ((libraries[0] == "cssQuery" || libraries[0] == "jQuery") && code.match(/nth\-child/) && (libRes.length > 0)) ||
97              ((libraries[0] == "jQold") && jqRes.length > 0)) {
98              jQuery(el).parent().append("<td>" + Math.round(diff / times * 100) / 100 + "ms</td>");
99            } else {
100              jQuery(el).parent().append("<td class='fail'>FAIL</td>");
101            }
102          } catch(e) {
103            jQuery(el).parent().append("<td class='fail'>FAIL</td>");
104          }
105        setTimeout(benchmarkList(list, times, libraries), 100);
106      } else if(libraries[1]) {
107        benchmark(jQuery.benchmarker.startingList, times, libraries.slice(1));
108      } else {
109        jQuery("tbody tr").each(function() {
110          var winners = jQuery("td:gt(1)", this).min(2);
111          if(winners.length == 1) winners.addClass("winner");
112          else winners.addClass("tie");
113        });
114        setTimeout(count, 100);
115      }
116    }
117
118   function benchmarkList(list, times, libraries) {
119     return function() {
120       benchmark(list.slice(1), times, libraries);
121     }
122   }
123
124  function count() {
125    for(i = 3; i <= jQuery.benchmarker.libraries.length + 2 ; i++) {
126      var fails = jQuery("td:nth-child(" + i + ").fail").length;
127      var wins = jQuery("td:nth-child(" + i + ").winner").length;
128      jQuery("tfoot tr:first th:eq(" + (i - 1) + ")")
129       .html("<span class='wins'>" + wins + "</span> / <span class='fails'>" + fails + "</span>");
130    }
131  }
132
133
134  jQuery.fn.maxmin = function(tolerance, maxmin, percentage) {
135    tolerance = tolerance || 0;
136    var target = Math[maxmin].apply(Math, jQuery.map(this, function(i) {
137      var parsedNum = parseFloat(i.innerHTML.replace(/[^\.\d]/g, ""));
138      if(parsedNum || (parsedNum == 0)) return parsedNum;
139    }));
140    return this.filter(function() {
141      if( withinTolerance(parseFloat(this.innerHTML.replace(/[^\.\d]/g, "")), target, tolerance, percentage) ) return true;
142    })
143  }
144
145  jQuery.fn.max = function(tolerance, percentage) { return this.maxmin(tolerance, "max", percentage) }
146  jQuery.fn.min = function(tolerance, percentage) { return this.maxmin(tolerance, "min", percentage) }
147
148  function withinTolerance(number, target, tolerance, percentage) {
149    if(percentage) { var high = target + ((tolerance / 100) * target); var low = target - ((tolerance / 100) * target); }
150    else { var high = target + tolerance; var low = target - tolerance; }
151    if(number >= low && number <= high) return true;
152  }
153
154  Math.sum = function(arr) {
155    var sum = 0;
156    for(i = 0; i < arr.length; i++) sum += arr[i];
157    return sum;
158  }