Bug 1582741 - Rewrite native allocations test as an xpcshell test; r=canaltinova
authorGreg Tatum <gtatum@mozilla.com>
Wed, 13 Nov 2019 16:17:21 +0000
changeset 501799 b1c0de5b727cc3bb5c03866793f7e2669c65ce3c
parent 501798 9cdc93b402a207bd714de113f4bcfd7086062cf2
child 501800 b37cf462c34198a34ffe38ec1b9fc0ca56ab9a25
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscanaltinova
bugs1582741
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1582741 - Rewrite native allocations test as an xpcshell test; r=canaltinova The bloat log was not compatible with the native allocations, and is always on for debug builds of mochitests. We had no native allocation coverage on debug builds because of it. This commit rewrites the test as an xpcshell test which is both faster and simpler. I don't think we need the added complexity of running the test in the full browser environment. An xpcshell test fully excercises the code in a simpler fashion. Differential Revision: https://phabricator.services.mozilla.com/D51934
tools/profiler/tests/browser/browser.ini
tools/profiler/tests/browser/browser_test_feature_nativeallocations.js
tools/profiler/tests/shared-head.js
tools/profiler/tests/xpcshell/test_feature_nativeallocations.js
tools/profiler/tests/xpcshell/xpcshell.ini
--- a/tools/profiler/tests/browser/browser.ini
+++ b/tools/profiler/tests/browser/browser.ini
@@ -7,11 +7,10 @@ support-files =
   multi_frame.html
   simple.html
   single_frame.html
 
 [browser_test_feature_ipcmessages.js]
 [browser_test_feature_jsallocations.js]
 [browser_test_feature_nostacksampling.js]
 [browser_test_feature_preferencereads.js]
-[browser_test_feature_nativeallocations.js]
 [browser_test_profile_single_frame_page_info.js]
 [browser_test_profile_multi_frame_page_info.js]
deleted file mode 100644
--- a/tools/profiler/tests/browser/browser_test_feature_nativeallocations.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Test the native allocations feature. This is done as a browser test to ensure
- * that we realistically try out how the native allocations are running. This
- * ensures that we are collecting allocations for the content process and the
- * parent process.
- */
-add_task(async function test_profile_feature_nativeallocations() {
-  if (!AppConstants.MOZ_GECKO_PROFILER) {
-    return;
-  }
-  Assert.ok(
-    !Services.profiler.IsActive(),
-    "The profiler is not currently active"
-  );
-
-  info("Start the profiler to test the native allocations.");
-  startProfiler({
-    features: ["threads", "leaf", "nativeallocations"],
-  });
-
-  const env = Cc["@mozilla.org/process/environment;1"].getService(
-    Ci.nsIEnvironment
-  );
-
-  if (env.get("XPCOM_MEM_BLOAT_LOG")) {
-    info("Native allocations do not currently work with the bloat log.");
-    // Stop the profiler and exit. Note that this happens after we have already
-    // turned on the profiler so that we can still test this code path.
-    Services.profiler.StopProfiler();
-    return;
-  }
-
-  info("Launch a new tab to kick off a content process.");
-
-  const url = BASE_URL + "do_work_500ms.html";
-  await BrowserTestUtils.withNewTab(url, async contentBrowser => {
-    const contentPid = await ContentTask.spawn(
-      contentBrowser,
-      null,
-      () => Services.appinfo.processID
-    );
-
-    info("Wait 100ms so that we know some work has been done.");
-    await wait(100);
-
-    info(
-      "Check that we can get some allocations when the feature is turned on."
-    );
-    {
-      const { parentThread, contentThread } = await stopProfilerAndGetThreads(
-        contentPid
-      );
-      Assert.greater(
-        getPayloadsOfType(parentThread, "Native allocation").length,
-        0,
-        "Allocations were recorded for the parent process' main thread when the " +
-          "Native Allocation feature was turned on."
-      );
-      Assert.greater(
-        getPayloadsOfType(contentThread, "Native allocation").length,
-        0,
-        "Allocations were recorded for the content process' main thread when the " +
-          "Native Allocation feature was turned on."
-      );
-    }
-
-    info(
-      "Flush out any straggling allocation markers that may have not been " +
-        "collected yet by starting and stopping the profiler once."
-    );
-    startProfiler({ features: ["threads", "leaf"] });
-    await stopProfilerAndGetThreads(contentPid);
-
-    info("Now reload the tab with a clean run.");
-    gBrowser.reload();
-    await wait(100);
-    startProfiler({ features: ["threads", "leaf"] });
-
-    info(
-      "Check that no allocations were recorded, and allocation tracking was " +
-        "correctly turned off."
-    );
-
-    {
-      const { parentThread, contentThread } = await stopProfilerAndGetThreads(
-        contentPid
-      );
-      Assert.equal(
-        getPayloadsOfType(parentThread, "Native allocation").length,
-        0,
-        "No allocations were recorded for the parent processes' main thread when " +
-          "Native allocation was not turned on."
-      );
-
-      Assert.equal(
-        getPayloadsOfType(contentThread, "Native allocation").length,
-        0,
-        "No allocations were recorded for the content processes' main thread when " +
-          "Native allocation was not turned on."
-      );
-    }
-  });
-});
--- a/tools/profiler/tests/shared-head.js
+++ b/tools/profiler/tests/shared-head.js
@@ -103,8 +103,20 @@ function captureAtLeastOneJsSample() {
   const sampleCount = getProfileSampleCount();
   // Create an infinite loop until a sample has been collected.
   while (true) {
     if (sampleCount < getProfileSampleCount()) {
       return sampleCount;
     }
   }
 }
+
+/**
+ * This function pauses the profiler before getting the profile. Then after the
+ * getting the data, the profiler is stopped, and all profiler data is removed.
+ * @returns {Promise<Profile>}
+ */
+async function stopAndGetProfile() {
+  Services.profiler.PauseSampling();
+  const profile = await Services.profiler.getProfileDataAsync();
+  Services.profiler.StopProfiler();
+  return profile;
+}
new file mode 100644
--- /dev/null
+++ b/tools/profiler/tests/xpcshell/test_feature_nativeallocations.js
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+add_task(async () => {
+  if (!AppConstants.MOZ_GECKO_PROFILER) {
+    return;
+  }
+  Assert.ok(
+    !Services.profiler.IsActive(),
+    "The profiler is not currently active"
+  );
+
+  info(
+    "Test that the profiler can install memory hooks and collect native allocation " +
+      "information in the marker payloads."
+  );
+  {
+    info("Start the profiler.");
+    startProfiler({
+      // Increase the entries so we don't overflow the buffer.
+      entries: 1e8,
+      // Only instrument the main thread.
+      threads: ["GeckoMain"],
+      features: ["threads", "leaf", "nativeallocations"],
+    });
+
+    info(
+      "Do some JS work for a little bit. This will increase the amount of allocations " +
+        "that take place."
+    );
+    doWork();
+
+    info(
+      "Go ahead and wait for a periodic sample as well, in order to make sure that " +
+        "the native allocations play nicely with the rest of the profiler machinery."
+    );
+    await Services.profiler.waitOnePeriodicSampling();
+
+    info("Get the profile data and analyze it.");
+    const profile = await stopAndGetProfile();
+
+    const allocationPayloads = getPayloadsOfType(
+      profile.threads[0],
+      "Native allocation"
+    );
+
+    Assert.greater(
+      allocationPayloads.length,
+      0,
+      "Native allocation payloads were recorded for the parent process' main thread when " +
+        "the Native Allocation feature was turned on."
+    );
+  }
+
+  info("Restart the profiler, to ensure that we get no more allocations.");
+  {
+    startProfiler({ features: ["threads", "leaf"] });
+    info("Do some work again.");
+    doWork();
+    info("Wait for the periodic sampling.");
+    await Services.profiler.waitOnePeriodicSampling();
+
+    const profile = await stopAndGetProfile();
+    const allocationPayloads = getPayloadsOfType(
+      profile.threads[0],
+      "Native allocation"
+    );
+
+    Assert.equal(
+      allocationPayloads.length,
+      0,
+      "No native allocations were collected when the feature was disabled."
+    );
+  }
+});
+
+function doWork() {
+  this.n = 0;
+  for (let i = 0; i < 1e5; i++) {
+    this.n += Math.random();
+  }
+}
--- a/tools/profiler/tests/xpcshell/xpcshell.ini
+++ b/tools/profiler/tests/xpcshell/xpcshell.ini
@@ -17,16 +17,17 @@ skip-if = true
 skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1536652
 [test_enterjit_osr_disabling.js]
 skip-if = !debug
 [test_enterjit_osr_enabling.js]
 skip-if = !debug
 [test_asm.js]
 [test_feature_mainthreadio.js]
 skip-if = release_or_beta || (os == "win" && processor == "aarch64") # The IOInterposer is in an ifdef, aarch64 due to 1536657
+[test_feature_nativeallocations.js]
 
 # Native stackwalking is somewhat unreliable depending on the platform.
 #
 # We don't have frame pointers on macOS release and beta, so stack walking does not
 # work. See Bug 1571216 for more details.
 #
 # Linux can be very unreliable when native stackwalking through JavaScript code.
 # See Bug 1434402 for more details.