print_stats.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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_instruction_counts(cpu);
  7. },
  8. print_misc_stats: function(cpu)
  9. {
  10. let text = "";
  11. const stat_names = [
  12. "COMPILE",
  13. "COMPILE_SKIPPED_NO_NEW_ENTRY_POINTS",
  14. "COMPILE_WRONG_ADDRESS_SPACE",
  15. "COMPILE_CUT_OFF_AT_END_OF_PAGE",
  16. "COMPILE_WITH_LOOP_SAFETY",
  17. "COMPILE_PAGE",
  18. "COMPILE_PAGE/COMPILE",
  19. "COMPILE_BASIC_BLOCK",
  20. "COMPILE_DUPLICATED_BASIC_BLOCK",
  21. "COMPILE_WASM_BLOCK",
  22. "COMPILE_WASM_LOOP",
  23. "COMPILE_DISPATCHER",
  24. "COMPILE_ENTRY_POINT",
  25. "COMPILE_WASM_TOTAL_BYTES",
  26. "COMPILE_WASM_TOTAL_BYTES/COMPILE_PAGE",
  27. "RUN_INTERPRETED",
  28. "RUN_INTERPRETED_NEW_PAGE",
  29. "RUN_INTERPRETED_PAGE_HAS_CODE",
  30. "RUN_INTERPRETED_PAGE_HAS_ENTRY_AFTER_PAGE_WALK",
  31. "RUN_INTERPRETED_NEAR_END_OF_PAGE",
  32. "RUN_INTERPRETED_DIFFERENT_STATE",
  33. "RUN_INTERPRETED_DIFFERENT_STATE_CPL3",
  34. "RUN_INTERPRETED_DIFFERENT_STATE_FLAT",
  35. "RUN_INTERPRETED_DIFFERENT_STATE_IS32",
  36. "RUN_INTERPRETED_DIFFERENT_STATE_SS32",
  37. "RUN_INTERPRETED_MISSED_COMPILED_ENTRY_RUN_INTERPRETED",
  38. "RUN_INTERPRETED_STEPS",
  39. "RUN_FROM_CACHE",
  40. "RUN_FROM_CACHE_STEPS",
  41. "RUN_FROM_CACHE_STEPS/RUN_FROM_CACHE",
  42. "RUN_FROM_CACHE_STEPS/RUN_INTERPRETED_STEPS",
  43. "DIRECT_EXIT",
  44. "INDIRECT_JUMP",
  45. "INDIRECT_JUMP_NO_ENTRY",
  46. "NORMAL_PAGE_CHANGE",
  47. "NORMAL_FALLTHRU",
  48. "NORMAL_FALLTHRU_WITH_TARGET_BLOCK",
  49. "NORMAL_BRANCH",
  50. "NORMAL_BRANCH_WITH_TARGET_BLOCK",
  51. "CONDITIONAL_JUMP",
  52. "CONDITIONAL_JUMP_PAGE_CHANGE",
  53. "CONDITIONAL_JUMP_EXIT",
  54. "CONDITIONAL_JUMP_FALLTHRU",
  55. "CONDITIONAL_JUMP_FALLTHRU_WITH_TARGET_BLOCK",
  56. "CONDITIONAL_JUMP_BRANCH",
  57. "CONDITIONAL_JUMP_BRANCH_WITH_TARGET_BLOCK",
  58. "DISPATCHER_SMALL",
  59. "DISPATCHER_LARGE",
  60. "LOOP",
  61. "LOOP_SAFETY",
  62. "CONDITION_OPTIMISED",
  63. "CONDITION_UNOPTIMISED",
  64. "CONDITION_UNOPTIMISED_PF",
  65. "CONDITION_UNOPTIMISED_UNHANDLED_L",
  66. "CONDITION_UNOPTIMISED_UNHANDLED_LE",
  67. "FAILED_PAGE_CHANGE",
  68. "SAFE_READ_FAST",
  69. "SAFE_READ_SLOW_PAGE_CROSSED",
  70. "SAFE_READ_SLOW_NOT_VALID",
  71. "SAFE_READ_SLOW_NOT_USER",
  72. "SAFE_READ_SLOW_IN_MAPPED_RANGE",
  73. "SAFE_WRITE_FAST",
  74. "SAFE_WRITE_SLOW_PAGE_CROSSED",
  75. "SAFE_WRITE_SLOW_NOT_VALID",
  76. "SAFE_WRITE_SLOW_NOT_USER",
  77. "SAFE_WRITE_SLOW_IN_MAPPED_RANGE",
  78. "SAFE_WRITE_SLOW_READ_ONLY",
  79. "SAFE_WRITE_SLOW_HAS_CODE",
  80. "SAFE_READ_WRITE_FAST",
  81. "SAFE_READ_WRITE_SLOW_PAGE_CROSSED",
  82. "SAFE_READ_WRITE_SLOW_NOT_VALID",
  83. "SAFE_READ_WRITE_SLOW_NOT_USER",
  84. "SAFE_READ_WRITE_SLOW_IN_MAPPED_RANGE",
  85. "SAFE_READ_WRITE_SLOW_READ_ONLY",
  86. "SAFE_READ_WRITE_SLOW_HAS_CODE",
  87. "PAGE_FAULT",
  88. "TLB_MISS",
  89. "DO_MANY_CYCLES",
  90. "CYCLE_INTERNAL",
  91. "INVALIDATE_ALL_MODULES_NO_FREE_WASM_INDICES",
  92. "INVALIDATE_MODULE_WRITTEN_WHILE_COMPILED",
  93. "INVALIDATE_MODULE_UNUSED_AFTER_OVERWRITE",
  94. "INVALIDATE_MODULE_DIRTY_PAGE",
  95. "INVALIDATE_PAGE_HAD_CODE",
  96. "INVALIDATE_PAGE_HAD_ENTRY_POINTS",
  97. "DIRTY_PAGE_DID_NOT_HAVE_CODE",
  98. "RUN_FROM_CACHE_EXIT_SAME_PAGE",
  99. "RUN_FROM_CACHE_EXIT_NEAR_END_OF_PAGE",
  100. "RUN_FROM_CACHE_EXIT_DIFFERENT_PAGE",
  101. "CLEAR_TLB",
  102. "FULL_CLEAR_TLB",
  103. "TLB_FULL",
  104. "TLB_GLOBAL_FULL",
  105. "MODRM_SIMPLE_REG",
  106. "MODRM_SIMPLE_REG_WITH_OFFSET",
  107. "MODRM_SIMPLE_CONST_OFFSET",
  108. "MODRM_COMPLEX",
  109. "SEG_OFFSET_OPTIMISED",
  110. "SEG_OFFSET_NOT_OPTIMISED",
  111. "SEG_OFFSET_NOT_OPTIMISED_ES",
  112. "SEG_OFFSET_NOT_OPTIMISED_FS",
  113. "SEG_OFFSET_NOT_OPTIMISED_GS",
  114. "SEG_OFFSET_NOT_OPTIMISED_NOT_FLAT",
  115. ];
  116. let j = 0;
  117. const stat_values = {};
  118. for(let i = 0; i < stat_names.length; i++)
  119. {
  120. const name = stat_names[i];
  121. let value;
  122. if(name.includes("/"))
  123. {
  124. j++; // skip profiler_stat_get
  125. const [left, right] = name.split("/");
  126. value = stat_values[left] / stat_values[right];
  127. }
  128. else
  129. {
  130. let stat = stat_values[name] = cpu.wm.exports["profiler_stat_get"](i - j);
  131. value = stat >= 100e6 ? Math.round(stat / 1e6) + "m" : stat >= 100e3 ? Math.round(stat / 1e3) + "k" : stat;
  132. }
  133. text += name + "=" + value + "\n";
  134. }
  135. text += "\n";
  136. const tlb_entries = cpu.wm.exports["get_valid_tlb_entries_count"]();
  137. const global_tlb_entries = cpu.wm.exports["get_valid_global_tlb_entries_count"]();
  138. const nonglobal_tlb_entries = tlb_entries - global_tlb_entries;
  139. text += "TLB_ENTRIES=" + tlb_entries + " (" + global_tlb_entries + " global, " + nonglobal_tlb_entries + " non-global)\n";
  140. text += "WASM_TABLE_FREE=" + cpu.wm.exports["jit_get_wasm_table_index_free_list_count"]() + "\n";
  141. text += "JIT_CACHE_SIZE=" + cpu.wm.exports["jit_get_cache_size"]() + "\n";
  142. text += "FLAT_SEGMENTS=" + cpu.wm.exports["has_flat_segmentation"]() + "\n";
  143. text += "do_many_cycles avg: " + (cpu.do_many_cycles_total / cpu.do_many_cycles_count || 0) + "\n";
  144. text += "wasm memory size: " + (cpu.wasm_memory.buffer.byteLength >> 20) + "m\n";
  145. text += "Config:\n";
  146. text += "MAX_PAGES=" + cpu.wm.exports["get_config"](0) + "\n";
  147. text += "JIT_USE_LOOP_SAFETY=" + cpu.wm.exports["get_config"](1) + "\n";
  148. text += "MAX_EXTRA_BASIC_BLOCKS=" + cpu.wm.exports["get_config"](2) + "\n";
  149. return text;
  150. },
  151. print_instruction_counts: function(cpu)
  152. {
  153. return [
  154. print_stats.print_instruction_counts_offset(cpu, false, false, false, false),
  155. print_stats.print_instruction_counts_offset(cpu, true, false, false, false),
  156. print_stats.print_instruction_counts_offset(cpu, false, true, false, false),
  157. print_stats.print_instruction_counts_offset(cpu, false, false, true, false),
  158. print_stats.print_instruction_counts_offset(cpu, false, false, false, true),
  159. ].join("\n\n");
  160. },
  161. print_instruction_counts_offset: function(cpu, compiled, jit_exit, unguarded_register, wasm_size)
  162. {
  163. let text = "";
  164. const counts = [];
  165. const label =
  166. compiled ? "compiled" :
  167. jit_exit ? "jit exit" :
  168. unguarded_register ? "unguarded register" :
  169. wasm_size ? "wasm size" :
  170. "executed";
  171. for(let opcode = 0; opcode < 0x100; opcode++)
  172. {
  173. for(let fixed_g = 0; fixed_g < 8; fixed_g++)
  174. {
  175. for(let is_mem of [false, true])
  176. {
  177. const count = cpu.wm.exports["get_opstats_buffer"](compiled, jit_exit, unguarded_register, wasm_size, opcode, false, is_mem, fixed_g);
  178. counts.push({ opcode, count, is_mem, fixed_g });
  179. const count_0f = cpu.wm.exports["get_opstats_buffer"](compiled, jit_exit, unguarded_register, wasm_size, opcode, true, is_mem, fixed_g);
  180. counts.push({ opcode: 0x0f00 | opcode, count: count_0f, is_mem, fixed_g });
  181. }
  182. }
  183. }
  184. let total = 0;
  185. const prefixes = new Set([
  186. 0x26, 0x2E, 0x36, 0x3E,
  187. 0x64, 0x65, 0x66, 0x67,
  188. 0xF0, 0xF2, 0xF3,
  189. ]);
  190. for(let { count, opcode } of counts)
  191. {
  192. if(!prefixes.has(opcode))
  193. {
  194. total += count;
  195. }
  196. }
  197. if(total === 0)
  198. {
  199. return "";
  200. }
  201. const per_opcode = new Uint32Array(0x100);
  202. const per_opcode0f = new Uint32Array(0x100);
  203. for(let { opcode, count } of counts)
  204. {
  205. if((opcode & 0xFF00) == 0x0F00)
  206. {
  207. per_opcode0f[opcode & 0xFF] += count;
  208. }
  209. else
  210. {
  211. per_opcode[opcode & 0xFF] += count;
  212. }
  213. }
  214. text += "------------------\n";
  215. text += "Total: " + total + "\n";
  216. const factor = total > 1e7 ? 1000 : 1;
  217. const max_count = Math.max.apply(Math,
  218. counts.map(({ count }) => Math.round(count / factor))
  219. );
  220. const pad_length = String(max_count).length;
  221. text += `Instruction counts ${label} (in ${factor}):\n`;
  222. for(let i = 0; i < 0x100; i++)
  223. {
  224. text += i.toString(16).padStart(2, "0") + ":" + v86util.pads(Math.round(per_opcode[i] / factor), pad_length);
  225. if(i % 16 == 15)
  226. text += "\n";
  227. else
  228. text += " ";
  229. }
  230. text += "\n";
  231. text += `Instruction counts ${label} (0f, in ${factor}):\n`;
  232. for(let i = 0; i < 0x100; i++)
  233. {
  234. text += (i & 0xFF).toString(16).padStart(2, "0") + ":" + v86util.pads(Math.round(per_opcode0f[i] / factor), pad_length);
  235. if(i % 16 == 15)
  236. text += "\n";
  237. else
  238. text += " ";
  239. }
  240. text += "\n";
  241. const top_counts = counts.filter(({ count }) => count).sort(({ count: count1 }, { count: count2 }) => count2 - count1);
  242. for(let { opcode, is_mem, fixed_g, count } of top_counts.slice(0, 200))
  243. {
  244. let opcode_description = opcode.toString(16) + "_" + fixed_g + (is_mem ? "_m" : "_r");
  245. text += opcode_description + ":" + (count / total * 100).toFixed(2) + " ";
  246. }
  247. text += "\n";
  248. return text;
  249. },
  250. };
  251. if(typeof module !== "undefined" && typeof module.exports !== "undefined")
  252. {
  253. module.exports["print_stats"] = print_stats;
  254. }