]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/profiler/profiler.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / profiler / profiler.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('profiler', function(Y) {
9
10     /**
11      * The YUI JavaScript profiler.
12      * @module profiler
13      * @requires yui
14      */
15      
16     //-------------------------------------------------------------------------
17     // Private Variables and Functions
18     //-------------------------------------------------------------------------
19     
20     var container   = {},   //Container object on which to put the original unprofiled methods.
21         report      = {},   //Profiling information for functions
22         stopwatches = {},   //Additional stopwatch information
23         
24         WATCH_STARTED   = 0,
25         WATCH_STOPPED   = 1,
26         WATCH_PAUSED    = 2,    
27         
28         //shortcuts
29         L   = Y.Lang;
30
31     /* (intentionally not documented)
32      * Creates a report object with the given name.
33      * @param {String} name The name to store for the report object.
34      * @return {Void}
35      * @method createReport
36      * @private
37      */
38     function createReport(name){
39         report[name] = {
40             calls: 0,
41             max: 0,
42             min: 0,
43             avg: 0,
44             points: []
45         };
46         return report[name];
47     }
48     
49     /* (intentionally not documented)
50      * Called when a method ends execution. Marks the start and end time of the 
51      * method so it can calculate how long the function took to execute. Also 
52      * updates min/max/avg calculations for the function.
53      * @param {String} name The name of the function to mark as stopped.
54      * @param {int} duration The number of milliseconds it took the function to
55      *      execute.
56      * @return {Void}
57      * @method saveDataPoint
58      * @private
59      * @static
60      */
61     function saveDataPoint(name, duration){
62
63         //get the function data
64         var functionData /*:Object*/ = report[name];
65         
66         //just in case clear() was called
67         if (!functionData){
68             functionData = createReport(name);
69         }
70     
71         //increment the calls
72         functionData.calls++;
73         functionData.points.push(duration);
74
75         //if it's already been called at least once, do more complex calculations
76         if (functionData.calls > 1) {
77             functionData.avg = ((functionData.avg*(functionData.calls-1))+duration)/functionData.calls;
78             functionData.min = Math.min(functionData.min, duration);
79             functionData.max = Math.max(functionData.max, duration);
80         } else {
81             functionData.avg = duration;
82             functionData.min = duration;
83             functionData.max = duration;
84         }                             
85     
86     }
87     
88     //-------------------------------------------------------------------------
89     // Public Interface
90     //-------------------------------------------------------------------------
91     
92     /**
93      * Profiles functions in JavaScript.
94      * @class Profiler
95      * @static
96      */
97     Y.Profiler = {
98     
99         //-------------------------------------------------------------------------
100         // Utility Methods
101         //-------------------------------------------------------------------------        
102         
103         /**
104          * Removes all report data from the profiler.
105          * @param {String} name (Optional) The name of the report to clear. If
106          *      omitted, then all report data is cleared.
107          * @return {Void}
108          * @method clear
109          * @static
110          */
111         clear: function(name){
112             if (L.isString(name)){
113                 delete report[name];
114                 delete stopwatches[name];
115             } else {
116                 report = {};
117                 stopwatches = {};
118             }
119         },
120
121         /**
122          * Returns the uninstrumented version of a function/object.
123          * @param {String} name The name of the function/object to retrieve.
124          * @return {Function|Object} The uninstrumented version of a function/object.
125          * @method getOriginal
126          * @static
127          */    
128         getOriginal: function(name){
129             return container[name];
130         },
131     
132         /**
133          * Instruments a method to have profiling calls.
134          * @param {String} name The name of the report for the function.
135          * @param {Function} method The function to instrument.
136          * @return {Function} An instrumented version of the function.
137          * @method instrument
138          * @static
139          */
140         instrument: function(name, method){
141         
142             //create instrumented version of function
143             var newMethod = function () {
144     
145                 var start = new Date(),
146                     retval = method.apply(this, arguments),
147                     stop = new Date();
148                 
149                 saveDataPoint(name, stop-start);
150                 
151                 return retval;                
152             
153             };     
154
155             //copy the function properties over
156             Y.mix(newMethod, method);
157             
158             //assign prototype and flag as being profiled
159             newMethod.__yuiProfiled = true;
160             newMethod.prototype = method.prototype;
161             
162             //store original method
163             container[name] = method;
164             container[name].__yuiFuncName = name;
165             
166             //create the report
167             createReport(name);
168
169             //return the new method
170             return newMethod;
171         },    
172         
173         //-------------------------------------------------------------------------
174         // Stopwatch Methods
175         //-------------------------------------------------------------------------        
176         
177         /**
178          * Pauses profiling information for a given name.
179          * @param {String} name The name of the data point.
180          * @return {Void}
181          * @method pause
182          * @static
183          */        
184         pause: function(name){
185             var now = new Date(),
186                 stopwatch = stopwatches[name];
187                 
188             if (stopwatch && stopwatch.state == WATCH_STARTED){
189                 stopwatch.total += (now - stopwatch.start);
190                 stopwatch.start = 0;
191                 stopwatch.state = WATCH_PAUSED;
192             }
193         
194         },
195         
196         /**
197          * Start profiling information for a given name. The name cannot be the name
198          * of a registered function or object. This is used to start timing for a
199          * particular block of code rather than instrumenting the entire function.
200          * @param {String} name The name of the data point.
201          * @return {Void}
202          * @method start
203          * @static
204          */
205         start: function(name){
206             if(container[name]){
207                 throw new Error("Cannot use '" + name + "' for profiling through start(), name is already in use.");
208             } else {
209             
210                 //create report if necessary
211                 if (!report[name]){
212                     createReport(name);
213                 }
214                 
215                 //create stopwatch object if necessary
216                 if (!stopwatches[name]){             
217                     stopwatches[name] = {
218                         state: WATCH_STOPPED,
219                         start: 0,
220                         total: 0
221                     };
222                 }
223                 
224                 if (stopwatches[name].state == WATCH_STOPPED){
225                     stopwatches[name].state = WATCH_STARTED;
226                     stopwatches[name].start = new Date();                    
227                 }
228
229             }
230         },
231         
232         /**
233          * Stops profiling information for a given name.
234          * @param {String} name The name of the data point.
235          * @return {Void}
236          * @method stop
237          * @static
238          */
239         stop: function(name){
240             var now = new Date(),
241                 stopwatch = stopwatches[name];
242                 
243             if (stopwatch){
244                 if (stopwatch.state == WATCH_STARTED){
245                     saveDataPoint(name, stopwatch.total + (now - stopwatch.start));                    
246                 } else if (stopwatch.state == WATCH_PAUSED){
247                     saveDataPoint(name, stopwatch.total);
248                 }
249                 
250                 //reset stopwatch information
251                 stopwatch.start = 0;
252                 stopwatch.total = 0;
253                 stopwatch.state = WATCH_STOPPED;                
254             }
255         },
256     
257         //-------------------------------------------------------------------------
258         // Reporting Methods
259         //-------------------------------------------------------------------------    
260         
261         /**
262          * Returns the average amount of time (in milliseconds) that the function
263          * with the given name takes to execute.
264          * @param {String} name The name of the function whose data should be returned.
265          *      If an object type method, it should be 'constructor.prototype.methodName';
266          *      a normal object method would just be 'object.methodName'.
267          * @return {float} The average time it takes the function to execute.
268          * @method getAverage
269          * @static
270          */
271         getAverage : function (name /*:String*/) /*:float*/ {
272             return report[name].avg;
273         },
274     
275         /**
276          * Returns the number of times that the given function has been called.
277          * @param {String} name The name of the function whose data should be returned.
278          * @return {int} The number of times the function was called.
279          * @method getCallCount
280          * @static
281          */
282         getCallCount : function (name /*:String*/) /*:int*/ {
283             return report[name].calls;    
284         },
285         
286         /**
287          * Returns the maximum amount of time (in milliseconds) that the function
288          * with the given name takes to execute.
289          * @param {String} name The name of the function whose data should be returned.
290          *      If an object type method, it should be 'constructor.prototype.methodName';
291          *      a normal object method would just be 'object.methodName'.
292          * @return {float} The maximum time it takes the function to execute.
293          * @method getMax
294          * @static
295          */
296         getMax : function (name /*:String*/) /*:int*/ {
297             return report[name].max;
298         },
299         
300         /**
301          * Returns the minimum amount of time (in milliseconds) that the function
302          * with the given name takes to execute.
303          * @param {String} name The name of the function whose data should be returned.
304          *      If an object type method, it should be 'constructor.prototype.methodName';
305          *      a normal object method would just be 'object.methodName'.
306          * @return {float} The minimum time it takes the function to execute.
307          * @method getMin
308          * @static
309          */
310         getMin : function (name /*:String*/) /*:int*/ {
311             return report[name].min;
312         },
313     
314         /**
315          * Returns an object containing profiling data for a single function.
316          * The object has an entry for min, max, avg, calls, and points).
317          * @return {Object} An object containing profile data for a given function.
318          * @method getFunctionReport
319          * @static
320          * @deprecated Use getReport() instead.
321          */
322         getFunctionReport : function (name /*:String*/) /*:Object*/ {
323             return report[name];
324         },
325     
326         /**
327          * Returns an object containing profiling data for a single function.
328          * The object has an entry for min, max, avg, calls, and points).
329          * @return {Object} An object containing profile data for a given function.
330          * @method getReport
331          * @static
332          */
333         getReport : function (name /*:String*/) /*:Object*/ {
334             return report[name];
335         },
336     
337         /**
338          * Returns an object containing profiling data for all of the functions 
339          * that were profiled. The object has an entry for each function and 
340          * returns all information (min, max, average, calls, etc.) for each
341          * function.
342          * @return {Object} An object containing all profile data.
343          * @static
344          */
345         getFullReport : function (filter /*:Function*/) /*:Object*/ {
346             filter = filter || function(){return true;};
347         
348             if (L.isFunction(filter)) {
349                 var fullReport = {};
350                 
351                 for (var name in report){
352                     if (filter(report[name])){
353                         fullReport[name] = report[name];    
354                     }
355                 }
356                 
357                 return fullReport;
358             }
359         },
360     
361         //-------------------------------------------------------------------------
362         // Profiling Methods
363         //-------------------------------------------------------------------------   
364         
365         /**
366          * Sets up a constructor for profiling, including all properties and methods on the prototype.
367          * @param {string} name The fully-qualified name of the function including namespace information.
368          * @param {Object} owner (Optional) The object that owns the function (namespace or containing object).
369          * @return {Void}
370          * @method registerConstructor
371          * @static
372          */
373         registerConstructor : function (name /*:String*/, owner /*:Object*/) /*:Void*/ {    
374             this.registerFunction(name, owner, true);
375         },
376     
377         /**
378          * Sets up a function for profiling. It essentially overwrites the function with one
379          * that has instrumentation data. This method also creates an entry for the function
380          * in the profile report. The original function is stored on the container object.
381          * @param {String} name The full name of the function including namespacing. This
382          *      is the name of the function that is stored in the report.
383          * @param {Object} owner (Optional) The object that owns the function. If the function
384          *      isn't global then this argument is required. This could be the namespace that
385          *      the function belongs to or the object on which it's
386          *      a method.
387          * @param {Boolean} registerPrototype (Optional) Indicates that the prototype should
388          *      also be instrumented. Setting to true has the same effect as calling
389          *      registerConstructor().
390          * @return {Void}
391          * @method registerFunction
392          * @static
393          */     
394         registerFunction : function(name /*:String*/, owner /*:Object*/, registerPrototype /*:Boolean*/) /*:Void*/{
395         
396             //figure out the function name without namespacing
397             var funcName = (name.indexOf(".") > -1 ? 
398                     name.substring(name.lastIndexOf(".")+1) : name),
399                 method,
400                 prototype;
401                 
402             //if owner isn't an object, try to find it from the name
403             if (!L.isObject(owner)){
404                 owner = eval(name.substring(0, name.lastIndexOf(".")));
405             }
406             
407             //get the method and prototype
408             method = owner[funcName];
409             prototype = method.prototype;
410             
411             //see if the method has already been registered
412             if (L.isFunction(method) && !method.__yuiProfiled){
413                 
414                 //replace the function with the profiling one
415                 owner[funcName] = this.instrument(name, method);
416                         
417                 /*
418                  * Store original function information. We store the actual
419                  * function as well as the owner and the name used to identify
420                  * the function so it can be restored later.
421                  */
422                 container[name].__yuiOwner = owner;
423                 container[name].__yuiFuncName = funcName;  //overwrite with less-specific name
424                  
425                 //register prototype if necessary
426                 if (registerPrototype) {            
427                     this.registerObject(name + ".prototype", prototype);          
428                 }
429     
430             }
431         
432         },
433             
434         
435         /**
436          * Sets up an object for profiling. It takes the object and looks for functions.
437          * When a function is found, registerMethod() is called on it. If set to recrusive
438          * mode, it will also setup objects found inside of this object for profiling, 
439          * using the same methodology.
440          * @param {String} name The name of the object to profile (shows up in report).
441          * @param {Object} owner (Optional) The object represented by the name.
442          * @param {Boolean} recurse (Optional) Determines if subobject methods are also profiled.
443          * @return {Void}
444          * @method registerObject
445          * @static
446          */
447         registerObject : function (name /*:String*/, object /*:Object*/, recurse /*:Boolean*/) /*:Void*/{
448         
449             //get the object
450             object = (L.isObject(object) ? object : eval(name));
451         
452             //save the object
453             container[name] = object;
454         
455             for (var prop in object) {
456                 if (typeof object[prop] == "function"){
457                     if (prop != "constructor" && prop != "superclass"){ //don't do constructor or superclass, it's recursive
458                         this.registerFunction(name + "." + prop, object);
459                     }
460                 } else if (typeof object[prop] == "object" && recurse){
461                     this.registerObject(name + "." + prop, object[prop], recurse);
462                 }
463             }
464         
465         },    
466         
467         /**
468          * Removes a constructor function from profiling. Reverses the registerConstructor() method.
469          * @param {String} name The full name of the function including namespacing. This
470          *      is the name of the function that is stored in the report.
471          * @return {Void}
472          * @method unregisterFunction
473          * @static
474          */     
475         unregisterConstructor : function(name /*:String*/) /*:Void*/{
476                 
477             //see if the method has been registered
478             if (L.isFunction(container[name])){
479                 this.unregisterFunction(name, true);
480             }    
481         },
482         
483         /**
484          * Removes function from profiling. Reverses the registerFunction() method.
485          * @param {String} name The full name of the function including namespacing. This
486          *      is the name of the function that is stored in the report.
487          * @return {Void}
488          * @method unregisterFunction
489          * @static
490          */     
491         unregisterFunction : function(name /*:String*/, unregisterPrototype /*:Boolean*/) /*:Void*/{
492                 
493             //see if the method has been registered
494             if (L.isFunction(container[name])){
495             
496                 //check to see if you should unregister the prototype
497                 if (unregisterPrototype){
498                     this.unregisterObject(name + ".prototype", container[name].prototype);
499                 }
500                     
501                 //get original data
502                 var owner /*:Object*/ = container[name].__yuiOwner,
503                     funcName /*:String*/ = container[name].__yuiFuncName;
504                     
505                 //delete extra information
506                 delete container[name].__yuiOwner;
507                 delete container[name].__yuiFuncName;
508                 
509                 //replace instrumented function
510                 owner[funcName] = container[name];
511                 
512                 //delete supporting information
513                 delete container[name];          
514             }
515                 
516         
517         },
518         
519         /**
520          * Unregisters an object for profiling. It takes the object and looks for functions.
521          * When a function is found, unregisterMethod() is called on it. If set to recrusive
522          * mode, it will also unregister objects found inside of this object, 
523          * using the same methodology.
524          * @param {String} name The name of the object to unregister.
525          * @param {Boolean} recurse (Optional) Determines if subobject methods should also be
526          *      unregistered.
527          * @return {Void}
528          * @method unregisterObject
529          * @static
530          */
531         unregisterObject : function (name /*:String*/, recurse /*:Boolean*/) /*:Void*/{
532         
533             //get the object
534             if (L.isObject(container[name])){            
535                 var object = container[name];    
536             
537                 for (var prop in object) {
538                     if (typeof object[prop] == "function"){
539                         this.unregisterFunction(name + "." + prop);
540                     } else if (typeof object[prop] == "object" && recurse){
541                         this.unregisterObject(name + "." + prop, recurse);
542                     }
543                 }
544                 
545                 delete container[name];
546             }
547         
548         }
549              
550     
551     };
552
553
554
555 }, '3.3.0' ,{requires:['oop']});