Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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