print_stats.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. "use strict";
  2. const print_stats = {
  3. stats_to_string: function(cpu)
  4. {
  5. return print_stats.print_misc_stats(cpu) +
  6. print_stats.print_basic_block_duplication(cpu) +
  7. print_stats.print_wasm_basic_block_count_histogram(cpu) +
  8. print_stats.print_instruction_counts(cpu);
  9. },
  10. print_misc_stats: function(cpu)
  11. {
  12. let text = "";
  13. const stat_names = [
  14. "COMPILE",
  15. "COMPILE_SUCCESS",
  16. "COMPILE_CUT_OFF_AT_END_OF_PAGE",
  17. "COMPILE_WITH_LOOP_SAFETY",
  18. "COMPILE_BASIC_BLOCK",
  19. "COMPILE_ENTRY_POINT",
  20. "CACHE_MISMATCH",
  21. "RUN_INTERPRETED",
  22. "RUN_INTERPRETED_PENDING",
  23. "RUN_INTERPRETED_NEAR_END_OF_PAGE",
  24. "RUN_INTERPRETED_DIFFERENT_STATE",
  25. "RUN_INTERPRETED_STEPS",
  26. "RUN_FROM_CACHE",
  27. "RUN_FROM_CACHE_STEPS",
  28. "TRIGGER_CPU_EXCEPTION",
  29. "SAFE_READ32_FAST",
  30. "SAFE_READ32_SLOW_PAGE_CROSSED",
  31. "SAFE_READ32_SLOW_NOT_VALID",
  32. "SAFE_READ32_SLOW_NOT_USER",
  33. "SAFE_READ32_SLOW_IN_MAPPED_RANGE",
  34. "SAFE_WRITE32_FAST",
  35. "SAFE_WRITE32_SLOW_PAGE_CROSSED",
  36. "SAFE_WRITE32_SLOW_NOT_VALID",
  37. "SAFE_WRITE32_SLOW_NOT_USER",
  38. "SAFE_WRITE32_SLOW_IN_MAPPED_RANGE",
  39. "SAFE_WRITE32_SLOW_READ_ONLY",
  40. "SAFE_WRITE32_SLOW_HAS_CODE",
  41. "DO_RUN",
  42. "DO_MANY_CYCLES",
  43. "CYCLE_INTERNAL",
  44. "INVALIDATE_PAGE",
  45. "INVALIDATE_CACHE_ENTRY",
  46. "NONFAULTING_OPTIMIZATION",
  47. "CLEAR_TLB",
  48. "FULL_CLEAR_TLB",
  49. "TLB_FULL",
  50. "TLB_GLOBAL_FULL",
  51. ];
  52. for(let i = 0; i < stat_names.length; i++)
  53. {
  54. let stat = cpu.wm.exports["_profiler_stat_get"](i);
  55. stat = stat >= 100e6 ? Math.round(stat / 1e6) + "m" : stat >= 100e3 ? Math.round(stat / 1e3) + "k" : stat;
  56. text += stat_names[i] + "=" + stat + " ";
  57. if(((i + 1) % Math.floor(stat_names.length / 3) === 0))
  58. {
  59. text += "\n";
  60. }
  61. }
  62. text += "\n";
  63. text += "TLB_ENTRIES=" + cpu.wm.exports["_get_valid_tlb_entries_count"]() + "\n";
  64. text += "CACHE_UNUSED=" + cpu.v86oxide.exports["jit_unused_cache_stat"]() + "\n";
  65. text += "WASM_TABLE_FREE=" + cpu.v86oxide.exports["jit_get_wasm_table_index_free_list_count"]() + "\n";
  66. text += "do_many_cycles avg: " + do_many_cycles_total / do_many_cycles_count + "\n";
  67. return text;
  68. },
  69. print_basic_block_duplication: function(cpu)
  70. {
  71. let unique = 0;
  72. let total = 0;
  73. let duplicates = 0;
  74. const histogram = [];
  75. const addresses = {};
  76. for(let i = 0; i < JIT_CACHE_ARRAY_SIZE; i++)
  77. {
  78. const address = cpu.v86oxide.exports["jit_get_entry_address"](i);
  79. if(address !== 0)
  80. {
  81. addresses[address] = (addresses[address] || 0) + 1;
  82. }
  83. }
  84. for(let [address, count] of Object.entries(addresses))
  85. {
  86. dbg_assert(count >= 1);
  87. unique++;
  88. total += count;
  89. duplicates += count - 1;
  90. //for(let i = histogram.length; i < count + 1; i++) histogram.push(0);
  91. //histogram[count]++;
  92. }
  93. let text = "";
  94. text += "UNIQUE=" + unique + " DUPLICATES=" + duplicates + " TOTAL=" + total + "\n";
  95. return text;
  96. },
  97. print_wasm_basic_block_count_histogram: function(cpu)
  98. {
  99. let text = "";
  100. let pending_count = 0;
  101. const histogram = Object.create(null);
  102. for(let i = 0; i < JIT_CACHE_ARRAY_SIZE; i++)
  103. {
  104. const length = cpu.v86oxide.exports["jit_get_entry_length"](i);
  105. pending_count += cpu.v86oxide.exports["jit_get_entry_pending"](i);
  106. histogram[length] = (histogram[length] || 0) + 1;
  107. }
  108. let above = 0;
  109. for(let i of Object.keys(histogram))
  110. {
  111. i = +i;
  112. if(i >= 32)
  113. {
  114. above += histogram[i];
  115. }
  116. }
  117. for(let i = 0; i < 32; i++)
  118. {
  119. text += i + ":" + (histogram[i] || 0) + " ";
  120. }
  121. text += "32+:" + above + "\n";
  122. text += "Pending: " + pending_count + "\n";
  123. return text;
  124. },
  125. print_instruction_counts: function(cpu)
  126. {
  127. let text = "";
  128. const counts = [];
  129. for(let i = 0; i < 0x100; i++)
  130. {
  131. const count = cpu.wm.exports["_get_opstats_buffer"](i) / 1000 | 0;
  132. counts.push([i, count]);
  133. const count_0f = cpu.wm.exports["_get_opstats_buffer"](i + 0x100) / 1000 | 0;
  134. counts.push([0x0f00 | i, count_0f]);
  135. }
  136. const max_count = Math.max.apply(Math,
  137. counts.map(([_, count]) => count)
  138. );
  139. const pad_length = String(max_count).length;
  140. text += "Instruction counts (in 1000):\n";
  141. let total = 0;
  142. const prefixes = new Set([
  143. 0x26, 0x2E, 0x36, 0x3E,
  144. 0x64, 0x65, 0x66, 0x67,
  145. 0xF0, 0xF2, 0xF3,
  146. ]);
  147. for(let [i, count] of counts)
  148. {
  149. total += i < 0x100 && !prefixes.has(i) ? count : 0;
  150. }
  151. text += "Total: " + total + "\n";
  152. if(total === 0)
  153. {
  154. return "";
  155. }
  156. for(let [i, count] of counts)
  157. {
  158. if((i & 0xFF00) === 0)
  159. {
  160. text += h(i, 2).slice(2) + ":" + v86util.pads(count, pad_length);
  161. if(i % 16 == 15)
  162. text += "\n";
  163. else
  164. text += " ";
  165. }
  166. }
  167. text += "\n";
  168. text += "Instruction counts (0f, in 1000):\n";
  169. for(let [i, count] of counts)
  170. {
  171. if((i & 0xFF00) === 0x0F00)
  172. {
  173. text += h(i & 0xFF, 2).slice(2) + ":" + v86util.pads(count, pad_length);
  174. if(i % 16 == 15)
  175. text += "\n";
  176. else
  177. text += " ";
  178. }
  179. }
  180. text += "\n";
  181. const top_counts = counts.sort(([o1, c1], [o2, c2]) => c2 - c1);
  182. for(let [opcode, count] of top_counts.slice(0, 100))
  183. {
  184. text += opcode.toString(16) + ":" + (count / total * 100).toFixed(1) + " ";
  185. }
  186. text += "\n";
  187. return text;
  188. },
  189. };