Skip to content

Commit

Permalink
finished refactor of instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
btford committed Nov 14, 2012
1 parent d8aa313 commit bd61693
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 111 deletions.
27 changes: 1 addition & 26 deletions js/controllers/PerfCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,8 @@ panelApp.controller('PerfCtrl', function PerfCtrl($scope, appContext, filesystem
appContext.inspect(this.val.id);
};

var updateHistogram = function () {
var info = appContext.getHistogram();
if (!info) {
return;
}
var total = 0;
info.forEach(function (elt) {
total += elt.time;
});
var i, elt, his;
for (i = 0; (i < $scope.histogram.length && i < info.length); i++) {
elt = info[i];
his = $scope.histogram[i];
his.time = elt.time.toPrecision(3);
his.percent = (100 * elt.time / total).toPrecision(3);
}
for ( ; i < info.length; i++) {
elt = info[i];
elt.time = elt.time.toPrecision(3);
elt.percent = (100 * elt.time / total).toPrecision(3);
$scope.histogram.push(elt);
}
$scope.histogram.length = info.length;
};

var updateTree = function () {
$scope.histogram = appContext.getHistogram();
var roots = appContext.getListOfRoots();
if (!roots) {
return;
Expand All @@ -86,5 +62,4 @@ panelApp.controller('PerfCtrl', function PerfCtrl($scope, appContext, filesystem
}
};
appContext.watchPoll(updateTree);
appContext.watchPoll(updateHistogram);
});
6 changes: 6 additions & 0 deletions js/filters/precision.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// returns the number's first 4 decimals
panelApp.filter('precision', function () {
return function (input, output) {
return input.toPrecision(4);
};
});
191 changes: 115 additions & 76 deletions js/inject/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,23 @@ var inject = function () {
return;
}

// Helpers
// =======

// polyfill for performance.now on older webkit
if (!performance.now) {
performance.now = performance.webkitNow;
}

// Helpers
// =======

// Based on cycle.js
// 2011-08-24
// https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

// Make a deep copy of an object or array, assuring that there is at most
// one instance of each object or array in the resulting structure. The
// duplicate references (which might be forming cycles) are replaced with
// an object of the form
// {$ref: PATH}
// where the PATH is a JSONPath string that locates the first occurance.
// where the PATH is a JSONPath string that locates the first occurrence.
var decycle = function (object) {
var objects = [], // Keep a reference to each unique object or array
paths = []; // Keep the path to each unique object or array
Expand Down Expand Up @@ -112,9 +111,8 @@ var inject = function () {
// End
// ===

// Instrumentation
// ---------------

// given a scope object, return an object with deep clones
// of the models exposed on that scope
var getScopeLocals = function (scope) {
var scopeLocals = {}, prop;
for (prop in scope) {
Expand All @@ -125,16 +123,73 @@ var inject = function () {
return scopeLocals;
};

//var bootstrap = window.angular.bootstrap;
var debug = window.__ngDebug = {
watchers: {}, // map of scopes --> watchers
// helper to extract dependencies from function arguments
// not all versions of AngularJS expose annotate
var annotate = angular.injector().annotate;
if (!annotate) {
annotate = (function () {

watchPerf: {}, // maps of watch/apply exp/fns to perf data
applyPerf: {},
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

scopes: {}, // map of scope.$ids --> model objects
rootScopes: {}, // map of $ids --> refs to root scopes
rootScopeDirty: {},
// TODO: should I keep these assertions?
function assertArg(arg, name, reason) {
if (!arg) {
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
}
return arg;
}
function assertArgFn(arg, name, acceptArrayAnnotation) {
if (acceptArrayAnnotation && angular.isArray(arg)) {
arg = arg[arg.length - 1];
}

assertArg(angular.isFunction(arg), name, 'not a function, got ' +
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
return arg;
}

return function (fn) {
var $inject,
fnText,
argDecl,
last;

if (typeof fn == 'function') {
if (!($inject = fn.$inject)) {
$inject = [];
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
});
});
fn.$inject = $inject;
}
} else if (angular.isArray(fn)) {
last = fn.length - 1;
assertArgFn(fn[last], 'fn');
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
};
}());
}


// Public API
// ==========

var api = window.__ngDebug = {

getDeps: function () {
return debug.deps;
},

getRootScopeIds: function () {
var ids = [];
Expand All @@ -143,6 +198,7 @@ var inject = function () {
});
return ids;
},

getScopeTree: function (id) {
if (debug.rootScopeDirty[id] === false) {
return;
Expand Down Expand Up @@ -174,6 +230,20 @@ var inject = function () {
return tree;
},

getWatchPerf: function () {
var changes = [];
angular.forEach(debug.watchPerf, function (info, name) {
if (info.time > 0) {
changes.push({
name: name,
time: info.time
});
info.time = 0;
}
});
return changes;
},

getWatchTree: function (id) {
var traverse = function (sc) {
var tree = {
Expand All @@ -196,68 +266,37 @@ var inject = function () {
var tree = traverse(root);

return tree;
},

deps: []
}
};

var annotate = angular.injector().annotate;

// not all versions of AngularJS expose annotate
if (!annotate) {
annotate = (function () {
// Private state
// =============

var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
//var bootstrap = window.angular.bootstrap;
var debug = {
// map of scopes --> watcher function name strings
watchers: {},

// TODO: should I keep these assertions?
function assertArg(arg, name, reason) {
if (!arg) {
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
}
return arg;
}
function assertArgFn(arg, name, acceptArrayAnnotation) {
if (acceptArrayAnnotation && angular.isArray(arg)) {
arg = arg[arg.length - 1];
}
// maps of watch/apply exp/fns to perf data
watchPerf: {},
applyPerf: {},

assertArg(angular.isFunction(arg), name, 'not a function, got ' +
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
return arg;
}
// map of scope.$ids --> model objects
scopes: {},

return function (fn) {
var $inject,
fnText,
argDecl,
last;
// map of $ids --> refs to root scopes
rootScopes: {},

if (typeof fn == 'function') {
if (!($inject = fn.$inject)) {
$inject = [];
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
});
});
fn.$inject = $inject;
}
} else if (angular.isArray(fn)) {
last = fn.length - 1;
assertArgFn(fn[last], 'fn');
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
};
}());
}
// map of $ids --> bools
rootScopeDirty: {},

deps: []
};


// Instrumentation
// ===============

var ng = angular.module('ng');
ng.config(function ($provide) {
Expand Down Expand Up @@ -327,7 +366,6 @@ var inject = function () {

// patch watchExpression
// ---------------------

var w = watchExpression;
if (typeof w === 'function') {
watchExpression = function () {
Expand Down Expand Up @@ -378,9 +416,8 @@ var inject = function () {
};


// patch destroy
// -------------

// patch $destroy
// --------------
var _destroy = $delegate.__proto__.$destroy;
$delegate.__proto__.$destroy = function () {
if (debug.watchers[this.$id]) {
Expand All @@ -392,6 +429,8 @@ var inject = function () {
return _destroy.apply(this, arguments);
};

// patch $new
// ----------
var _new = $delegate.__proto__.$new;
$delegate.__proto__.$new = function () {

Expand All @@ -410,8 +449,8 @@ var inject = function () {
return ret;
};

// patch apply
// -----------
// patch $apply
// ------------
var _apply = $delegate.__proto__.$apply;
$delegate.__proto__.$apply = function (fn) {
var start = performance.now();
Expand Down
Loading

0 comments on commit bd61693

Please sign in to comment.