/**
* @singleton
* @private
*/
Ext.define('Ext.perf.Monitor', {
singleton: true,
alternateClassName: 'Ext.Perf',
requires: [
'Ext.perf.Accumulator'
],
constructor: function() {
this.accumulators = [];
this.accumulatorsByName = {};
},
calibrate: function() {
var accum = new Ext.perf.Accumulator('$'),
total = accum.total,
getTimestamp = Ext.perf.Accumulator.getTimestamp,
count = 0,
frame,
endTime,
startTime;
startTime = getTimestamp();
do {
frame = accum.enter();
frame.leave();
++count;
} while (total.sum < 100);
endTime = getTimestamp();
return (endTime - startTime) / count;
},
get: function(name) {
var me = this,
accum = me.accumulatorsByName[name];
if (!accum) {
me.accumulatorsByName[name] = accum = new Ext.perf.Accumulator(name);
me.accumulators.push(accum);
}
return accum;
},
enter: function(name) {
return this.get(name).enter();
},
monitor: function(name, fn, scope) {
this.get(name).monitor(fn, scope);
},
report: function() {
var me = this,
accumulators = me.accumulators,
calibration = me.calibrate();
accumulators.sort(function(a, b) {
return (a.name < b.name) ? -1 : ((b.name < a.name) ? 1 : 0);
});
me.updateGC();
Ext.log('Calibration: ' + Math.round(calibration * 100) / 100 + ' msec/sample');
Ext.each(accumulators, function(accum) {
Ext.log(accum.format(calibration));
});
},
getData: function(all) {
var ret = {},
accumulators = this.accumulators;
Ext.each(accumulators, function(accum) {
if (all || accum.count) {
ret[accum.name] = accum.getData();
}
});
return ret;
},
reset: function() {
Ext.each(this.accumulators, function(accum) {
var me = accum;
me.count = me.childCount = me.depth = me.maxDepth = 0;
me.pure = {
min: Number.MAX_VALUE,
max: 0,
sum: 0
};
me.total = {
min: Number.MAX_VALUE,
max: 0,
sum: 0
};
});
},
updateGC: function() {
var accumGC = this.accumulatorsByName.GC,
toolbox = Ext.senchaToolbox,
bucket;
if (accumGC) {
accumGC.count = toolbox.garbageCollectionCounter || 0;
if (accumGC.count) {
bucket = accumGC.pure;
accumGC.total.sum = bucket.sum = toolbox.garbageCollectionMilliseconds;
bucket.min = bucket.max = bucket.sum / accumGC.count;
bucket = accumGC.total;
bucket.min = bucket.max = bucket.sum / accumGC.count;
}
}
},
watchGC: function() {
var toolbox = Ext.senchaToolbox;
Ext.perf.getTimestamp(); // initializes SenchaToolbox (if available)
if (toolbox) {
this.get("GC");
toolbox.watchGarbageCollector(false); // no logging, just totals
}
},
setup: function(config) {
var key, prop,
accum, className, methods;
if (!config) {
config = {
/* insertHtml: {
'Ext.dom.Helper': 'insertHtml'
}, */
/* xtplCompile: {
'Ext.XTemplateCompiler': 'compile'
}, */
// doInsert: {
// 'Ext.Template': 'doInsert'
// },
// applyOut: {
// 'Ext.XTemplate': 'applyOut'
// },
render: {
'Ext.Component': 'render'
},
// fnishRender: {
// 'Ext.Component': 'finishRender'
// },
// renderSelectors: {
// 'Ext.Component': 'applyRenderSelectors'
// },
// compAddCls: {
// 'Ext.Component': 'addCls'
// },
// compRemoveCls: {
// 'Ext.Component': 'removeCls'
// },
// getStyle: {
// 'Ext.core.Element': 'getStyle'
// },
// setStyle: {
// 'Ext.core.Element': 'setStyle'
// },
// addCls: {
// 'Ext.core.Element': 'addCls'
// },
// removeCls: {
// 'Ext.core.Element': 'removeCls'
// },
// measure: {
// 'Ext.layout.component.Component': 'measureAutoDimensions'
// },
// moveItem: {
// 'Ext.layout.Layout': 'moveItem'
// },
// layoutFlush: {
// 'Ext.layout.Context': 'flush'
// },
layout: {
'Ext.layout.Context': 'run'
}
};
}
this.currentConfig = config;
for (key in config) {
if (config.hasOwnProperty(key)) {
prop = config[key];
accum = Ext.Perf.get(key);
for (className in prop) {
if (prop.hasOwnProperty(className)) {
methods = prop[className];
accum.tap(className, methods);
}
}
}
}
this.watchGC();
},
// This is a quick hack for now
setupLog: function(config) {
var className, cls, methods, method, override;
for (className in config) {
if (config.hasOwnProperty(className)) {
cls = Ext.ClassManager.get(className);
if (cls) {
methods = config[className];
override = {};
for (method in methods) {
override[method] = (function(methodName, idProp) {
return function() {
var before, diff, id, idHolder, ret;
before = +Date.now();
ret = this.callParent(arguments);
diff = +Date.now() - before;
if (window.console && diff > 0) {
/* eslint-disable multiline-ternary, no-multi-spaces, indent */
idHolder = idProp === 'this' ? this
: typeof idProp === 'string' ? this[idProp]
: typeof idProp === 'number' ? arguments[idProp]
: null
;
/* eslint-enable */
if (idHolder) {
id = idHolder.id;
}
if (id != null) {
console.log(methodName + ' for ' + id + ': ' + diff + 'ms');
}
else {
console.log(methodName + ' for unknown: ' + diff + 'ms');
}
if (console.trace) {
console.trace();
}
}
return ret;
};
})(method, methods[method]);
}
Ext.override(cls, override);
}
}
}
}
});