Browse Source

feat(profiling): refactorign profiling code, #5286

Torkel Ödegaard 9 years ago
parent
commit
c739428c30

+ 3 - 82
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;
 
-      $scope._ = _;
-
-      $rootScope.profilingEnabled = store.getBool('profilingEnabled') || config.buildInfo.env === 'development';
-      $rootScope.performance = { loadStart: new Date().getTime() };
       $rootScope.appSubUrl = config.appSubUrl;
+      $scope._ = _;
 
-      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();
   }
 }

+ 132 - 0
public/app/core/profiler.ts

@@ -0,0 +1,132 @@
+///<reference path="../headers/common.d.ts" />
+//
+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};

+ 1 - 1
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() {

+ 1 - 6
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');
     };
 

+ 2 - 0
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);
         }

+ 0 - 7
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());

+ 2 - 15
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() {

+ 1 - 1
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() {

+ 1 - 2
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);
       });