timing.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * @fileoverview Tracks performance of individual rules.
  3. * @author Brandon Mills
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Helpers
  8. //------------------------------------------------------------------------------
  9. /* c8 ignore next */
  10. /**
  11. * Align the string to left
  12. * @param {string} str string to evaluate
  13. * @param {int} len length of the string
  14. * @param {string} ch delimiter character
  15. * @returns {string} modified string
  16. * @private
  17. */
  18. function alignLeft(str, len, ch) {
  19. return str + new Array(len - str.length + 1).join(ch || " ");
  20. }
  21. /* c8 ignore next */
  22. /**
  23. * Align the string to right
  24. * @param {string} str string to evaluate
  25. * @param {int} len length of the string
  26. * @param {string} ch delimiter character
  27. * @returns {string} modified string
  28. * @private
  29. */
  30. function alignRight(str, len, ch) {
  31. return new Array(len - str.length + 1).join(ch || " ") + str;
  32. }
  33. //------------------------------------------------------------------------------
  34. // Module definition
  35. //------------------------------------------------------------------------------
  36. const enabled = !!process.env.TIMING;
  37. const HEADERS = ["Rule", "Time (ms)", "Relative"];
  38. const ALIGN = [alignLeft, alignRight, alignRight];
  39. /**
  40. * Decide how many rules to show in the output list.
  41. * @returns {number} the number of rules to show
  42. */
  43. function getListSize() {
  44. const MINIMUM_SIZE = 10;
  45. if (typeof process.env.TIMING !== "string") {
  46. return MINIMUM_SIZE;
  47. }
  48. if (process.env.TIMING.toLowerCase() === "all") {
  49. return Number.POSITIVE_INFINITY;
  50. }
  51. const TIMING_ENV_VAR_AS_INTEGER = Number.parseInt(process.env.TIMING, 10);
  52. return TIMING_ENV_VAR_AS_INTEGER > 10 ? TIMING_ENV_VAR_AS_INTEGER : MINIMUM_SIZE;
  53. }
  54. /* c8 ignore next */
  55. /**
  56. * display the data
  57. * @param {Object} data Data object to be displayed
  58. * @returns {void} prints modified string with console.log
  59. * @private
  60. */
  61. function display(data) {
  62. let total = 0;
  63. const rows = Object.keys(data)
  64. .map(key => {
  65. const time = data[key];
  66. total += time;
  67. return [key, time];
  68. })
  69. .sort((a, b) => b[1] - a[1])
  70. .slice(0, getListSize());
  71. rows.forEach(row => {
  72. row.push(`${(row[1] * 100 / total).toFixed(1)}%`);
  73. row[1] = row[1].toFixed(3);
  74. });
  75. rows.unshift(HEADERS);
  76. const widths = [];
  77. rows.forEach(row => {
  78. const len = row.length;
  79. for (let i = 0; i < len; i++) {
  80. const n = row[i].length;
  81. if (!widths[i] || n > widths[i]) {
  82. widths[i] = n;
  83. }
  84. }
  85. });
  86. const table = rows.map(row => (
  87. row
  88. .map((cell, index) => ALIGN[index](cell, widths[index]))
  89. .join(" | ")
  90. ));
  91. table.splice(1, 0, widths.map((width, index) => {
  92. const extraAlignment = index !== 0 && index !== widths.length - 1 ? 2 : 1;
  93. return ALIGN[index](":", width + extraAlignment, "-");
  94. }).join("|"));
  95. console.log(table.join("\n")); // eslint-disable-line no-console -- Debugging function
  96. }
  97. /* c8 ignore next */
  98. module.exports = (function() {
  99. const data = Object.create(null);
  100. /**
  101. * Time the run
  102. * @param {any} key key from the data object
  103. * @param {Function} fn function to be called
  104. * @returns {Function} function to be executed
  105. * @private
  106. */
  107. function time(key, fn) {
  108. if (typeof data[key] === "undefined") {
  109. data[key] = 0;
  110. }
  111. return function(...args) {
  112. let t = process.hrtime();
  113. const result = fn(...args);
  114. t = process.hrtime(t);
  115. data[key] += t[0] * 1e3 + t[1] / 1e6;
  116. return result;
  117. };
  118. }
  119. if (enabled) {
  120. process.on("exit", () => {
  121. display(data);
  122. });
  123. }
  124. return {
  125. time,
  126. enabled,
  127. getListSize
  128. };
  129. }());