/** * @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); } } } }});