diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index bfa0720fd71..a871e06ad30 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -6,6 +6,7 @@ import _ from 'lodash'; import angular from 'angular'; import $ from 'jquery'; import coreModule from 'app/core/core_module'; +import {profiler} from 'app/core/profiler'; export class GrafanaCtrl { @@ -15,14 +16,10 @@ export class GrafanaCtrl { $scope.init = function() { $scope.contextSrv = contextSrv; + $rootScope.appSubUrl = config.appSubUrl; $scope._ = _; - $rootScope.profilingEnabled = store.getBool('profilingEnabled') || config.buildInfo.env === 'development'; - $rootScope.performance = { loadStart: new Date().getTime() }; - $rootScope.appSubUrl = config.appSubUrl; - - if ($rootScope.profilingEnabled) { $scope.initProfiling(); } - + profiler.init(config, $rootScope); alertSrv.init(); utilSrv.init(); @@ -59,82 +56,6 @@ export class GrafanaCtrl { "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" ]; - $scope.getTotalWatcherCount = function() { - var count = 0; - var scopes = 0; - var root = $(document.getElementsByTagName('body')); - - var f = function (element) { - if (element.data().hasOwnProperty('$scope')) { - scopes++; - angular.forEach(element.data().$scope.$$watchers, function () { - count++; - }); - } - - angular.forEach(element.children(), function (childElement) { - f($(childElement)); - }); - }; - - f(root); - $rootScope.performance.scopeCount = scopes; - return count; - }; - - $scope.initProfiling = function() { - var count = 0; - - $scope.$watch(function digestCounter() { - count++; - }, function() { - // something - }); - - $rootScope.performance.panels = []; - - $scope.$on('refresh', function() { - if ($rootScope.performance.panels.length > 0) { - var totalRender = 0; - var totalQuery = 0; - - _.each($rootScope.performance.panels, function(panelTiming: any) { - totalRender += panelTiming.render; - totalQuery += panelTiming.query; - }); - - console.log('total query: ' + totalQuery); - console.log('total render: ' + totalRender); - console.log('avg render: ' + totalRender / $rootScope.performance.panels.length); - } - - $rootScope.performance.panels = []; - }); - - $scope.onAppEvent('dashboard-loaded', function() { - count = 0; - - setTimeout(function() { - console.log("Dashboard::Performance Total Digests: " + count); - console.log("Dashboard::Performance Total Watchers: " + $scope.getTotalWatcherCount()); - console.log("Dashboard::Performance Total ScopeCount: " + $rootScope.performance.scopeCount); - - var timeTaken = $rootScope.performance.allPanelsInitialized - $rootScope.performance.dashboardLoadStart; - console.log("Dashboard::Performance - All panels initialized in " + timeTaken + " ms"); - - // measure digest performance - var rootDigestStart = window.performance.now(); - for (var i = 0; i < 30; i++) { - $rootScope.$apply(); - } - console.log("Dashboard::Performance Root Digest " + ((window.performance.now() - rootDigestStart) / 30)); - - }, 3000); - - }); - - }; - $scope.init(); } } diff --git a/public/app/core/profiler.ts b/public/app/core/profiler.ts new file mode 100644 index 00000000000..0a0d611ac55 --- /dev/null +++ b/public/app/core/profiler.ts @@ -0,0 +1,132 @@ +/// +// +import $ from 'jquery'; +import _ from 'lodash'; +import angular from 'angular'; + +export class Profiler { + panelsRendered: number; + enabled: boolean; + panels: any[]; + panelsInitCount: any; + timings: any; + digestCounter: any; + $rootScope: any; + scopeCount: any; + + init(config, $rootScope) { + this.enabled = config.buildInfo.env === 'development'; + this.timings = {}; + this.timings.appStart = { loadStart: new Date().getTime() }; + this.$rootScope = $rootScope; + + if (!this.enabled) { + return; + } + + $rootScope.$watch(() => { + this.digestCounter++; + return false; + }, () => {}); + + $rootScope.$on('refresh', this.refresh.bind(this)); + $rootScope.onAppEvent('dashboard-fetched', this.dashboardFetched.bind(this)); + $rootScope.onAppEvent('dashboard-initialized', this.dashboardInitialized.bind(this)); + $rootScope.onAppEvent('panel-initialized', this.panelInitialized.bind(this)); + } + + refresh() { + if (this.panels.length > 0) { + var totalRender = 0; + var totalQuery = 0; + + for (let panelTiming of this.panels) { + totalRender += panelTiming.render; + totalQuery += panelTiming.query; + } + + console.log('panel count: ' + this.panels.length); + console.log('total query: ' + totalQuery); + console.log('total render: ' + totalRender); + console.log('avg render: ' + totalRender / this.panels.length); + } + this.$rootScope.panels = []; + } + + dashboardFetched() { + this.timings.dashboardLoadStart = new Date().getTime(); + this.panelsInitCount = 0; + this.digestCounter = 0; + this.panelsInitCount = 0; + this.panelsRendered = 0; + this.panels = []; + } + + dashboardInitialized() { + setTimeout(() => { + console.log("Dashboard::Performance Total Digests: " + this.digestCounter); + console.log("Dashboard::Performance Total Watchers: " + this.getTotalWatcherCount()); + console.log("Dashboard::Performance Total ScopeCount: " + this.scopeCount); + + var timeTaken = this.timings.lastPanelInitializedAt - this.timings.dashboardLoadStart; + console.log("Dashboard::Performance All panels initialized in " + timeTaken + " ms"); + + // measure digest performance + var rootDigestStart = window.performance.now(); + for (var i = 0; i < 30; i++) { + this.$rootScope.$apply(); + } + + console.log("Dashboard::Performance Root Digest " + ((window.performance.now() - rootDigestStart) / 30)); + }, 3000); + } + + getTotalWatcherCount() { + var count = 0; + var scopes = 0; + var root = $(document.getElementsByTagName('body')); + + var f = function (element) { + if (element.data().hasOwnProperty('$scope')) { + scopes++; + angular.forEach(element.data().$scope.$$watchers, function () { + count++; + }); + } + + angular.forEach(element.children(), function (childElement) { + f($(childElement)); + }); + }; + + f(root); + this.scopeCount = scopes; + return count; + } + + renderingCompleted(panelId, panelTimings) { + this.panelsRendered++; + + if (this.enabled) { + panelTimings.renderEnd = new Date().getTime(); + this.panels.push({ + panelId: panelId, + query: panelTimings.queryEnd - panelTimings.queryStart, + render: panelTimings.renderEnd - panelTimings.renderStart, + }); + } + } + + panelInitialized() { + if (!this.enabled) { + return; + } + + this.panelsInitCount++; + this.timings.lastPanelInitializedAt = new Date().getTime(); + } + +} + +var profiler = new Profiler(); +export {profiler}; diff --git a/public/app/features/annotations/annotations_srv.js b/public/app/features/annotations/annotations_srv.js index a693dd602c8..8f84a6ba905 100644 --- a/public/app/features/annotations/annotations_srv.js +++ b/public/app/features/annotations/annotations_srv.js @@ -14,7 +14,7 @@ define([ this.init = function() { $rootScope.onAppEvent('refresh', this.clearCache, $rootScope); - $rootScope.onAppEvent('dashboard-loaded', this.clearCache, $rootScope); + $rootScope.onAppEvent('dashboard-initialized', this.clearCache, $rootScope); }; this.clearCache = function() { diff --git a/public/app/features/dashboard/dashboardCtrl.js b/public/app/features/dashboard/dashboardCtrl.js index 9f3e6da998f..0a9c0fd7e92 100644 --- a/public/app/features/dashboard/dashboardCtrl.js +++ b/public/app/features/dashboard/dashboardCtrl.js @@ -35,10 +35,6 @@ function (angular, $, config, moment) { }; $scope.setupDashboard = function(data) { - $rootScope.performance.dashboardLoadStart = new Date().getTime(); - $rootScope.performance.panelsInitialized = 0; - $rootScope.performance.panelsRendered = 0; - var dashboard = dashboardSrv.create(data.dashboard, data.meta); dashboardSrv.setCurrent(dashboard); @@ -68,7 +64,7 @@ function (angular, $, config, moment) { }); } - $scope.appEvent("dashboard-loaded", $scope.dashboard); + $scope.appEvent("dashboard-initialized", $scope.dashboard); }).catch(function(err) { if (err.data && err.data.message) { err.message = err.data.message; } $scope.appEvent("alert-error", ['Dashboard init failed', 'Template variables could not be initialized: ' + err.message]); @@ -84,7 +80,6 @@ function (angular, $, config, moment) { }; $scope.broadcastRefresh = function() { - $rootScope.performance.panelsRendered = 0; $rootScope.$broadcast('refresh'); }; diff --git a/public/app/features/dashboard/dashboardLoaderSrv.js b/public/app/features/dashboard/dashboardLoaderSrv.js index 1af0894b462..70c49967ea5 100644 --- a/public/app/features/dashboard/dashboardLoaderSrv.js +++ b/public/app/features/dashboard/dashboardLoaderSrv.js @@ -47,6 +47,8 @@ function (angular, moment, _, $, kbn, dateMath, impressionStore) { } promise.then(function(result) { + $rootScope.appEvent("dashboard-fetched", result.dashboard); + if (result.meta.dashboardNotFound !== true) { impressionStore.impressions.addDashboardImpression(result.dashboard.id); } diff --git a/public/app/features/dashboard/viewStateSrv.js b/public/app/features/dashboard/viewStateSrv.js index ba820e86a92..035bfb6ae6e 100644 --- a/public/app/features/dashboard/viewStateSrv.js +++ b/public/app/features/dashboard/viewStateSrv.js @@ -51,13 +51,6 @@ function (angular, _, $) { $scope.onAppEvent('panel-initialized', function(evt, payload) { self.registerPanel(payload.scope); - - if ($scope.profilingEnabled) { - $scope.performance.panelsInitialized++; - if ($scope.performance.panelsInitialized === $scope.performance.panelCount) { - $scope.performance.allPanelsInitialized = new Date().getTime(); - } - } }); this.update(this.getQueryStringState()); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index df44559595b..0f253b5048a 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -4,6 +4,7 @@ import config from 'app/core/config'; import _ from 'lodash'; import angular from 'angular'; import $ from 'jquery'; +import {profiler} from 'app/core/profiler'; const TITLE_HEIGHT = 25; const EMPTY_TITLE_HEIGHT = 9; @@ -59,21 +60,7 @@ export class PanelCtrl { } renderingCompleted() { - this.$scope.$root.performance.panelsRendered++; - this.timing.renderEnd = new Date().getTime(); - if (this.$scope.$root.profilingEnabled) { - this.$scope.$root.performance.panels.push({ - panelId: this.panel.id, - query: this.timing.queryEnd - this.timing.queryStart, - render: this.timing.renderEnd - this.timing.renderStart, - }); - - if (this.$scope.$root.performance.panelsRendered === this.$scope.$root.performance.panelCount) { - this.$scope.$root.performance.allPanelsRendered = new Date().getTime(); - var timeTaken = this.$scope.$root.performance.allPanelsRendered - this.$scope.$root.performance.dashboardLoadStart; - console.log("Dashboard::Performance - All panels rendered in " + timeTaken + " ms"); - } - } + profiler.renderingCompleted(this.panel.id, this.timing); } refresh() { diff --git a/public/app/features/panel/solo_panel_ctrl.js b/public/app/features/panel/solo_panel_ctrl.js index 355d5e8b265..0eb271675ee 100644 --- a/public/app/features/panel/solo_panel_ctrl.js +++ b/public/app/features/panel/solo_panel_ctrl.js @@ -25,7 +25,7 @@ function (angular, $) { $scope.initDashboard(result, $scope); }); - $scope.onAppEvent("dashboard-loaded", $scope.initPanelScope); + $scope.onAppEvent("dashboard-initialized", $scope.initPanelScope); }; $scope.initPanelScope = function() { diff --git a/public/test/specs/dashboardViewStateSrv-specs.js b/public/test/specs/dashboardViewStateSrv-specs.js index 202a43670b1..90e35810ac0 100644 --- a/public/test/specs/dashboardViewStateSrv-specs.js +++ b/public/test/specs/dashboardViewStateSrv-specs.js @@ -31,7 +31,7 @@ define([ it('should update querystring and view state', function() { var updateState = {fullscreen: true, edit: true, panelId: 1}; viewState.update(updateState); - expect(location.search()).to.eql({fullscreen: true, edit: true, panelId: 1, org: 19}); + expect(location.search()).to.eql({fullscreen: true, edit: true, panelId: 1}); expect(viewState.dashboard.meta.fullscreen).to.be(true); expect(viewState.state.fullscreen).to.be(true); }); @@ -41,7 +41,6 @@ define([ it('should remove params from query string', function() { viewState.update({fullscreen: true, panelId: 1, edit: true}); viewState.update({fullscreen: false}); - expect(location.search()).to.eql({org: 19}); expect(viewState.dashboard.meta.fullscreen).to.be(false); expect(viewState.state.fullscreen).to.be(null); });