source: Dev/trunk/src/client/dojox/lang/tests/bench_decl.html

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 21.7 KB
Line 
1<html>
2        <head>
3                <title>OO/decl benchmark</title>
4                <style type="text/css">
5                        @import "../../../dojo/resources/dojo.css";
6
7            .stats th, .stats td { padding: 3pt; }
8            .stats th, .name { font-weight: bold; }
9            table.stats, .stats th, .stats td { border: 1px solid lightgray; }
10            .median { color: navy; font-weight: bold; }
11            .fastest { background-color: #ccf; }
12            .stablest { background-color: #ffc; }
13            .fastest.stablest { background-color: #cfc; }
14                </style>
15                <script type="text/javascript" src="../../../dojo/dojo.js" data-dojo-config="isDebug:true"></script>
16                <script type="text/javascript">
17                        dojo.require("dojox.lang.tests.declare-old");
18
19                        var d = dojo, oo = dojox.lang.oo, nothing = function(){};
20
21            // test harness
22
23            var DELAY = 20,     // pause in ms between tests
24                LIMIT = 50,     // the lower limit of a test
25                COUNT = 50;     // how many times to repeat the test
26
27            // the basic unit to run a test with timing
28            var runTest = function(f, n){
29                var start = new Date();
30                for(var i = 0; i < n; ++i){
31                    f();
32                }
33                var end = new Date();
34                return end.getTime() - start.getTime();
35            };
36
37            // find the threshold number of tests just exceeding the limit
38            var findThreshold = function(f, limit){
39                // very simplistic search probing only powers of two
40                var n = 1;
41                while(runTest(f, n) + runTest(nothing, n) < limit) n <<= 1;
42                return n;
43            };
44
45            var _runUnitTest = function(a, f, n, k, m, next){
46                a[k++] = runTest(f, n) - runTest(nothing, n);
47                if(k < m){
48                    setTimeout(d.hitch(null, _runUnitTest, a, f, n, k, m, next), DELAY);
49                }else{
50                    next(a);
51                }
52            };
53
54            var runTests = function(f, n, m, next){
55                var a = new Array(m);
56                _runUnitTest(a, f, n, 0, m, next);
57            };
58
59            // statistics
60
61            var statNames = ["minimum", "firstDecile", "lowerQuartile", "median", "upperQuartile", "lastDecile", "maximum", "average"];
62
63            var statAbbr = {
64                minimum:        "min",
65                maximum:        "max",
66                median:         "med",
67                lowerQuartile:  "25%",
68                upperQuartile:  "75%",
69                firstDecile:    "10%",
70                lastDecile:     "90%",
71                average:        "avg"
72            };
73
74            var getWeightedValue = function(a, pos){
75                var p = pos * (a.length - 1), t = Math.ceil(p), f = t - 1;
76                if(f <= 0){ return a[0]; }
77                if(t >= a.length){ return a[a.length - 1]; }
78                return a[f] * (t - p) + a[t] * (p - f);
79            };
80
81            var getStats = function(a, n){
82                var t = a.slice(0);
83                t.sort(function(a, b){ return a - b; });
84                var result = {
85                    // the five-number summary
86                    minimum:        t[0],
87                    maximum:        t[t.length - 1],
88                    median:         getWeightedValue(t, 0.5),
89                    lowerQuartile:  getWeightedValue(t, 0.25),
90                    upperQuartile:  getWeightedValue(t, 0.75),
91                    // extended to the Bowley's seven-figure summary
92                    firstDecile:    getWeightedValue(t, 0.1),
93                    lastDecile:     getWeightedValue(t, 0.9)
94                };
95                // add the average
96                for(var i = 0, sum = 0; i < t.length; sum += t[i++]);
97                result.average = sum / t.length;
98                d.forEach(statNames, function(name){
99                    if(result.hasOwnProperty(name) && typeof result[name] == "number"){
100                        result[name] /= n;
101                    }
102                });
103                return result;
104            };
105                       
106                        var testGroups = [];
107
108            // run a group of tests, prepare statistics and show results
109
110            var registerGroup = function(fs, bi, m, node, title){
111                var n = findThreshold(fs[bi].fun, LIMIT),
112                    x = {
113                        functions:  fs,
114                        stats:      [],
115                        process: function(a){
116                            if(a){
117                                this.stats.push(getStats(a, n));
118                                console.log("test #" + this.stats.length + " is completed: " + this.functions[this.stats.length - 1].name);
119                            }
120                            if(this.stats.length < this.functions.length){
121                                //setTimeout(d.hitch(null, runTests, this.functions[this.stats.length].fun, n, m, d.hitch(this, "process")), DELAY);
122                                var f = d.hitch(null, runTests, this.functions[this.stats.length].fun, n, m, d.hitch(this, "process"));
123                                f();
124                                return;
125                            }
126                            var diff = Math.max.apply(Math, d.map(this.stats, function(s){ return s.upperQuartile - s.lowerQuartile; })),
127                                prec = 1 - Math.floor(Math.log(diff) / Math.LN10), fastest = 0, stablest = 0;
128                            d.forEach(this.stats, function(s, i){
129                                if(i){
130                                    if(s.median < this.stats[fastest].median){
131                                        fastest = i;
132                                    }
133                                    if(s.upperQuartile - s.lowerQuartile < this.stats[i].upperQuartile - this.stats[i].lowerQuartile){
134                                        stablest = i;
135                                    }
136                                }
137                            }, this);
138                            // add the table
139                            var tab = ["<table class='stats'><thead><tr><th>Test</th>"];
140                                                        tab.push(d.map(this.functions, function(f, i){
141                                                                return "<th class='" + (i == fastest ? "fastest" : "") + " " + (i == stablest ? "stablest" : "") + "'>" + f.name + "</th>";
142                                                        }).join(""));
143                            tab.push("</tr></thead><tbody>");
144                                                        d.forEach(statNames, function(n){
145                                                                tab.push("<tr class='name " + n + "'><td>" + n + "</td>");
146                                                                d.forEach(this.stats, function(s, i){
147                                                                        tab.push("<td class='" + (i == fastest ? "fastest" : "") + " " + (i == stablest ? "stablest" : "") + "'>" + s[n].toFixed(prec) + "</td>");
148                                                                }, this);
149                                                                tab.push("</tr>");
150                                                        }, this);
151                            tab.push("</tbody></table>");
152                            d.place(tab.join(""), node);
153                                                        // next
154                                                        run();
155                        }
156                    };
157                                testGroups.push(function(){
158                                        console.log("all tests will be repeated " + n + " times in " + m + " series");
159                                        d.place("<h1>" + title + "</h1>", node);
160                                        x.process();
161                                });
162            };
163                       
164                        function run(){
165                                if(testGroups.length){
166                                        testGroups.shift()();
167                                }else{
168                                        setTimeout(function(){
169                                                console.log("Done!");
170                                                alert("Done!");
171                                        }, DELAY);
172                                }
173                        }
174
175            // actual benchmarks
176
177            var decl0 = dojox.lang.tests.declareOld, declx = d.declare;
178
179            var benchmarkClassCreation = function(){
180                var a0 = decl0("temp.A0", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
181                    b0 = decl0("temp.B0", a0, {m1: function(){}, m2: function(){}, m3: function(){}}),
182                    c0 = decl0("temp.C0", b0, {m1: function(){}, m2: function(){}, m3: function(){}}),
183
184                    ax = declx("temp.Ax", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
185                    bx = declx("temp.Bx", ax, {m1: function(){}, m2: function(){}, m3: function(){}}),
186                    cx = declx("temp.Cx", bx, {m1: function(){}, m2: function(){}, m3: function(){}}),
187
188                    group = [
189                        {
190                            name: "old/A",
191                            fun:  function(){ decl0("temp.test.A", null, {m1: function(){}, m2: function(){}, m3: function(){}}); }
192                        },
193                        {
194                            name: "new/A",
195                            fun:  function(){ declx("temp.test.A", null, {m1: function(){}, m2: function(){}, m3: function(){}}); }
196                        },
197                        {
198                            name: "old/B",
199                            fun:  function(){ decl0("temp.test.B", temp.A0, {m1: function(){}, m2: function(){}, m3: function(){}}); }
200                        },
201                        {
202                            name: "new/B",
203                            fun:  function(){ declx("temp.test.B", temp.Ax, {m1: function(){}, m2: function(){}, m3: function(){}}); }
204                        },
205                        {
206                            name: "old/C",
207                            fun:  function(){ decl0("temp.test.C", temp.B0, {m1: function(){}, m2: function(){}, m3: function(){}}); }
208                        },
209                        {
210                            name: "new/C",
211                            fun:  function(){ declx("temp.test.C", temp.Bx, {m1: function(){}, m2: function(){}, m3: function(){}}); }
212                        },
213                        {
214                            name: "old/D",
215                            fun:  function(){ decl0("temp.test.D", temp.C0, {m1: function(){}, m2: function(){}, m3: function(){}}); }
216                        },
217                        {
218                            name: "new/D",
219                            fun:  function(){ declx("temp.test.D", temp.Cx, {m1: function(){}, m2: function(){}, m3: function(){}}); }
220                        }
221                    ];
222                registerGroup(group, 0, COUNT, "result", "Create a class (single inheritance)");
223            };
224
225            var benchmarkClassMixing = function(){
226                var a0 = decl0("temp.A0", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
227                    b0 = decl0("temp.B0", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
228                    c0 = decl0("temp.C0", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
229
230                    ax = declx("temp.Ax", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
231                    bx = declx("temp.Bx", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
232                    cx = declx("temp.Cx", null, {m1: function(){}, m2: function(){}, m3: function(){}}),
233
234                    group = [
235                        {
236                            name: "old/A",
237                            fun:  function(){ decl0("temp.test.A", temp.A0, {m1: function(){}, m2: function(){}, m3: function(){}}); }
238                        },
239                        {
240                            name: "new/A",
241                            fun:  function(){ declx("temp.test.A", temp.Ax, {m1: function(){}, m2: function(){}, m3: function(){}}); }
242                        },
243                        {
244                            name: "old/A,B",
245                            fun:  function(){ decl0("temp.test.B", [temp.A0, temp.B0], {m1: function(){}, m2: function(){}, m3: function(){}}); }
246                        },
247                        {
248                            name: "new/A,B",
249                            fun:  function(){ declx("temp.test.B", [temp.Ax, temp.Bx], {m1: function(){}, m2: function(){}, m3: function(){}}); }
250                        },
251                        {
252                            name: "old/A,B,C",
253                            fun:  function(){ decl0("temp.test.C", [temp.A0, temp.B0, temp.C0], {m1: function(){}, m2: function(){}, m3: function(){}}); }
254                        },
255                        {
256                            name: "new/A,B,C",
257                            fun:  function(){ declx("temp.test.C", [temp.Ax, temp.Bx, temp.Cx], {m1: function(){}, m2: function(){}, m3: function(){}}); }
258                        }
259                    ];
260                registerGroup(group, 0, COUNT, "result", "Create a class with mixins");
261            };
262
263            var benchmarkConstructor = function(){
264                var A0 = decl0("temp.A0", null, {constructor: function(a){ this.a = a; }}),
265                    B0 = decl0("temp.B0", A0, {constructor: function(a, b){ this.b = b; }}),
266                    C0 = decl0("temp.C0", B0, {constructor: function(a, b, c){ this.c = c; }}),
267                    D0 = decl0("temp.D0", C0, {constructor: function(a, b, c, d){ this.d = d; }}),
268
269                    Ax = declx("temp.Ax", null, {constructor: function(a){ this.a = a; }}),
270                    Bx = declx("temp.Bx", Ax, {constructor: function(a, b){ this.b = b; }}),
271                    Cx = declx("temp.Cx", Bx, {constructor: function(a, b, c){ this.c = c; }}),
272                    Dx = declx("temp.Dx", Cx, {constructor: function(a, b, c, d){ this.d = d; }}),
273
274                    group = [
275                        {
276                            name: "old/A",
277                            fun:  function(){ var t = new A0("a"); }
278                        },
279                        {
280                            name: "new/A",
281                            fun:  function(){ var t = new Ax("a"); }
282                        },
283                        {
284                            name: "old/B",
285                            fun:  function(){ var t = new B0("a", "b"); }
286                        },
287                        {
288                            name: "new/B",
289                            fun:  function(){ var t = new Bx("a", "b"); }
290                        },
291                        {
292                            name: "old/C",
293                            fun:  function(){ var t = new C0("a", "b", "c"); }
294                        },
295                        {
296                            name: "new/C",
297                            fun:  function(){ var t = new Cx("a", "b", "c"); }
298                        },
299                        {
300                            name: "old/D",
301                            fun:  function(){ var t = new D0("a", "b", "c", "d"); }
302                        },
303                        {
304                            name: "new/D",
305                            fun:  function(){ var t = new Dx("a", "b", "c", "d"); }
306                        }
307                    ];
308                registerGroup(group, 0, COUNT, "result", "Create an instance");
309            };
310
311            var benchmarkRegularCalls = function(){
312                var A0 = decl0("temp.A0", null, {ma: function(a){ return this.a = a; }}),
313                    B0 = decl0("temp.B0", A0, {mb: function(b){ return this.b = b; }}),
314                    C0 = decl0("temp.C0", B0, {mc: function(c){ return this.c = c; }}),
315                    D0 = decl0("temp.D0", C0, {md: function(d){ return this.d = d; }}),
316
317                    Ax = declx("temp.Ax", null, {ma: function(a){ return this.a = a; }}),
318                    Bx = declx("temp.Bx", Ax, {mb: function(b){ return this.b = b; }}),
319                    Cx = declx("temp.Cx", Bx, {mc: function(c){ return this.c = c; }}),
320                    Dx = declx("temp.Dx", Cx, {md: function(d){ return this.d = d; }}),
321
322                    d0 = new D0,
323                                        dx = new Dx,
324
325                    group = [
326                        {
327                            name: "old/A",
328                            fun:  function(){ d0.ma("x"); }
329                        },
330                        {
331                            name: "new/A",
332                            fun:  function(){ dx.ma("x"); }
333                        },
334                        {
335                            name: "old/B",
336                            fun:  function(){ d0.mb("x"); }
337                        },
338                        {
339                            name: "new/B",
340                            fun:  function(){ dx.mb("x"); }
341                        },
342                        {
343                            name: "old/C",
344                            fun:  function(){ d0.mc("x"); }
345                        },
346                        {
347                            name: "new/C",
348                            fun:  function(){ dx.mc("x"); }
349                        },
350                        {
351                            name: "old/D",
352                            fun:  function(){ d0.md("x"); }
353                        },
354                        {
355                            name: "new/D",
356                            fun:  function(){ dx.md("x"); }
357                        }
358                    ];
359                registerGroup(group, 0, COUNT, "result", "Call a method");
360            };
361
362            var benchmarkInheritedCalls = function(){
363                var A0 = decl0("temp.A0", null, {m: function(a){ return this.a = a; }}),
364                    B0 = decl0("temp.B0", A0, {m: function(b){ return this.b = this.inherited(arguments); }}),
365                    C0 = decl0("temp.C0", B0, {m: function(c){ return this.c = this.inherited(arguments); }}),
366                    D0 = decl0("temp.D0", C0, {m: function(d){ return this.d = this.inherited(arguments); }}),
367
368                    Ax = declx("temp.Ax", null, {m: function(a){ return this.a = a; }}),
369                    Bx = declx("temp.Bx", Ax, {m: function(b){ return this.b = this.inherited(arguments); }}),
370                    Cx = declx("temp.Cx", Bx, {m: function(c){ return this.c = this.inherited(arguments); }}),
371                    Dx = declx("temp.Dx", Cx, {m: function(d){ return this.d = this.inherited(arguments); }}),
372
373                    b0 = new B0,
374                    bx = new Bx,
375
376                    c0 = new C0,
377                    cx = new Cx,
378
379                    d0 = new D0,
380                    dx = new Dx,
381
382                    group = [
383                        {
384                            name: "old/B",
385                            fun:  function(){ b0.m("x"); }
386                        },
387                        {
388                            name: "new/B",
389                            fun:  function(){ bx.m("x"); }
390                        },
391                        {
392                            name: "old/C",
393                            fun:  function(){ c0.m("x"); }
394                        },
395                        {
396                            name: "new/C",
397                            fun:  function(){ cx.m("x"); }
398                        },
399                        {
400                            name: "old/D",
401                            fun:  function(){ d0.m("x"); }
402                        },
403                        {
404                            name: "new/D",
405                            fun:  function(){ dx.m("x"); }
406                        }
407                    ];
408                registerGroup(group, 0, COUNT, "result", "Call an inherited method");
409            };
410
411            var benchmarkChains = function(){
412                var     A0 = decl0("temp.A0", null, {m: function(a){ this.a = a; }}),
413                    B0 = decl0("temp.B0", A0, {m: function(b){ this.inherited(arguments); this.b = b; }}),
414                    C0 = decl0("temp.C0", B0, {m: function(c){ this.inherited(arguments); this.c = c; }}),
415                    D0 = decl0("temp.D0", C0, {m: function(d){ this.inherited(arguments); this.d = d; }}),
416
417                    Ax = declx("temp.Ax", null, {m: function(a){ this.a = a; }, "-chains-": {m: "after"}}),
418                    Bx = declx("temp.Bx", Ax, {m: function(b){ this.b = b; }}),
419                    Cx = declx("temp.Cx", Bx, {m: function(c){ this.c = c; }}),
420                    Dx = declx("temp.Dx", Cx, {m: function(d){ this.d = d; }}),
421
422                    b0 = new B0,
423                    bx = new Bx,
424
425                    c0 = new C0,
426                    cx = new Cx,
427
428                    d0 = new D0,
429                    dx = new Dx,
430
431                    group = [
432                        {
433                            name: "old/B",
434                            fun:  function(){ b0.m("x"); }
435                        },
436                        {
437                            name: "new/B",
438                            fun:  function(){ bx.m("x"); }
439                        },
440                        {
441                            name: "old/C",
442                            fun:  function(){ c0.m("x"); }
443                        },
444                        {
445                            name: "new/C",
446                            fun:  function(){ cx.m("x"); }
447                        },
448                        {
449                            name: "old/D",
450                            fun:  function(){ d0.m("x"); }
451                        },
452                        {
453                            name: "new/D",
454                            fun:  function(){ dx.m("x"); }
455                        }
456                    ];
457                registerGroup(group, 0, COUNT, "result", "Call a chain");
458            };
459
460            var startBenchmarks = function(){
461                console.log("Used parameters: count=" + COUNT + " limit=" + LIMIT + "ms delay=" + DELAY + "ms");
462                benchmarkClassCreation();
463                benchmarkClassMixing();
464                benchmarkConstructor();
465                //benchmarkRegularCalls();
466                benchmarkInheritedCalls();
467                benchmarkChains();
468                                run();
469            };
470
471                        //dojo.addOnLoad(startBenchmarks);
472                </script>
473        </head>
474        <body>
475                <p>Warning: the benchmark takes several minutes, wait for a dialog box.</p>
476                <p>Color legend: <span class="fastest">the fastest</span>, <span class="stablest">the most stable</span>, <span class="fastest stablest">the fastest and the most stable</span></p>
477                <p><button onclick="startBenchmarks()">Start</button></p>
478        <div id="result"></div>
479        </body>
480</html>
Note: See TracBrowser for help on using the repository browser.