profilerVisualization.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. function createRow(table, cellName, items) {
  2. var tr = document.createElement('tr');
  3. var res = [];
  4. items.forEach(function(x, i) {
  5. if (x === undefined) {
  6. res.push(null);
  7. return;
  8. }
  9. var td = document.createElement(cellName);
  10. td.textContent = x;
  11. tr.appendChild(td);
  12. res.push(td);
  13. var colspan = 1;
  14. for (var n = i + 1; n < items.length; n++) {
  15. if (items[n] !== undefined) {
  16. break;
  17. }
  18. colspan += 1;
  19. }
  20. if (colspan > 1) {
  21. td.colSpan = colspan;
  22. }
  23. });
  24. table.appendChild(tr);
  25. return res;
  26. }
  27. function createVisualizationTable(data, cutoff = 0, sort = "") {
  28. var table = document.createElement('table');
  29. table.className = 'popup-table';
  30. var keys = Object.keys(data);
  31. if (sort === "number") {
  32. keys = keys.sort(function(a, b) {
  33. return data[b] - data[a];
  34. });
  35. } else {
  36. keys = keys.sort();
  37. }
  38. var items = keys.map(function(x) {
  39. return {key: x, parts: x.split('/'), value: data[x]};
  40. });
  41. var maxLength = items.reduce(function(a, b) {
  42. return Math.max(a, b.parts.length);
  43. }, 0);
  44. var cols = createRow(
  45. table,
  46. 'th',
  47. [
  48. cutoff === 0 ? 'key' : 'record',
  49. cutoff === 0 ? 'value' : 'seconds'
  50. ]
  51. );
  52. cols[0].colSpan = maxLength;
  53. function arraysEqual(a, b) {
  54. return !(a < b || b < a);
  55. }
  56. var addLevel = function(level, parent, hide) {
  57. var matching = items.filter(function(x) {
  58. return x.parts[level] && !x.parts[level + 1] && arraysEqual(x.parts.slice(0, level), parent);
  59. });
  60. if (sort === "number") {
  61. matching = matching.sort(function(a, b) {
  62. return b.value - a.value;
  63. });
  64. } else {
  65. matching = matching.sort();
  66. }
  67. var othersTime = 0;
  68. var othersList = [];
  69. var othersRows = [];
  70. var childrenRows = [];
  71. matching.forEach(function(x) {
  72. var visible = (cutoff === 0 && !hide) || (x.value >= cutoff && !hide);
  73. var cells = [];
  74. for (var i = 0; i < maxLength; i++) {
  75. cells.push(x.parts[i]);
  76. }
  77. cells.push(cutoff === 0 ? x.value : x.value.toFixed(3));
  78. var cols = createRow(table, 'td', cells);
  79. for (i = 0; i < level; i++) {
  80. cols[i].className = 'muted';
  81. }
  82. var tr = cols[0].parentNode;
  83. if (!visible) {
  84. tr.classList.add("hidden");
  85. }
  86. if (cutoff === 0 || x.value >= cutoff) {
  87. childrenRows.push(tr);
  88. } else {
  89. othersTime += x.value;
  90. othersList.push(x.parts[level]);
  91. othersRows.push(tr);
  92. }
  93. var children = addLevel(level + 1, parent.concat([x.parts[level]]), true);
  94. if (children.length > 0) {
  95. var cell = cols[level];
  96. var onclick = function() {
  97. cell.classList.remove("link");
  98. cell.removeEventListener("click", onclick);
  99. children.forEach(function(x) {
  100. x.classList.remove("hidden");
  101. });
  102. };
  103. cell.classList.add("link");
  104. cell.addEventListener("click", onclick);
  105. }
  106. });
  107. if (othersTime > 0) {
  108. var cells = [];
  109. for (var i = 0; i < maxLength; i++) {
  110. cells.push(parent[i]);
  111. }
  112. cells.push(othersTime.toFixed(3));
  113. cells[level] = 'others';
  114. var cols = createRow(table, 'td', cells);
  115. for (i = 0; i < level; i++) {
  116. cols[i].className = 'muted';
  117. }
  118. var cell = cols[level];
  119. var tr = cell.parentNode;
  120. var onclick = function() {
  121. tr.classList.add("hidden");
  122. cell.classList.remove("link");
  123. cell.removeEventListener("click", onclick);
  124. othersRows.forEach(function(x) {
  125. x.classList.remove("hidden");
  126. });
  127. };
  128. cell.title = othersList.join(", ");
  129. cell.classList.add("link");
  130. cell.addEventListener("click", onclick);
  131. if (hide) {
  132. tr.classList.add("hidden");
  133. }
  134. childrenRows.push(tr);
  135. }
  136. return childrenRows;
  137. };
  138. addLevel(0, []);
  139. return table;
  140. }
  141. function showProfile(path, cutoff = 0.05) {
  142. requestGet(path, {}, function(data) {
  143. data.records['total'] = data.total;
  144. const table = createVisualizationTable(data.records, cutoff, "number");
  145. popup(table);
  146. });
  147. }