2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
7 YAHOO.namespace("tool");
10 * The YUI JavaScript profiler.
12 * @namespace YAHOO.tool
17 * Profiles functions in JavaScript.
18 * @namespace YAHOO.tool
22 YAHOO.tool.Profiler = {
24 //-------------------------------------------------------------------------
26 //-------------------------------------------------------------------------
29 * Container object on which to put the original unprofiled methods.
33 * @property _container
35 _container : new Object(),
38 * Call information for functions.
44 _report : new Object(),
46 //-------------------------------------------------------------------------
48 //-------------------------------------------------------------------------
51 * Called when a method ends execution. Marks the start and end time of the
52 * method so it can calculate how long the function took to execute. Also
53 * updates min/max/avg calculations for the function.
54 * @param {String} name The name of the function to mark as stopped.
55 * @param {int} duration The number of milliseconds it took the function to
61 _saveData : function (name /*:String*/, duration /*:int*/){
63 //get the function data
64 var functionData /*:Object*/ = this._report[name];
68 functionData.points.push(duration);
70 //if it's already been called at least once, do more complex calculations
71 if (functionData.calls > 1) {
72 functionData.avg = ((functionData.avg*(functionData.calls-1))+duration)/functionData.calls;
73 functionData.min = Math.min(functionData.min, duration);
74 functionData.max = Math.max(functionData.max, duration);
76 functionData.avg = duration;
77 functionData.min = duration;
78 functionData.max = duration;
83 //-------------------------------------------------------------------------
85 //-------------------------------------------------------------------------
88 * Returns the average amount of time (in milliseconds) that the function
89 * with the given name takes to execute.
90 * @param {String} name The name of the function whose data should be returned.
91 * If an object type method, it should be 'constructor.prototype.methodName';
92 * a normal object method would just be 'object.methodName'.
93 * @return {float} The average time it takes the function to execute.
96 getAverage : function (name /*:String*/) /*:float*/ {
97 return this._report[name].avg;
101 * Returns the number of times that the given function has been called.
102 * @param {String} name The name of the function whose data should be returned.
103 * @return {int} The number of times the function was called.
106 getCallCount : function (name /*:String*/) /*:int*/ {
107 return this._report[name].calls;
111 * Returns the maximum amount of time (in milliseconds) that the function
112 * with the given name takes to execute.
113 * @param {String} name The name of the function whose data should be returned.
114 * If an object type method, it should be 'constructor.prototype.methodName';
115 * a normal object method would just be 'object.methodName'.
116 * @return {float} The maximum time it takes the function to execute.
118 getMax : function (name /*:String*/) /*:int*/ {
119 return this._report[name].max;
123 * Returns the minimum amount of time (in milliseconds) that the function
124 * with the given name takes to execute.
125 * @param {String} name The name of the function whose data should be returned.
126 * If an object type method, it should be 'constructor.prototype.methodName';
127 * a normal object method would just be 'object.methodName'.
128 * @return {float} The minimum time it takes the function to execute.
130 getMin : function (name /*:String*/) /*:int*/ {
131 return this._report[name].min;
135 * Returns an object containing profiling data for a single function.
136 * The object has an entry for min, max, avg, calls, and points).
137 * @return {Object} An object containing profile data for a given function.
140 getFunctionReport : function (name /*:String*/) /*:Object*/ {
141 return this._report[name];
145 * Returns an object containing profiling data for all of the functions
146 * that were profiled. The object has an entry for each function and
147 * returns all information (min, max, average, calls, etc.) for each
149 * @return {Object} An object containing all profile data.
152 getFullReport : function (filter /*:Function*/) /*:Object*/ {
153 filter = filter || function(){return true;};
155 if (YAHOO.lang.isFunction(filter)) {
158 for (var name in this._report){
159 if (filter(this._report[name])){
160 report[name] = this._report[name];
168 //-------------------------------------------------------------------------
170 //-------------------------------------------------------------------------
173 * Sets up a constructor for profiling, including all properties and methods on the prototype.
174 * @param {string} name The fully-qualified name of the function including namespace information.
175 * @param {Object} owner (Optional) The object that owns the function (namespace or containing object).
179 registerConstructor : function (name /*:String*/, owner /*:Object*/) /*:Void*/ {
180 this.registerFunction(name, owner, true);
184 * Sets up a function for profiling. It essentially overwrites the function with one
185 * that has instrumentation data. This method also creates an entry for the function
186 * in the profile report. The original function is stored on the _container object.
187 * @param {String} name The full name of the function including namespacing. This
188 * is the name of the function that is stored in the report.
189 * @param {Object} owner (Optional) The object that owns the function. If the function
190 * isn't global then this argument is required. This could be the namespace that
191 * the function belongs to, such as YAHOO.util.Dom, or the object on which it's
194 * @method registerFunction
196 registerFunction : function(name /*:String*/, owner /*:Object*/, registerPrototype /*:Boolean*/) /*:Void*/{
198 //figure out the function name without namespacing
199 var funcName /*:String*/ = (name.indexOf(".") > -1 ? name.substring(name.lastIndexOf(".")+1) : name);
200 if (!YAHOO.lang.isObject(owner)){
201 owner = eval(name.substring(0, name.lastIndexOf(".")));
204 //get the method and prototype
205 var method /*:Function*/ = owner[funcName];
206 var prototype /*:Object*/ = method.prototype;
208 //see if the method has already been registered
209 if (YAHOO.lang.isFunction(method) && !method.__yuiProfiled){
211 //create a new slot for the original method
212 this._container[name] = method;
214 //replace the function with the profiling one
215 owner[funcName] = function () {
217 var start = new Date();
218 var retval = method.apply(this, arguments);
219 var stop = new Date();
221 YAHOO.tool.Profiler._saveData(name, stop-start);
227 //copy the function properties over
228 YAHOO.lang.augmentObject(owner[funcName], method);
229 owner[funcName].__yuiProfiled = true;
230 owner[funcName].prototype = prototype;
231 this._container[name].__yuiOwner = owner;
232 this._container[name].__yuiFuncName = funcName;
234 //register prototype if necessary
235 if (registerPrototype) {
236 this.registerObject(name + ".prototype", prototype);
239 //store function information
240 this._report[name] = {
255 * Sets up an object for profiling. It takes the object and looks for functions.
256 * When a function is found, registerMethod() is called on it. If set to recrusive
257 * mode, it will also setup objects found inside of this object for profiling,
258 * using the same methodology.
259 * @param {String} name The name of the object to profile (shows up in report).
260 * @param {Object} owner (Optional) The object represented by the name.
261 * @param {Boolean} recurse (Optional) Determines if subobject methods are also profiled.
265 registerObject : function (name /*:String*/, object /*:Object*/, recurse /*:Boolean*/) /*:Void*/{
268 object = (YAHOO.lang.isObject(object) ? object : eval(name));
271 this._container[name] = object;
273 for (var prop in object) {
274 if (typeof object[prop] == "function"){
275 if (prop != "constructor" && prop != "superclass"){ //don't do constructor or superclass, it's recursive
276 this.registerFunction(name + "." + prop, object);
278 } else if (typeof object[prop] == "object" && recurse){
279 this.registerObject(name + "." + prop, object[prop], recurse);
286 * Removes a constructor function from profiling. Reverses the registerConstructor() method.
287 * @param {String} name The full name of the function including namespacing. This
288 * is the name of the function that is stored in the report.
290 * @method unregisterFunction
292 unregisterConstructor : function(name /*:String*/) /*:Void*/{
294 //see if the method has been registered
295 if (YAHOO.lang.isFunction(this._container[name])){
298 //var owner /*:Object*/ = this._container[name].__yuiOwner;
299 //var funcName /*:String*/ = this._container[name].__yuiFuncName;
300 //delete this._container[name].__yuiOwner;
301 //delete this._container[name].__yuiFuncName;
303 //replace instrumented function
304 //owner[funcName] = this._container[name];
305 //delete this._container[name];
306 this.unregisterFunction(name, true);
314 * Removes function from profiling. Reverses the registerFunction() method.
315 * @param {String} name The full name of the function including namespacing. This
316 * is the name of the function that is stored in the report.
318 * @method unregisterFunction
320 unregisterFunction : function(name /*:String*/, unregisterPrototype /*:Boolean*/) /*:Void*/{
322 //see if the method has been registered
323 if (YAHOO.lang.isFunction(this._container[name])){
325 //check to see if you should unregister the prototype
326 if (unregisterPrototype){
327 this.unregisterObject(name + ".prototype", this._container[name].prototype);
331 var owner /*:Object*/ = this._container[name].__yuiOwner;
332 var funcName /*:String*/ = this._container[name].__yuiFuncName;
333 delete this._container[name].__yuiOwner;
334 delete this._container[name].__yuiFuncName;
336 //replace instrumented function
337 owner[funcName] = this._container[name];
339 //delete supporting information
340 delete this._container[name];
341 delete this._report[name];
349 * Unregisters an object for profiling. It takes the object and looks for functions.
350 * When a function is found, unregisterMethod() is called on it. If set to recrusive
351 * mode, it will also unregister objects found inside of this object,
352 * using the same methodology.
353 * @param {String} name The name of the object to unregister.
354 * @param {Boolean} recurse (Optional) Determines if subobject methods should also be
359 unregisterObject : function (name /*:String*/, recurse /*:Boolean*/) /*:Void*/{
362 if (YAHOO.lang.isObject(this._container[name])){
363 var object = this._container[name];
365 for (var prop in object) {
366 if (typeof object[prop] == "function"){
367 this.unregisterFunction(name + "." + prop);
368 } else if (typeof object[prop] == "object" && recurse){
369 this.unregisterObject(name + "." + prop, recurse);
373 delete this._container[name];
380 YAHOO.register("profiler", YAHOO.tool.Profiler, {version: "2.7.0", build: "1799"});