Make the analysis page more useful
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Apr 2015 21:04:22 +0000 (21:04 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Apr 2015 21:04:22 +0000 (21:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143617

Reviewed by Chris Dumez.

* public/api/analysis-tasks.php:
(fetch_and_push_bugs_to_tasks): Added total and finished numbers of build requests associated
with the fetched analysis tasks as buildRequestCount and finishedBuildRequestCount respectively.
* public/v2/analysis.js:
(App.AnalysisTask.formattedCreatedAt): Added.
(App.AnalysisTask._addLeadingZero): Added.
(App.AnalysisTask.buildRequestCount): Added.
(App.AnalysisTask.finishedBuildRequestCount): Added.
(App.AnalysisTask.statusLabel): Added. Status total and finished numbers of build requests.
(App.AnalysisTask.testGroups):
(App.AnalysisTask.triggerable):
(App.AnalysisTask.label):

* public/v2/app.css: Tweaked style rules for the analysis page.

* public/v2/app.js:
(App.buildPopup): Sort the list of platforms by name.
(App.AnalysisRoute.model): Sort the list of analysis tasks by the order they are created.
(App.AnalysisTaskController._fetchedManifest): Added elementId to associate bug tracker names
such as "Bugzilla" with the corresponding text field.

* public/v2/index.html: Added a bunch of columns to the analysis page and also wrapped the table
showing A/B testing results in a div with overflow: scroll so that it always leaves enough space
for the accompanying graph.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182641 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/public/api/analysis-tasks.php
Websites/perf.webkit.org/public/v2/analysis.js
Websites/perf.webkit.org/public/v2/app.css
Websites/perf.webkit.org/public/v2/app.js
Websites/perf.webkit.org/public/v2/index.html

index 2d39a7c..eaab4e6 100644 (file)
@@ -1,3 +1,35 @@
+2015-04-10  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Make the analysis page more useful
+        https://bugs.webkit.org/show_bug.cgi?id=143617
+
+        Reviewed by Chris Dumez.
+
+        * public/api/analysis-tasks.php:
+        (fetch_and_push_bugs_to_tasks): Added total and finished numbers of build requests associated
+        with the fetched analysis tasks as buildRequestCount and finishedBuildRequestCount respectively.
+        * public/v2/analysis.js:
+        (App.AnalysisTask.formattedCreatedAt): Added.
+        (App.AnalysisTask._addLeadingZero): Added.
+        (App.AnalysisTask.buildRequestCount): Added.
+        (App.AnalysisTask.finishedBuildRequestCount): Added.
+        (App.AnalysisTask.statusLabel): Added. Status total and finished numbers of build requests.
+        (App.AnalysisTask.testGroups):
+        (App.AnalysisTask.triggerable):
+        (App.AnalysisTask.label):
+
+        * public/v2/app.css: Tweaked style rules for the analysis page.
+
+        * public/v2/app.js:
+        (App.buildPopup): Sort the list of platforms by name.
+        (App.AnalysisRoute.model): Sort the list of analysis tasks by the order they are created.
+        (App.AnalysisTaskController._fetchedManifest): Added elementId to associate bug tracker names
+        such as "Bugzilla" with the corresponding text field.
+
+        * public/v2/index.html: Added a bunch of columns to the analysis page and also wrapped the table
+        showing A/B testing results in a div with overflow: scroll so that it always leaves enough space
+        for the accompanying graph.
+
 2015-04-09  Ryosuke Niwa  <rniwa@webkit.org>
 
         Perf dashboard should automatically select ranges for A/B testing
index 1967b62..a31b067 100644 (file)
@@ -57,6 +57,22 @@ function fetch_and_push_bugs_to_tasks($db, &$tasks) {
         array_push($associated_task['bugs'], $bug['id']);
     }
 
+    $task_build_counts = $db->query_and_fetch_all('SELECT
+        testgroup_task AS "task",
+        count(testgroup_id) as "total",
+        sum(case when request_status = \'failed\' or request_status = \'completed\' then 1 else 0 end) as "finished"
+        FROM analysis_test_groups, build_requests
+        WHERE request_group = testgroup_id AND testgroup_task = ANY($1) GROUP BY testgroup_task',
+        array('{' . implode(', ', $task_ids) . '}'));
+    if (!is_array($task_build_counts))
+        exit_with_error('FailedToFetchTestGroups');
+
+    foreach ($task_build_counts as $build_count) {
+        $task = &$task_by_id[$build_count['task']];
+        $task['buildRequestCount'] = $build_count['total'];
+        $task['finishedBuildRequestCount'] = $build_count['finished'];
+    }
+
     return $bugs;
 }
 
index f3f3578..99a2907 100644 (file)
@@ -1,15 +1,33 @@
 App.AnalysisTask = App.NameLabelModel.extend({
     author: DS.attr('string'),
     createdAt: DS.attr('date'),
+    formattedCreatedAt: function () {
+        var format = d3.time.format("%Y-%m-%d");
+        return format(this.get('createdAt'));
+    }.property('createdAt'),
     platform: DS.belongsTo('platform'),
     metric: DS.belongsTo('metric'),
     startRun: DS.attr('number'),
     endRun: DS.attr('number'),
     bugs: DS.hasMany('bugs'),
-    testGroups: function (key, value, oldValue) {
+    buildRequestCount: DS.attr('number'),
+    finishedBuildRequestCount: DS.attr('number'),
+    statusLabel: function ()
+    {
+        var total = this.get('buildRequestCount');
+        var finished = this.get('finishedBuildRequestCount');
+        if (!total)
+            return 'Empty';
+        if (total != finished)
+            return finished + ' out of ' + total;
+        return 'Done';
+    }.property('buildRequestCount', 'finishedBuildRequestCount'),
+    testGroups: function (key, value, oldValue)
+    {
         return this.store.find('testGroup', {task: this.get('id')});
     }.property(),
-    triggerable: function () {
+    triggerable: function ()
+    {
         return this.store.find('triggerable', {task: this.get('id')}).then(function (triggerables) {
             return triggerables.objectAt(0);
         }, function (error) {
@@ -17,7 +35,8 @@ App.AnalysisTask = App.NameLabelModel.extend({
             return null;
         });
     }.property(),
-    label: function () {
+    label: function ()
+    {
         var label = this.get('name');
         var bugs = this.get('bugs').map(function (bug) { return bug.get('label'); }).join(' / ');
         return bugs ? label + ' (' + bugs + ')' : label;
index b2c11dd..5a46f81 100755 (executable)
@@ -88,6 +88,7 @@ body {
 
 .popup li .label {
     display: block;
+    font-size: 0.8rem;
     max-width: 15rem;
     text-overflow: ellipsis;
     overflow: hidden;
@@ -437,45 +438,55 @@ form .analysis-group > * {
 }
 
 #analysis-tasks,
-.analysis-group table {
+.analysis-group table {
     border: solid 0px #999;
     border-collapse: collapse;
 }
 
 #analysis-tasks thead,
-.analysis-group table thead {
+.analysis-group table thead {
     color: #c93;
 }
 
 #analysis-tasks th,
-.analysis-group table th {
+.analysis-group table th {
     font-weight: normal;
 }
 
 #analysis-tasks td,
 #analysis-tasks th,
-.analysis-group table td,
-.analysis-group table th {
+.analysis-group table td,
+.analysis-group table th {
     padding: 0.2rem 0.5rem;
 }
 
+#analysis-tasks .status,
+#analysis-tasks .author,
+#analysis-tasks .created-at,
+#analysis-tasks .platform-name {
+    white-space: nowrap;
+}
+
+#analysis-tasks .test-name {
+}
+
 #analysis-tasks tbody td,
 #analysis-tasks tbody th,
-.analysis-group table tbody td,
-.analysis-group table tbody th {
+.analysis-group table tbody td,
+.analysis-group table tbody th {
     border-top: solid 1px #ddd;
 }
 
-.analysis-group .results .summary td {
+.analysis-group table .summary td {
     vertical-align: top;
 }
 
-.analysis-group .results thead td {
+.analysis-group table thead td {
     text-align: center;
 }
 
-.analysis-group .results .config-letter,
-.analysis-group .results .summary {
+.analysis-group table .config-letter,
+.analysis-group table .summary {
     cursor: pointer;
 }
 
@@ -487,9 +498,10 @@ form .analysis-group > * {
     display: none;
 }
 
-.analysis-group .results {
+.analysis-group .table-container {
     margin: 0.5rem;
-    margin-right: 20rem;
+    margin-right: 19rem;
+    overflow: scroll;
 }
 
 .analysis-group .reference-chart {
index 5ba08e6..d2787fa 100755 (executable)
@@ -911,7 +911,7 @@ App.ChartsController = Ember.Controller.extend({
 App.buildPopup = function(store, action, position)
 {
     return App.Manifest.fetch(store).then(function () {
-        return App.Manifest.get('platforms').map(function (platform) {
+        return App.Manifest.get('platforms').sortBy('label').map(function (platform) {
             return App.PlatformProxyForPopup.create({content: platform,
                 action: action, position: position});
         });
@@ -1126,7 +1126,7 @@ App.PaneController = Ember.ObjectController.extend({
 App.AnalysisRoute = Ember.Route.extend({
     model: function () {
         return this.store.findAll('analysisTask').then(function (tasks) {
-            return Ember.Object.create({'tasks': tasks});
+            return Ember.Object.create({'tasks': tasks.sortBy('createdAt').toArray().reverse()});
         });
     },
 });
@@ -1174,6 +1174,7 @@ App.AnalysisTaskController = Ember.Controller.extend({
         this.set('bugTrackers', App.Manifest.get('bugTrackers').map(function (bugTracker) {
             var bugNumber = trackerIdToBugNumber[bugTracker.get('id')];
             return Ember.ObjectProxy.create({
+                elementId: 'bug-' + bugTracker.get('id'),
                 content: bugTracker,
                 bugNumber: bugNumber,
                 editedBugNumber: bugNumber,
index 5bb63f1..bc800a7 100755 (executable)
         <table id="analysis-tasks">
             <thead>
                 <tr>
-                    <td>ID</td>
                     <td>Name</td>
+                    <td>Status</td>
+                    <td>Author</td>
                     <td>Created at</td>
+                    <td>Platform</td>
+                    <td>Test</td>
                 </tr>
             </thead>
             <tbody>
                 {{#each model.tasks}}
                     <tr>
-                        <td>{{#link-to 'analysisTask' id}}{{id}}{{/link-to}}</td>
-                        <td>{{name}}</td>
-                        <td>{{createdAt}}</td>
+                        <td class="task-name">{{#link-to 'analysisTask' id}}{{name}}{{/link-to}}</td>
+                        <td class="status">{{statusLabel}}</td>
+                        <td class="author">{{author}}</td>
+                        <td class="created-at">{{formattedCreatedAt}}</td>
+                        <td class="platform-name">{{platform.label}}</td>
+                        <td class="test-name">{{metric.fullName}}</td>
                     </tr>
                 {{/each}}
             </tbody>
                             <tbody>
                                 {{#each bugTrackers}}
                                     <tr>
-                                        <th>{{label}}</th>
+                                        <th><label {{bind-attr for=elementId}}>{{label}}</label></th>
                                         <td>
                                             <form {{action "associateBug" this editedBugNumber on="submit"}}>
-                                                {{input type=text value=editedBugNumber}}
+                                                {{input id=elementId type=text value=editedBugNumber}}
                                             </form>
                                         </td>
                                     </tr>
     <script type="text/x-handlebars" data-template-name="testGroup">
         <section class="analysis-group">
             <h1>{{name}}</h1>
-            <table class="results">
-                <thead>
-                    <tr>
-                        <td colspan="2">Configuration</td>
-                        {{#each repositories}}
-                            <td>{{name}}</td>
-                        {{/each}}
-                        <td>Results</td>
-                        <td>Status</td>
-                    </tr>
-                </thead>
-                {{#each configurations}}
-                    <tbody {{bind-attr class="showRequestList::hideRequests"}}>
-                        <tr class="summary" {{action toggleShowRequestList this}}>
-                            <td class="config-letter" colspan="2">{{summary.configLetter}}</td>
-                            {{#with summary}}
-                                {{partial "testGroupRow"}}
-                            {{/with}}
+            <div class="table-container">
+                <table class="results">
+                    <thead>
+                        <tr>
+                            <td colspan="2">Configuration</td>
+                            {{#each repositories}}
+                                <td>{{name}}</td>
+                            {{/each}}
+                            <td>Results</td>
+                            <td>Status</td>
                         </tr>
-                        {{#each requests}}
-                            <tr class="request">
+                    </thead>
+                    {{#each configurations}}
+                        <tbody {{bind-attr class="showRequestList::hideRequests"}}>
+                            <tr class="summary" {{action toggleShowRequestList this}}>
+                                <td class="config-letter" colspan="2">{{summary.configLetter}}</td>
+                                {{#with summary}}
+                                    {{partial "testGroupRow"}}
+                                {{/with}}
+                            </tr>
+                            {{#each requests}}
+                                <tr class="request">
+                                    {{#with ../this}}
+                                        <td class="config-letter" {{action toggleShowRequestList this}}></td>
+                                    {{/with}}
+                                    <td>Run {{orderLabel}}</td>
+                                    {{partial "testGroupRow"}}
+                                </tr>
+                            {{/each}}
+                        </tbody>
+                    {{/each}}
+                    {{#each comparisons}}
+                        <tbody>
+                            <tr>
+                                <td colspan="2">{{label}}</td>
                                 {{#with ../this}}
-                                    <td class="config-letter" {{action toggleShowRequestList this}}></td>
+                                    {{#each repositories}}
+                                        <td></td>
+                                    {{/each}}
                                 {{/with}}
-                                <td>Run {{orderLabel}}</td>
-                                {{partial "testGroupRow"}}
+                                <td colspan="2">{{result}}</td>
                             </tr>
-                        {{/each}}
-                    </tbody>
-                {{/each}}
-                {{#each comparisons}}
-                    <tbody>
-                        <tr>
-                            <td colspan="2">{{label}}</td>
-                            {{#with ../this}}
-                                {{#each repositories}}
-                                    <td></td>
-                                {{/each}}
-                            {{/with}}
-                            <td colspan="2">{{result}}</td>
-                        </tr>
-                    </tbody>
-                {{/each}}
-            </table>
+                        </tbody>
+                    {{/each}}
+                </table>
+            </div>
             <div class="reference-chart">
                 {{#if referenceChart}}
                     {{interactive-chart