diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html new file mode 100644 index 0000000000..76536555f5 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html @@ -0,0 +1,21 @@ + + + + + + + diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js new file mode 100644 index 0000000000..c7180a74e0 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js @@ -0,0 +1,95 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function() { + 'use strict'; + + var APP_STARTED = 'App Started'; + var PAGE_LOADED = 'Page Loaded'; + var TIMING_EVENT = 'timing-report'; + var DEFAULT_CATEGORY = 'UI Latency'; + var DEFAULT_TYPE = 'timing'; + + Polymer({ + is: 'gr-reporting', + + properties: { + _baselines: { + type: Array, + value: function() { return {}; }, + } + }, + + get performanceTiming() { + return window.performance.timing; + }, + + now: function() { + return Math.round(10 * window.performance.now()) / 10; + }, + + reporter: function(type, category, eventName, eventValue) { + eventValue = eventValue; + var detail = { + type: type, + category: category, + name: eventName, + value: eventValue, + }; + document.dispatchEvent( + new CustomEvent(TIMING_EVENT, {detail: detail})); + console.log(eventName + ': ' + eventValue); + }, + + /** + * User-perceived app start time, should be reported when the app is ready. + */ + appStarted: function() { + var startTime = + new Date().getTime() - this.performanceTiming.navigationStart; + this.reporter( + DEFAULT_TYPE, DEFAULT_CATEGORY, APP_STARTED, startTime); + }, + + /** + * Page load time, should be reported at any time after navigation. + */ + pageLoaded: function() { + if (this.performanceTiming.loadEventEnd === 0) { + console.error('pageLoaded should be called after window.onload'); + this.async(this.pageLoaded, 100); + } else { + var loadTime = this.performanceTiming.loadEventEnd - + this.performanceTiming.navigationStart; + this.reporter(DEFAULT_TYPE, DEFAULT_CATEGORY, PAGE_LOADED, loadTime); + } + }, + + /** + * Reset named timer. + */ + time: function(name) { + this._baselines[name] = this.now(); + }, + + /** + * Finish named timer and report it to server. + */ + timeEnd: function(name) { + var baseTime = this._baselines[name] || 0; + var time = this.now() - baseTime; + this.reporter(DEFAULT_TYPE, DEFAULT_CATEGORY, name, time); + delete this._baselines[name]; + }, + }); +})(); diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html new file mode 100644 index 0000000000..e9226b8865 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html @@ -0,0 +1,93 @@ + + + + +gr-reporting + + + + + + + + + + + diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js index d11d438266..8441372426 100644 --- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js +++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js @@ -18,8 +18,12 @@ // custom element having the id "app", but it is made explicit here. var app = document.querySelector('#app'); var restAPI = document.createElement('gr-rest-api-interface'); + var reporting = document.createElement('gr-reporting'); window.addEventListener('WebComponentsReady', function() { + reporting.timeEnd('WebComponentsReady'); + reporting.pageLoaded(); + // Middleware page(function(ctx, next) { document.body.scrollTop = 0; diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html index ec19a2df45..18c06025f8 100644 --- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html +++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html @@ -14,10 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> + + @@ -111,17 +114,19 @@ limitations under the License. this._clearDiffContent(); - console.time(TimingLabel.TOTAL); - console.time(TimingLabel.CONTENT); + var reporting = this.$.reporting; + + reporting.time(TimingLabel.TOTAL); + reporting.time(TimingLabel.CONTENT); return this.$.processor.process(this.diff.content).then(function() { if (this.isImageDiff) { this._builder.renderDiffImages(); } - console.timeEnd(TimingLabel.CONTENT); - console.time(TimingLabel.SYNTAX); + reporting.timeEnd(TimingLabel.CONTENT); + reporting.time(TimingLabel.SYNTAX); this.$.syntaxLayer.process().then(function() { - console.timeEnd(TimingLabel.SYNTAX); - console.timeEnd(TimingLabel.TOTAL); + reporting.timeEnd(TimingLabel.SYNTAX); + reporting.timeEnd(TimingLabel.TOTAL); }); this.fire('render'); }.bind(this)); diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html index e8b14530e2..187a5cd5da 100644 --- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html +++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html @@ -437,6 +437,10 @@ limitations under the License. ] }, ]; + stub('gr-reporting', { + time: sinon.stub(), + timeEnd: sinon.stub(), + }); element = fixture('basic'); outputEl = element.queryEffectiveChildren('#diffTable'); element.addEventListener('render', function() { @@ -458,6 +462,20 @@ limitations under the License. element.render({left: [], right: []}, prefs); }); + test('reporting', function(done) { + var timeStub = element.$.reporting.time; + var timeEndStub = element.$.reporting.timeEnd; + flush(function() { + assert.isTrue(timeStub.calledWithExactly('Diff Total Render')); + assert.isTrue(timeStub.calledWithExactly('Diff Content Render')); + assert.isTrue(timeStub.calledWithExactly('Diff Syntax Render')); + assert.isTrue(timeEndStub.calledWithExactly('Diff Total Render')); + assert.isTrue(timeEndStub.calledWithExactly('Diff Content Render')); + assert.isTrue(timeEndStub.calledWithExactly('Diff Syntax Render')); + done(); + }); + }); + test('renderSection', function() { var section = outputEl.querySelector('stub:nth-of-type(2)'); var prevInnerHTML = section.innerHTML; diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html index c20795b49e..25dfaffbb1 100644 --- a/polygerrit-ui/app/elements/gr-app.html +++ b/polygerrit-ui/app/elements/gr-app.html @@ -22,6 +22,7 @@ limitations under the License. + @@ -136,6 +137,7 @@ limitations under the License. + diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js index 0833a725a2..f24ecfdf1d 100644 --- a/polygerrit-ui/app/elements/gr-app.js +++ b/polygerrit-ui/app/elements/gr-app.js @@ -72,6 +72,7 @@ }, ready: function() { + this.$.reporting.appStarted(); this._viewState = { changeView: { changeNum: null, diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html new file mode 100644 index 0000000000..ca26ed01a0 --- /dev/null +++ b/polygerrit-ui/app/elements/gr-app_test.html @@ -0,0 +1,53 @@ + + + + +gr-app + + + + + + + + + + + diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html index d3cb316630..2714f48374 100644 --- a/polygerrit-ui/app/test/index.html +++ b/polygerrit-ui/app/test/index.html @@ -49,8 +49,8 @@ limitations under the License. 'diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html', 'diff/gr-diff-comment/gr-diff-comment_test.html', 'diff/gr-diff-cursor/gr-diff-cursor_test.html', - 'diff/gr-diff-highlight/gr-diff-highlight_test.html', 'diff/gr-diff-highlight/gr-annotation_test.html', + 'diff/gr-diff-highlight/gr-diff-highlight_test.html', 'diff/gr-diff-preferences/gr-diff-preferences_test.html', 'diff/gr-diff-processor/gr-diff-processor_test.html', 'diff/gr-diff-selection/gr-diff-selection_test.html', @@ -61,6 +61,7 @@ limitations under the License. 'diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html', 'diff/gr-selection-action-box/gr-selection-action-box_test.html', 'diff/gr-syntax-layer/gr-syntax-layer_test.html', + 'gr-app_test.html', 'settings/gr-account-info/gr-account-info_test.html', 'settings/gr-email-editor/gr-email-editor_test.html', 'settings/gr-group-list/gr-group-list_test.html', @@ -69,10 +70,10 @@ limitations under the License. 'settings/gr-settings-view/gr-settings-view_test.html', 'settings/gr-ssh-editor/gr-ssh-editor_test.html', 'settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html', - 'shared/gr-autocomplete/gr-autocomplete_test.html', 'shared/gr-account-label/gr-account-label_test.html', 'shared/gr-account-link/gr-account-link_test.html', 'shared/gr-alert/gr-alert_test.html', + 'shared/gr-autocomplete/gr-autocomplete_test.html', 'shared/gr-avatar/gr-avatar_test.html', 'shared/gr-change-star/gr-change-star_test.html', 'shared/gr-confirm-dialog/gr-confirm-dialog_test.html',