Changeset 161458 in webkit


Ignore:
Timestamp:
Jan 7, 2014, 3:22:22 PM (12 years ago)
Author:
rniwa@webkit.org
Message:

DoYouEvenBench: Extract tests and runner code from benchmark.js/html
https://bugs.webkit.org/show_bug.cgi?id=126596

Reviewed by Stephanie Lewis.

Extracted benchmark-runner.js and tests.js out of benchmark.js and benchmark.html.

Added a "client" interface to BenchmarkRunner so that benchmark.html could register necessary hooks to
update its UI. Also made BenchmarkRunner store a tree of results so that the serialization of test names
could be isolated from BenchmarkRunner itself in the future.

  • DoYouEvenBench/benchmark.html:

Moved the code to instantiate and update UI here from benchmark.js. The test code was moved out of this
file into resources/tests.js.

  • DoYouEvenBench/resources/benchmark-runner.js: Renamed from PerformanceTests/DoYouEvenBench/benchmark.js.

(SimplePromise): Moved from benchmark.js
(SimplePromise.prototype.then): Ditto.
(SimplePromise.prototype.resolve): Ditto.
(BenchmarkTestStep): Added. Wraps each test step.
(BenchmarkRunner.suite): Moved from benchmark.js.
(BenchmarkRunner.setClient): Added.
(BenchmarkRunner.waitForElement): Moved.
(BenchmarkRunner._removeFrame): Ditto.
(BenchmarkRunner._appendFrame): Ditto. Set the width and the height of the iframe as they're more than
presentational as they affect performance.
(BenchmarkRunner._waitAndWarmUp): Ditto.
(BenchmarkRunner._runTest): Ditto.
(BenchmarkRunner._testName): Ditto.
(BenchmarkState): Ditto.
(BenchmarkState.prototype.currentSuite): Ditto.
(BenchmarkState.prototype.currentTest): Ditto.
(BenchmarkState.prototype.next): Ditto.
(BenchmarkState.prototype.isFirstTest): Ditto.
(BenchmarkState.prototype.prepareCurrentSuite): Ditto.
(BenchmarkRunner.step): Ditto.
(BenchmarkRunner._runTestAndRecordResults): Ditto. Note the code to update the UI has been move to
benchmark.html. Also moved the code to accumulate the totals here from _finalize.
(BenchmarkRunner._finalize): Moved.

  • DoYouEvenBench/resources/tests.js: Copied from PerformanceTests/DoYouEvenBench/benchmark.html.

Uses BenchmarkTestStep instead of an array for each test step.

Location:
trunk/PerformanceTests
Files:
3 added
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/PerformanceTests/ChangeLog

    r161235 r161458  
     12014-01-07  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        DoYouEvenBench: Extract tests and runner code from benchmark.js/html
     4        https://bugs.webkit.org/show_bug.cgi?id=126596
     5
     6        Reviewed by Stephanie Lewis.
     7       
     8        Extracted benchmark-runner.js and tests.js out of benchmark.js and benchmark.html.
     9
     10        Added a "client" interface to BenchmarkRunner so that benchmark.html could register necessary hooks to
     11        update its UI. Also made BenchmarkRunner store a tree of results so that the serialization of test names
     12        could be isolated from BenchmarkRunner itself in the future.
     13
     14        * DoYouEvenBench/benchmark.html:
     15        Moved the code to instantiate and update UI here from benchmark.js. The test code was moved out of this
     16        file into resources/tests.js.
     17
     18        * DoYouEvenBench/resources/benchmark-runner.js: Renamed from PerformanceTests/DoYouEvenBench/benchmark.js.
     19        (SimplePromise): Moved from benchmark.js
     20        (SimplePromise.prototype.then): Ditto.
     21        (SimplePromise.prototype.resolve): Ditto.
     22        (BenchmarkTestStep): Added. Wraps each test step.
     23        (BenchmarkRunner.suite): Moved from benchmark.js.
     24        (BenchmarkRunner.setClient): Added.
     25        (BenchmarkRunner.waitForElement): Moved.
     26        (BenchmarkRunner._removeFrame): Ditto.
     27        (BenchmarkRunner._appendFrame): Ditto. Set the width and the height of the iframe as they're more than
     28        presentational as they affect performance.
     29        (BenchmarkRunner._waitAndWarmUp): Ditto.
     30        (BenchmarkRunner._runTest): Ditto.
     31        (BenchmarkRunner._testName): Ditto.
     32        (BenchmarkState): Ditto.
     33        (BenchmarkState.prototype.currentSuite): Ditto.
     34        (BenchmarkState.prototype.currentTest): Ditto.
     35        (BenchmarkState.prototype.next): Ditto.
     36        (BenchmarkState.prototype.isFirstTest): Ditto.
     37        (BenchmarkState.prototype.prepareCurrentSuite): Ditto.
     38        (BenchmarkRunner.step): Ditto.
     39        (BenchmarkRunner._runTestAndRecordResults): Ditto. Note the code to update the UI has been move to
     40        benchmark.html. Also moved the code to accumulate the totals here from _finalize.
     41        (BenchmarkRunner._finalize): Moved.
     42
     43        * DoYouEvenBench/resources/tests.js: Copied from PerformanceTests/DoYouEvenBench/benchmark.html.
     44        Uses BenchmarkTestStep instead of an array for each test step.
     45
    1462014-01-02  Myles C. Maxfield  <mmaxfield@apple.com>
    247
  • trunk/PerformanceTests/DoYouEvenBench/benchmark.html

    r157009 r161458  
    33<head>
    44<title>DoYouEvenBench</title>
    5 <script src="benchmark.js"></script>
     5<script src="resources/benchmark-runner.js" defer></script>
     6<script src="resources/tests.js" defer></script>
     7<style>
     8iframe { border: 1px solid black; }
     9ol { list-style: none; margin: 0; padding: 0; }
     10ol ol { margin-left: 2em; list-position: outside; }
     11.running { text-decoration: underline; }
     12.ran { color: grey; }
     13nav { position: absolute; right: 10px; }
     14</style>
     15</head>
     16<body>
    617<script>
    718
    8 var numberOfItemsToAdd = 100;
     19window.addEventListener('load', function () {
     20    var self = BenchmarkRunner;
     21    var control = document.createElement('nav');
    922
    10 BenchmarkRunner.suite({
    11     name: 'VanillaJS/TodoMVC',
    12     url: 'todomvc/vanilla-examples/vanillajs/index.html',
    13     prepare: function (contentWindow, contentDocument) {
    14         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    15             element.focus();
    16             return element;
     23    var suites = BenchmarkRunner._suites;
     24    var ol = document.createElement('ol');
     25    var checkboxes = [];
     26    for (var suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {
     27        var suite = suites[suiteIndex];
     28        var li = document.createElement('li');
     29        var checkbox = document.createElement('input');
     30        checkbox.id = suite.name;
     31        checkbox.type = 'checkbox';
     32        checkbox.checked = true;
     33        checkbox.onchange = (function (suite, checkbox) { return function () { suite.disabled = !checkbox.checked; } })(suite, checkbox);
     34        checkbox.onchange();
     35        checkboxes.push(checkbox);
     36
     37        li.appendChild(checkbox);
     38        var label = document.createElement('label');
     39        label.appendChild(document.createTextNode(self._testName(suite)));
     40        li.appendChild(label);
     41        label.htmlFor = checkbox.id;
     42
     43        var testList = document.createElement('ol');
     44        for (var testIndex = 0; testIndex < suite.tests.length; testIndex++) {
     45            var testItem = document.createElement('li');
     46            var test = suite.tests[testIndex];
     47            var anchor = document.createElement('a');
     48            anchor.id = suite.name + '-' + test.name;
     49            test.anchor = anchor;
     50            anchor.appendChild(document.createTextNode(self._testName(suite, test.name)));
     51            testItem.appendChild(anchor);
     52            testList.appendChild(testItem);
     53        }
     54        li.appendChild(testList);
     55
     56        ol.appendChild(li);
     57    }
     58
     59    control.appendChild(ol);
     60
     61    BenchmarkRunner.setClient({
     62        willRunTest: function (suite, test) {
     63            test.anchor.classList.add('running');
     64        },
     65        didRunTest: function (suite, test) {
     66            var classList = test.anchor.classList;
     67            classList.remove('running');
     68            classList.add('ran');
     69        },
     70        didRunSuites: function (measuredValues) {
     71            var results = '';
     72            var total = 0; // FIXME: Compute the total properly.
     73            for (var suiteName in measuredValues) {
     74                var suiteResults = measuredValues[suiteName];
     75                for (var testName in suiteResults.tests) {
     76                    var testResults = suiteResults.tests[testName];
     77                    for (var subtestName in testResults) {
     78                        results += suiteName + ' : ' + testName + ' : ' + subtestName
     79                            + ': ' + testResults[subtestName] + ' ms\n';
     80                    }
     81                }
     82                results += suiteName + ' : ' + suiteResults.total + ' ms\n';
     83                total += suiteResults.total;
     84            }
     85            results += 'Total : ' + total + ' ms\n';
     86
     87            if (!results)
     88                return;
     89
     90            var pre = document.createElement('pre');
     91            document.body.appendChild(pre);
     92            pre.textContent = results;
     93        }
     94    });
     95
     96    var currentState = null;
     97
     98    // Don't call step while step is already executing.
     99    var button = document.createElement('button');
     100    button.textContent = 'Step';
     101    button.onclick = function () {
     102        self.step(currentState).then(function (state) { currentState = state; });
     103    }
     104    control.appendChild(button);
     105
     106    function callNextStep(state) {
     107        self.step(state).then(function (newState) {
     108            currentState = newState;
     109            if (newState)
     110                callNextStep(newState);
    17111        });
    18     },
    19     tests: [
    20         ['Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
    21             var todoController = contentWindow.todo.controller;
    22             for (var i = 0; i < numberOfItemsToAdd; i++) {
    23                 newTodo.value = 'Something to do ' + i;
    24                 todoController.addItem({keyCode: todoController.ENTER_KEY, target: newTodo});
    25             }
    26         }],
    27         ['CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
    28             var checkboxes = contentDocument.querySelectorAll('.toggle');
    29             for (var i = 0; i < checkboxes.length; i++)
    30                 checkboxes[i].click();
    31         }],
    32         ['DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
    33             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    34             for (var i = 0; i < deleteButtons.length; i++)
    35                 deleteButtons[i].click();
    36         }],
    37     ]
    38 });
     112    }
    39113
    40 BenchmarkRunner.suite({
    41     name: 'EmberJS/TodoMVC',
    42     url: 'todomvc/architecture-examples/emberjs/index.html',
    43     prepare: function (contentWindow, contentDocument) {
    44         contentWindow.Todos.Store = contentWindow.DS.Store.extend({
    45             revision: 12,
    46             adapter: 'Todos.LSAdapter',
    47             commit: function () { }
    48         });
     114    var button = document.createElement('button');
     115    button.textContent = 'Run';
     116    button.onclick = function () { callNextStep(currentState); }
     117    control.appendChild(button);
    49118
    50         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    51             element.focus();
    52             return {
    53                 views: contentWindow.Ember.View.views,
    54                 emberRun: contentWindow.Ember.run,
    55             }
    56         });
    57     },
    58     tests: [
    59         ['Adding' + numberOfItemsToAdd + 'Items', function (params) {
    60             for (var i = 0; i < numberOfItemsToAdd; i++) {
    61                 params.emberRun(function () { params.views["new-todo"].set('value', 'Something to do' + i); });
    62                 params.emberRun(function () { params.views["new-todo"].insertNewline(document.createEvent('Event')); });
    63             }
    64         }],
    65         ['CompletingAllItems', function (params, contentWindow, contentDocument) {
    66             var checkboxes = contentDocument.querySelectorAll('.ember-checkbox');
    67             for (var i = 0; i < checkboxes.length; i++) {
    68                 var view = params.views[checkboxes[i].id];
    69                 params.emberRun(function () { view.set('checked', true); });
    70             }
    71         }],
    72         ['DeletingItems', function (params, contentWindow, contentDocument) {
    73             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    74             for (var i = 0; i < deleteButtons.length; i++)
    75                 params.emberRun(function () { deleteButtons[i].click(); });
    76         }],
    77     ]
    78 });
    79 
    80 BenchmarkRunner.suite({
    81     name: 'BackboneJS/TodoMVC',
    82     url: 'todomvc/architecture-examples/backbone/index.html',
    83     prepare: function (contentWindow, contentDocument) {
    84     contentWindow.Backbone.sync = function () {}
    85         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    86             element.focus();
    87             return element;
    88         });
    89     },
    90     tests: [
    91         ['Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
    92             var appView = contentWindow.appView;
    93             var fakeEvent = {which: contentWindow.ENTER_KEY};
    94             for (var i = 0; i < numberOfItemsToAdd; i++) {
    95                 newTodo.value = 'Something to do ' + i;
    96                 appView.createOnEnter(fakeEvent);
    97             }
    98         }],
    99         ['CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
    100             var checkboxes = contentDocument.querySelectorAll('.toggle');
    101             for (var i = 0; i < checkboxes.length; i++)
    102                 checkboxes[i].click();
    103         }],
    104         ['DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
    105             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    106             for (var i = 0; i < deleteButtons.length; i++)
    107                 deleteButtons[i].click();
    108         }],
    109     ]
    110 });
    111 
    112 BenchmarkRunner.suite({
    113     name: 'jQuery/TodoMVC',
    114     url: 'todomvc/architecture-examples/jquery/index.html',
    115     prepare: function (contentWindow, contentDocument) {
    116         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    117             element.focus();
    118             return element;
    119         });
    120     },
    121     tests: [
    122         ['Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
    123             var app = contentWindow.app;
    124             var fakeEvent = {which: app.ENTER_KEY};
    125             for (var i = 0; i < numberOfItemsToAdd; i++) {
    126                 newTodo.value = 'Something to do ' + i;
    127                 app.create.call(newTodo, fakeEvent);
    128             }
    129         }],
    130         ['CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
    131             var app = contentWindow.app;
    132             var checkboxes = contentDocument.querySelectorAll('.toggle');
    133             var $ = contentWindow.$;
    134 
    135             itemIndexToId = new Array(checkboxes.length);
    136             for (var i = 0; i < checkboxes.length; i++)
    137                 itemIndexToId[i] = $(checkboxes[i]).closest('li').data('id');
    138 
    139             app.getTodo = function (element, callback) {
    140                 var self = this;
    141                 var id = itemIndexToId[this.currentItemIndex];
    142                 $.each(this.todos, function (j, val) {
    143                     if (val.id === id) {
    144                         callback.apply(self, arguments);
    145                         return false;
    146                     }
    147                 });
    148             }
    149 
    150             for (var i = 0; i < checkboxes.length; i++) {
    151                 app.currentItemIndex = i;
    152                 app.toggle.call(checkboxes[i]);
    153             }
    154         }],
    155         ['DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
    156             contentDocument.querySelector('#clear-completed').click();
    157             var app = contentWindow.app;
    158             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    159 
    160             for (var i = 0; i < deleteButtons.length; i++) {
    161                 app.currentItemIndex = i;
    162                 app.destroy.call(deleteButtons[i]);
    163             }
    164         }],
    165     ]
    166 });
    167 
    168 BenchmarkRunner.suite({
    169     name: 'AngularJS/TodoMVC',
    170     url: 'todomvc/architecture-examples/angularjs/index.html',
    171     prepare: function (contentWindow, contentDocument) {
    172         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    173             element.focus();
    174             return element;
    175         });
    176     },
    177     tests: [
    178         ['Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
    179             var todomvc = contentWindow.todomvc;
    180             var submitEvent = document.createEvent('Event');
    181             submitEvent.initEvent('submit', true, true);
    182             var inputEvent = document.createEvent('Event');
    183             inputEvent.initEvent('input', true, true);
    184             for (var i = 0; i < numberOfItemsToAdd; i++) {
    185                 newTodo.value = 'Something to do ' + i;
    186                 newTodo.dispatchEvent(inputEvent);
    187                 newTodo.form.dispatchEvent(submitEvent);
    188             }
    189         }],
    190         ['CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
    191             var checkboxes = contentDocument.querySelectorAll('.toggle');
    192             for (var i = 0; i < checkboxes.length; i++)
    193                 checkboxes[i].click();
    194         }],
    195         ['DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
    196             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    197             for (var i = 0; i < deleteButtons.length; i++)
    198                 deleteButtons[i].click();
    199         }],
    200     ]
    201 });
    202 
    203 BenchmarkRunner.suite({
    204     name: 'React/TodoMVC',
    205     url: 'todomvc/labs/architecture-examples/react/index.html',
    206     prepare: function (contentWindow, contentDocument) {
    207         contentWindow.Utils.store = function () {}
    208         return BenchmarkRunner.waitForElement('#new-todo').then(function (element) {
    209             element.focus();
    210             return element;
    211         });
    212     },
    213     tests: [
    214         ['Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
    215             var todomvc = contentWindow.todomvc;
    216             for (var i = 0; i < numberOfItemsToAdd; i++) {
    217                 newTodo.value = 'Something to do ' + i;
    218 
    219                 var keydownEvent = document.createEvent('Event');
    220                 keydownEvent.initEvent('keydown', true, true);
    221                 keydownEvent.which = 13; // VK_ENTER
    222                 newTodo.dispatchEvent(keydownEvent);
    223             }
    224         }],
    225         ['CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
    226             var checkboxes = contentDocument.querySelectorAll('.toggle');
    227             for (var i = 0; i < checkboxes.length; i++)
    228                 checkboxes[i].click();
    229         }],
    230         ['DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
    231             var deleteButtons = contentDocument.querySelectorAll('.destroy');
    232             for (var i = 0; i < deleteButtons.length; i++)
    233                 deleteButtons[i].click();
    234         }],
    235     ]
    236 });
    237 
    238 var actionCount = 50;
    239 BenchmarkRunner.suite({
    240     name: 'FlightJS/MailClient',
    241     url: 'flightjs-example-app/index.html',
    242     prepare: function (contentWindow, contentDocument) {
    243         return BenchmarkRunner.waitForElement('.span8').then(function (element) {
    244             element.focus();
    245             return element;
    246         });
    247     },
    248     tests: [
    249         ['OpeningTabs' + actionCount + 'Times', function (newTodo, contentWindow, contentDocument) {
    250             contentDocument.getElementById('inbox').click();
    251             for (var i = 0; i < actionCount; i++) {
    252                 contentDocument.getElementById('later').click();
    253                 contentDocument.getElementById('sent').click();
    254                 contentDocument.getElementById('trash').click();
    255                 contentDocument.getElementById('inbox').click();
    256             }
    257         }],
    258         ['MovingEmails' + actionCount + 'Times', function (newTodo, contentWindow, contentDocument) {
    259             contentDocument.getElementById('inbox').click();
    260             for (var i = 0; i < actionCount; i++) {
    261                 contentDocument.getElementById('mail_2139').click();
    262                 contentDocument.getElementById('move_mail').click();
    263                 contentDocument.querySelector('#move_to_selector #later').click();
    264                 contentDocument.getElementById('later').click();
    265                 contentDocument.getElementById('mail_2139').click();
    266                 contentDocument.getElementById('move_mail').click();
    267                 contentDocument.querySelector('#move_to_selector #trash').click();
    268                 contentDocument.getElementById('trash').click();
    269                 contentDocument.getElementById('mail_2139').click();
    270                 contentDocument.getElementById('move_mail').click();
    271                 contentDocument.querySelector('#move_to_selector #inbox').click();
    272                 contentDocument.getElementById('inbox').click();
    273             }
    274         }],
    275         ['Sending' + actionCount + 'NewEmails', function (newTodo, contentWindow, contentDocument) {
    276             for (var i = 0; i < actionCount; i++) {
    277                 contentDocument.getElementById('new_mail').click();
    278                 contentDocument.getElementById('recipient_select').selectedIndex = 1;
    279                 var subject = contentDocument.getElementById('compose_subject');
    280                 var message = contentDocument.getElementById('compose_message');
    281                 subject.focus();
    282                 contentWindow.$(subject).trigger('keydown');
    283                 contentWindow.$(subject).text('Hello');
    284                 message.focus();
    285                 contentWindow.$(message).trigger('keydown');
    286                 contentWindow.$(message).text('Hello,\n\nThis is a test message.\n\n- WebKitten');
    287                 contentDocument.getElementById('send_composed').click();
    288             }
    289         }],
    290     ]
     119    document.body.appendChild(control);
    291120});
    292121
    293122</script>
    294 </head>
    295 <body>
    296123</body>
    297124</html>
Note: See TracChangeset for help on using the changeset viewer.