browser_perf-options-show-jit-optimizations.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /* Any copyright is dedicated to the Public Domain.
  2. http://creativecommons.org/publicdomain/zero/1.0/ */
  3. "use strict";
  4. /* eslint-disable */
  5. // Bug 1235788, increase time out of this test
  6. requestLongerTimeout(2);
  7. /**
  8. * Tests that the JIT Optimizations view renders optimization data
  9. * if on, and displays selected frames on focus.
  10. */
  11. const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
  12. Services.prefs.setBoolPref(INVERT_PREF, false);
  13. function* spawnTest() {
  14. let { panel } = yield initPerformance(SIMPLE_URL);
  15. let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
  16. let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView } = panel.panelWin;
  17. let profilerData = { threads: [gThread] };
  18. is(Services.prefs.getBoolPref(JIT_PREF), false, "record JIT Optimizations pref off by default");
  19. Services.prefs.setBoolPref(JIT_PREF, true);
  20. is(Services.prefs.getBoolPref(JIT_PREF), true, "toggle on record JIT Optimizations");
  21. // Make two recordings, so we have one to switch to later, as the
  22. // second one will have fake sample data
  23. yield startRecording(panel);
  24. yield stopRecording(panel);
  25. yield startRecording(panel);
  26. yield stopRecording(panel);
  27. yield DetailsView.selectView("js-calltree");
  28. yield injectAndRenderProfilerData();
  29. is($("#jit-optimizations-view").classList.contains("hidden"), true,
  30. "JIT Optimizations should be hidden when pref is on, but no frame selected");
  31. // A is never a leaf, so it's optimizations should not be shown.
  32. yield checkFrame(1);
  33. // gRawSite2 and gRawSite3 are both optimizations on B, so they'll have
  34. // indices in descending order of # of samples.
  35. yield checkFrame(2, true);
  36. // Leaf node (C) with no optimizations should not display any opts.
  37. yield checkFrame(3);
  38. // Select the node with optimizations and change to a new recording
  39. // to ensure the opts view is cleared
  40. let rendered = once(JsCallTreeView, "focus");
  41. mousedown(window, $$(".call-tree-item")[2]);
  42. yield rendered;
  43. let isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  44. ok(!isHidden, "opts view should be visible when selecting a frame with opts");
  45. let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  46. rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
  47. setSelectedRecording(panel, 0);
  48. yield Promise.all([select, rendered]);
  49. isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  50. ok(isHidden, "opts view is hidden when switching recordings");
  51. rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
  52. setSelectedRecording(panel, 1);
  53. yield rendered;
  54. rendered = once(JsCallTreeView, "focus");
  55. mousedown(window, $$(".call-tree-item")[2]);
  56. yield rendered;
  57. isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  58. ok(!isHidden, "opts view should be visible when selecting a frame with opts");
  59. rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
  60. Services.prefs.setBoolPref(JIT_PREF, false);
  61. yield rendered;
  62. ok(true, "call tree rerendered when JIT pref changes");
  63. isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  64. ok(isHidden, "opts view hidden when toggling off jit pref");
  65. rendered = once(JsCallTreeView, "focus");
  66. mousedown(window, $$(".call-tree-item")[2]);
  67. yield rendered;
  68. isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  69. ok(isHidden, "opts view hidden when jit pref off and selecting a frame with opts");
  70. yield teardown(panel);
  71. finish();
  72. function* injectAndRenderProfilerData() {
  73. // Get current recording and inject our mock data
  74. info("Injecting mock profile data");
  75. let recording = PerformanceController.getCurrentRecording();
  76. recording._profile = profilerData;
  77. // Force a rerender
  78. let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
  79. JsCallTreeView.render(OverviewView.getTimeInterval());
  80. yield rendered;
  81. }
  82. function* checkFrame(frameIndex, hasOpts) {
  83. info(`Checking frame ${frameIndex}`);
  84. // Click the frame
  85. let rendered = once(JsCallTreeView, "focus");
  86. mousedown(window, $$(".call-tree-item")[frameIndex]);
  87. yield rendered;
  88. let isHidden = $("#jit-optimizations-view").classList.contains("hidden");
  89. if (hasOpts) {
  90. ok(!isHidden, "JIT Optimizations view is not hidden if current frame has opts.");
  91. } else {
  92. ok(isHidden, "JIT Optimizations view is hidden if current frame does not have opts");
  93. }
  94. }
  95. }
  96. var gUniqueStacks = new RecordingUtils.UniqueStacks();
  97. function uniqStr(s) {
  98. return gUniqueStacks.getOrAddStringIndex(s);
  99. }
  100. // Since deflateThread doesn't handle deflating optimization info, use
  101. // placeholder names A_O1, B_O2, and B_O3, which will be used to manually
  102. // splice deduped opts into the profile.
  103. var gThread = RecordingUtils.deflateThread({
  104. samples: [{
  105. time: 0,
  106. frames: [
  107. { location: "(root)" }
  108. ]
  109. }, {
  110. time: 5,
  111. frames: [
  112. { location: "(root)" },
  113. { location: "A_O1" },
  114. { location: "B_O2" },
  115. { location: "C (http://foo/bar/baz:56)" }
  116. ]
  117. }, {
  118. time: 5 + 1,
  119. frames: [
  120. { location: "(root)" },
  121. { location: "A (http://foo/bar/baz:12)" },
  122. { location: "B_O2" },
  123. ]
  124. }, {
  125. time: 5 + 1 + 2,
  126. frames: [
  127. { location: "(root)" },
  128. { location: "A_O1" },
  129. { location: "B_O3" },
  130. ]
  131. }, {
  132. time: 5 + 1 + 2 + 7,
  133. frames: [
  134. { location: "(root)" },
  135. { location: "A_O1" },
  136. { location: "E (http://foo/bar/baz:90)" },
  137. { location: "F (http://foo/bar/baz:99)" }
  138. ]
  139. }],
  140. markers: []
  141. }, gUniqueStacks);
  142. // 3 RawOptimizationSites
  143. var gRawSite1 = {
  144. _testFrameInfo: { name: "A", line: "12", file: "@baz" },
  145. line: 12,
  146. column: 2,
  147. types: [{
  148. mirType: uniqStr("Object"),
  149. site: uniqStr("A (http://foo/bar/bar:12)"),
  150. typeset: [{
  151. keyedBy: uniqStr("constructor"),
  152. name: uniqStr("Foo"),
  153. location: uniqStr("A (http://foo/bar/baz:12)")
  154. }, {
  155. keyedBy: uniqStr("primitive"),
  156. location: uniqStr("self-hosted")
  157. }]
  158. }],
  159. attempts: {
  160. schema: {
  161. outcome: 0,
  162. strategy: 1
  163. },
  164. data: [
  165. [uniqStr("Failure1"), uniqStr("SomeGetter1")],
  166. [uniqStr("Failure2"), uniqStr("SomeGetter2")],
  167. [uniqStr("Failure3"), uniqStr("SomeGetter3")]
  168. ]
  169. }
  170. };
  171. var gRawSite2 = {
  172. _testFrameInfo: { name: "B", line: "10", file: "@boo" },
  173. line: 40,
  174. types: [{
  175. mirType: uniqStr("Int32"),
  176. site: uniqStr("Receiver")
  177. }],
  178. attempts: {
  179. schema: {
  180. outcome: 0,
  181. strategy: 1
  182. },
  183. data: [
  184. [uniqStr("Failure1"), uniqStr("SomeGetter1")],
  185. [uniqStr("Failure2"), uniqStr("SomeGetter2")],
  186. [uniqStr("Inlined"), uniqStr("SomeGetter3")]
  187. ]
  188. }
  189. };
  190. var gRawSite3 = {
  191. _testFrameInfo: { name: "B", line: "10", file: "@boo" },
  192. line: 34,
  193. types: [{
  194. mirType: uniqStr("Int32"),
  195. site: uniqStr("Receiver")
  196. }],
  197. attempts: {
  198. schema: {
  199. outcome: 0,
  200. strategy: 1
  201. },
  202. data: [
  203. [uniqStr("Failure1"), uniqStr("SomeGetter1")],
  204. [uniqStr("Failure2"), uniqStr("SomeGetter2")],
  205. [uniqStr("Failure3"), uniqStr("SomeGetter3")]
  206. ]
  207. }
  208. };
  209. gThread.frameTable.data.forEach((frame) => {
  210. const LOCATION_SLOT = gThread.frameTable.schema.location;
  211. const OPTIMIZATIONS_SLOT = gThread.frameTable.schema.optimizations;
  212. let l = gThread.stringTable[frame[LOCATION_SLOT]];
  213. switch (l) {
  214. case "A_O1":
  215. frame[LOCATION_SLOT] = uniqStr("A (http://foo/bar/baz:12)");
  216. frame[OPTIMIZATIONS_SLOT] = gRawSite1;
  217. break;
  218. case "B_O2":
  219. frame[LOCATION_SLOT] = uniqStr("B (http://foo/bar/boo:10)");
  220. frame[OPTIMIZATIONS_SLOT] = gRawSite2;
  221. break;
  222. case "B_O3":
  223. frame[LOCATION_SLOT] = uniqStr("B (http://foo/bar/boo:10)");
  224. frame[OPTIMIZATIONS_SLOT] = gRawSite3;
  225. break;
  226. }
  227. });
  228. /* eslint-enable */