timing.js 4.1 KB

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