output.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. const MS_IN_MINUTE = 60000;
  2. const MS_IN_SECOND = 1000;
  3. const chalk = require("chalk");
  4. const { fg, bg } = require("./colours");
  5. const { groupBy, getAverages, getTotalActiveTime } = require("./utils");
  6. const humanTime = (ms, options = {}) => {
  7. if (options.verbose) {
  8. return ms.toLocaleString() + " ms";
  9. }
  10. const minutes = Math.floor(ms / MS_IN_MINUTE);
  11. const secondsRaw = (ms - minutes * MS_IN_MINUTE) / MS_IN_SECOND;
  12. const secondsWhole = Math.floor(secondsRaw);
  13. const remainderPrecision = secondsWhole > 0 ? 2 : 3;
  14. const secondsRemainder = Math.min(secondsRaw - secondsWhole, 0.99);
  15. const seconds =
  16. secondsWhole +
  17. secondsRemainder
  18. .toPrecision(remainderPrecision)
  19. .replace(/^0/, "")
  20. .replace(/0+$/, "")
  21. .replace(/^\.$/, "");
  22. let time = "";
  23. if (minutes > 0) time += minutes + " min" + (minutes > 1 ? "s" : "") + ", ";
  24. time += seconds + " secs";
  25. return time;
  26. };
  27. const smpTag = () => bg(" SMP ") + " ⏱ ";
  28. module.exports.smpTag = smpTag;
  29. module.exports.getHumanOutput = (outputObj, options = {}) => {
  30. const hT = x => humanTime(x, options);
  31. let output = "\n\n" + smpTag() + "\n";
  32. if (outputObj.misc) {
  33. output +=
  34. "General output time took " +
  35. fg(hT(outputObj.misc.compileTime, options), outputObj.misc.compileTime);
  36. output += "\n\n";
  37. }
  38. if (outputObj.plugins) {
  39. output += smpTag() + "Plugins\n";
  40. Object.keys(outputObj.plugins)
  41. .sort(
  42. (name1, name2) => outputObj.plugins[name2] - outputObj.plugins[name1]
  43. )
  44. .forEach(pluginName => {
  45. output +=
  46. chalk.bold(pluginName) +
  47. " took " +
  48. fg(hT(outputObj.plugins[pluginName]), outputObj.plugins[pluginName]);
  49. output += "\n";
  50. });
  51. output += "\n";
  52. }
  53. if (outputObj.loaders) {
  54. output += smpTag() + "Loaders\n";
  55. outputObj.loaders.build
  56. .sort((obj1, obj2) => obj2.activeTime - obj1.activeTime)
  57. .forEach(loaderObj => {
  58. output +=
  59. loaderObj.loaders.map(fg).join(", and \n") +
  60. " took " +
  61. fg(hT(loaderObj.activeTime), loaderObj.activeTime) +
  62. "\n";
  63. let xEqualsY = [];
  64. if (options.verbose) {
  65. xEqualsY.push(["median", hT(loaderObj.averages.median)]);
  66. xEqualsY.push(["mean", hT(loaderObj.averages.mean)]);
  67. if (typeof loaderObj.averages.variance === "number")
  68. xEqualsY.push(["s.d.", hT(Math.sqrt(loaderObj.averages.variance))]);
  69. xEqualsY.push([
  70. "range",
  71. "(" +
  72. hT(loaderObj.averages.range.start) +
  73. " --> " +
  74. hT(loaderObj.averages.range.end) +
  75. ")",
  76. ]);
  77. }
  78. if (loaderObj.loaders.length > 1) {
  79. Object.keys(loaderObj.subLoadersTime).forEach(subLoader => {
  80. xEqualsY.push([subLoader, hT(loaderObj.subLoadersTime[subLoader])]);
  81. });
  82. }
  83. xEqualsY.push(["module count", loaderObj.averages.dataPoints]);
  84. const maxXLength = xEqualsY.reduce(
  85. (acc, cur) => Math.max(acc, cur[0].length),
  86. 0
  87. );
  88. xEqualsY.forEach(xY => {
  89. const padEnd = maxXLength - xY[0].length;
  90. output += " " + xY[0] + " ".repeat(padEnd) + " = " + xY[1] + "\n";
  91. });
  92. });
  93. }
  94. output += "\n\n";
  95. return output;
  96. };
  97. module.exports.getMiscOutput = data => ({
  98. compileTime: data.compile[0].end - data.compile[0].start,
  99. });
  100. module.exports.getPluginsOutput = data =>
  101. Object.keys(data).reduce((acc, key) => {
  102. const inData = data[key];
  103. const startEndsByName = groupBy("name", inData);
  104. return startEndsByName.reduce((innerAcc, startEnds) => {
  105. innerAcc[startEnds[0].name] =
  106. (innerAcc[startEnds[0].name] || 0) + getTotalActiveTime(startEnds);
  107. return innerAcc;
  108. }, acc);
  109. }, {});
  110. module.exports.getLoadersOutput = data => {
  111. const startEndsByLoader = groupBy("loaders", data.build);
  112. const allSubLoaders = data["build-specific"] || [];
  113. const buildData = startEndsByLoader.map(startEnds => {
  114. const averages = getAverages(startEnds);
  115. const activeTime = getTotalActiveTime(startEnds);
  116. const subLoaders = groupBy(
  117. "loader",
  118. allSubLoaders.filter(l => startEnds.find(x => x.name === l.name))
  119. );
  120. const subLoadersActiveTime = subLoaders.reduce((acc, loaders) => {
  121. acc[loaders[0].loader] = getTotalActiveTime(loaders);
  122. return acc;
  123. }, {});
  124. return {
  125. averages,
  126. activeTime,
  127. loaders: startEnds[0].loaders,
  128. subLoadersTime: subLoadersActiveTime,
  129. };
  130. });
  131. return { build: buildData };
  132. };