/** * @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 () { Ext.perf.getTimestamp(); // initializes SenchaToolbox (if available) var toolbox = Ext.senchaToolbox; if (toolbox) { this.get("GC"); toolbox.watchGarbageCollector(false); // no logging, just totals } }, setup: function (config) { 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; var key, prop, accum, className, methods; 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) { idHolder = idProp === 'this' ? this : typeof idProp === 'string' ? this[idProp] : typeof idProp === 'number' ? arguments[idProp] : null ; 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); } } } }});