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