From 102536e7ea1d3dde957b11154b2815c056fd91eb Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Tue, 9 Apr 2019 18:58:37 +0000 Subject: [PATCH] Bug 1541819 - Record allocations of Target class. r=jdescottes This records on Talos the number of allocated objects after creating, attaching and destroying a Tab Target. Depends on D26107 Differential Revision: https://phabricator.services.mozilla.com/D26108 --HG-- extra : moz-landing-system : lando --- devtools/client/framework/moz.build | 1 + .../browser_allocations_target.ini | 10 ++ .../allocations/browser_allocations_target.js | 106 ++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 devtools/client/framework/test/allocations/browser_allocations_target.ini create mode 100644 devtools/client/framework/test/allocations/browser_allocations_target.js diff --git a/devtools/client/framework/moz.build b/devtools/client/framework/moz.build index 487a177fc6cc..1834c46096c1 100644 --- a/devtools/client/framework/moz.build +++ b/devtools/client/framework/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. BROWSER_CHROME_MANIFESTS += [ + 'test/allocations/browser_allocations_target.ini', 'test/browser.ini', 'test/metrics/browser_metrics_debugger.ini', 'test/metrics/browser_metrics_inspector.ini', diff --git a/devtools/client/framework/test/allocations/browser_allocations_target.ini b/devtools/client/framework/test/allocations/browser_allocations_target.ini new file mode 100644 index 000000000000..28cb7642c64b --- /dev/null +++ b/devtools/client/framework/test/allocations/browser_allocations_target.ini @@ -0,0 +1,10 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +support-files = + !/devtools/shared/test-helpers/allocation-tracker.js + +# Each metrics tests is loaded in a separate .ini file. This way the test is executed +# individually, without any other test being executed before or after. +[browser_allocations_target.js] +skip-if = os != 'linux' || debug || asan || pgo # Results should be platform agnostic - only run on linux64-opt diff --git a/devtools/client/framework/test/allocations/browser_allocations_target.js b/devtools/client/framework/test/allocations/browser_allocations_target.js new file mode 100644 index 000000000000..454f06984fcb --- /dev/null +++ b/devtools/client/framework/test/allocations/browser_allocations_target.js @@ -0,0 +1,106 @@ +const TEST_URL = "data:text/html;charset=UTF-8,
Target allocations test
"; + +// Load the tracker very first in order to ensure tracking all objects created by DevTools. +// Loader.jsm shouldn't be loaded, not any other DevTools module until an explicit user action. +let tracker; +{ + const { DevToolsLoader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); + const loader = new DevToolsLoader(); + loader.invisibleToDebugger = true; + const { allocationTracker } = loader.require("chrome://mochitests/content/browser/devtools/shared/test-helpers/allocation-tracker"); + tracker = allocationTracker({ watchDevToolsGlobals: true }); +} + +// So that PERFHERDER data can be extracted from the logs. +SimpleTest.requestCompleteLog(); + +const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); + +const {TargetFactory} = require("devtools/client/framework/target"); + +async function doGC() { + // In order to get stable results, we really have to do 3 GC attempts + // *and* do wait for 1s between each GC. + const numCycles = 3; + for (let i = 0; i < numCycles; i++) { + Cu.forceGC(); + Cu.forceCC(); + await new Promise(resolve => Cu.schedulePreciseShrinkingGC(resolve)); + + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 1000)); + } +} + +async function addTab(url) { + const tab = BrowserTestUtils.addTab(gBrowser, url); + gBrowser.selectedTab = tab; + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + return tab; +} + +async function testScript(tab) { + const target = await TargetFactory.forTab(tab); + await target.attach(); + + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 1000)); + + await target.destroy(); +} + +add_task(async function() { + const tab = await addTab(TEST_URL); + + // Run the test scenario first before recording in order to load all the + // modules. Otherwise they get reported as "still allocated" objects, + // whereas we do expect them to be kept in memory as they are loaded via + // the main DevTools loader, which keeps the module loaded until the + // shutdown of Firefox + await testScript(tab); + + // Do a first pass of GC, to ensure all to-be-freed objects from the first run + // are really freed. + await doGC(); + + // Then, record what was already allocated, which should not be declared + // as potential leaks. For ex, there is all the modules already loaded + // in the main DevTools loader. + const totalBefore = tracker.stillAllocatedObjects(); + + // Now, run the test script. This time, we record this run. + await testScript(tab); + + // After that, re-do some GCs in order to free all what is to-be-freed. + await doGC(); + + // Ensure that Memory API didn't ran out of buffers + ok(!tracker.overflowed, "Allocation were all recorded"); + + // And finally, retrieve the number of objects that are still allocated. + const totalAfter = tracker.stillAllocatedObjects(); + + gBrowser.removeTab(tab); + + const PERFHERDER_DATA = { + framework: { + name: "devtools", + }, + suites: [{ + name: "total-after-gc", + value: totalAfter - totalBefore, + subtests: [ + { + name: "before", + value: totalBefore, + }, + { + name: "after", + value: totalAfter - totalBefore, + }, + ], + }], + }; + info("PERFHERDER_DATA: " + JSON.stringify(PERFHERDER_DATA)); + ok(true, "Test succeeded"); +});