]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @private\r | |
3 | */\r | |
4 | Ext.define('Ext.perf.Accumulator', function () {\r | |
5 | var currentFrame = null,\r | |
6 | khrome = Ext.global['chrome'], // jshint ignore:line\r | |
7 | formatTpl,\r | |
8 | // lazy init on first request for timestamp (avoids infobar in IE until needed)\r | |
9 | // Also avoids kicking off Chrome's microsecond timer until first needed\r | |
10 | getTimestamp = function () {\r | |
11 | getTimestamp = Ext.now;\r | |
12 | \r | |
13 | var interval, toolbox;\r | |
14 | \r | |
15 | // If Chrome is started with the --enable-benchmarking switch\r | |
16 | if (Ext.isChrome && khrome && khrome.Interval) {\r | |
17 | interval = new khrome.Interval();\r | |
18 | interval.start();\r | |
19 | getTimestamp = function () {\r | |
20 | return interval.microseconds() / 1000;\r | |
21 | };\r | |
22 | } else if (window.ActiveXObject) {\r | |
23 | try {\r | |
24 | // the above technique is not very accurate for small intervals...\r | |
25 | toolbox = new ActiveXObject('SenchaToolbox.Toolbox'); // jshint ignore:line\r | |
26 | Ext.senchaToolbox = toolbox; // export for other uses\r | |
27 | getTimestamp = function () {\r | |
28 | return toolbox.milliseconds;\r | |
29 | };\r | |
30 | } catch (e) {\r | |
31 | // ignore\r | |
32 | }\r | |
33 | }\r | |
34 | \r | |
35 | Ext.perf.getTimestamp = Ext.perf.Accumulator.getTimestamp = getTimestamp;\r | |
36 | return getTimestamp();\r | |
37 | };\r | |
38 | \r | |
39 | function adjustSet (set, time) {\r | |
40 | set.sum += time;\r | |
41 | set.min = Math.min(set.min, time);\r | |
42 | set.max = Math.max(set.max, time);\r | |
43 | }\r | |
44 | \r | |
45 | function leaveFrame (time) {\r | |
46 | var totalTime = time ? time : (getTimestamp() - this.time), // do this first\r | |
47 | me = this, // me = frame\r | |
48 | accum = me.accum;\r | |
49 | \r | |
50 | ++accum.count;\r | |
51 | if (! --accum.depth) {\r | |
52 | adjustSet(accum.total, totalTime);\r | |
53 | }\r | |
54 | adjustSet(accum.pure, totalTime - me.childTime);\r | |
55 | \r | |
56 | currentFrame = me.parent;\r | |
57 | if (currentFrame) {\r | |
58 | ++currentFrame.accum.childCount;\r | |
59 | currentFrame.childTime += totalTime;\r | |
60 | }\r | |
61 | }\r | |
62 | \r | |
63 | function makeSet () {\r | |
64 | return {\r | |
65 | min: Number.MAX_VALUE,\r | |
66 | max: 0,\r | |
67 | sum: 0\r | |
68 | };\r | |
69 | }\r | |
70 | \r | |
71 | function makeTap (me, fn) {\r | |
72 | return function () {\r | |
73 | var frame = me.enter(),\r | |
74 | ret = fn.apply(this, arguments);\r | |
75 | \r | |
76 | frame.leave();\r | |
77 | return ret;\r | |
78 | };\r | |
79 | }\r | |
80 | \r | |
81 | function setToJSON (count, childCount, calibration, set) {\r | |
82 | var data = {\r | |
83 | avg: 0,\r | |
84 | min: set.min,\r | |
85 | max: set.max,\r | |
86 | sum: 0\r | |
87 | };\r | |
88 | \r | |
89 | if (count) {\r | |
90 | calibration = calibration || 0;\r | |
91 | data.sum = set.sum - childCount * calibration;\r | |
92 | data.avg = data.sum / count;\r | |
93 | // min and max cannot be easily corrected since we don't know the number of\r | |
94 | // child calls for them.\r | |
95 | }\r | |
96 | \r | |
97 | return data;\r | |
98 | }\r | |
99 | \r | |
100 | return {\r | |
101 | requires: [\r | |
102 | 'Ext.XTemplate',\r | |
103 | 'Ext.ClassManager'\r | |
104 | ],\r | |
105 | \r | |
106 | constructor: function (name) {\r | |
107 | var me = this;\r | |
108 | \r | |
109 | me.count = me.childCount = me.depth = me.maxDepth = 0;\r | |
110 | me.pure = makeSet();\r | |
111 | me.total = makeSet();\r | |
112 | me.name = name;\r | |
113 | },\r | |
114 | \r | |
115 | statics: {\r | |
116 | getTimestamp: getTimestamp\r | |
117 | },\r | |
118 | \r | |
119 | format: function (calibration) {\r | |
120 | if (!formatTpl) {\r | |
121 | formatTpl = new Ext.XTemplate([\r | |
122 | '{name} - {count} call(s)',\r | |
123 | '<tpl if="count">',\r | |
124 | '<tpl if="childCount">',\r | |
125 | ' ({childCount} children)',\r | |
126 | '</tpl>',\r | |
127 | '<tpl if="depth - 1">',\r | |
128 | ' ({depth} deep)',\r | |
129 | '</tpl>',\r | |
130 | '<tpl for="times">',\r | |
131 | ', {type}: {[this.time(values.sum)]} msec (',\r | |
132 | //'min={[this.time(values.min)]}, ',\r | |
133 | 'avg={[this.time(values.sum / parent.count)]}',\r | |
134 | //', max={[this.time(values.max)]}',\r | |
135 | ')',\r | |
136 | '</tpl>',\r | |
137 | '</tpl>'\r | |
138 | ].join(''), {\r | |
139 | time: function (t) {\r | |
140 | return Math.round(t * 100) / 100;\r | |
141 | }\r | |
142 | });\r | |
143 | }\r | |
144 | \r | |
145 | var data = this.getData(calibration);\r | |
146 | data.name = this.name;\r | |
147 | data.pure.type = 'Pure';\r | |
148 | data.total.type = 'Total';\r | |
149 | data.times = [data.pure, data.total];\r | |
150 | return formatTpl.apply(data);\r | |
151 | },\r | |
152 | \r | |
153 | getData: function (calibration) {\r | |
154 | var me = this;\r | |
155 | \r | |
156 | return {\r | |
157 | count: me.count,\r | |
158 | childCount: me.childCount,\r | |
159 | depth: me.maxDepth,\r | |
160 | pure: setToJSON(me.count, me.childCount, calibration, me.pure),\r | |
161 | total: setToJSON(me.count, me.childCount, calibration, me.total)\r | |
162 | };\r | |
163 | },\r | |
164 | \r | |
165 | enter: function () {\r | |
166 | var me = this,\r | |
167 | frame = {\r | |
168 | accum: me,\r | |
169 | leave: leaveFrame,\r | |
170 | childTime: 0,\r | |
171 | parent: currentFrame\r | |
172 | };\r | |
173 | \r | |
174 | ++me.depth;\r | |
175 | if (me.maxDepth < me.depth) {\r | |
176 | me.maxDepth = me.depth;\r | |
177 | }\r | |
178 | \r | |
179 | currentFrame = frame;\r | |
180 | frame.time = getTimestamp(); // do this last\r | |
181 | return frame;\r | |
182 | },\r | |
183 | \r | |
184 | monitor: function (fn, scope, args) {\r | |
185 | var frame = this.enter();\r | |
186 | if (args) {\r | |
187 | fn.apply(scope, args);\r | |
188 | } else {\r | |
189 | fn.call(scope);\r | |
190 | }\r | |
191 | frame.leave();\r | |
192 | },\r | |
193 | \r | |
194 | report: function () {\r | |
195 | Ext.log(this.format());\r | |
196 | },\r | |
197 | \r | |
198 | tap: function (className, methodName) {\r | |
199 | var me = this,\r | |
200 | methods = typeof methodName === 'string' ? [methodName] : methodName,\r | |
201 | klass, statik, i, parts, length, name, src,\r | |
202 | tapFunc;\r | |
203 | \r | |
204 | tapFunc = function(){\r | |
205 | if (typeof className === 'string') {\r | |
206 | klass = Ext.global;\r | |
207 | parts = className.split('.');\r | |
208 | for (i = 0, length = parts.length; i < length; ++i) {\r | |
209 | klass = klass[parts[i]];\r | |
210 | }\r | |
211 | } else {\r | |
212 | klass = className;\r | |
213 | }\r | |
214 | \r | |
215 | for (i = 0, length = methods.length; i < length; ++i) {\r | |
216 | name = methods[i];\r | |
217 | statik = name.charAt(0) === '!';\r | |
218 | \r | |
219 | if (statik) {\r | |
220 | name = name.substring(1);\r | |
221 | } else {\r | |
222 | statik = !(name in klass.prototype);\r | |
223 | }\r | |
224 | \r | |
225 | src = statik ? klass : klass.prototype;\r | |
226 | src[name] = makeTap(me, src[name]);\r | |
227 | }\r | |
228 | };\r | |
229 | \r | |
230 | Ext.ClassManager.onCreated(tapFunc, me, className);\r | |
231 | \r | |
232 | return me;\r | |
233 | }\r | |
234 | };\r | |
235 | },\r | |
236 | function () {\r | |
237 | Ext.perf.getTimestamp = this.getTimestamp;\r | |
238 | });\r |