From eb498b98ebe3527b61b82b642a89237dc8a45081 Mon Sep 17 00:00:00 2001 From: Greg Tatum Date: Tue, 6 Oct 2020 13:57:50 +0000 Subject: [PATCH] Bug 1665810 - Add an end-to-end mochitest for DOMEvent markers r=gerald I created a new test file for testing markers in the parent process. It can be re-used to test a variety of different markers and their payloads to ensure they are properly being created, and with relevant information. The idea here is that this tests the entire pipeline, and excercises the code as an end user of the profiler would. Differential Revision: https://phabricator.services.mozilla.com/D92457 --- tools/profiler/tests/browser/browser.ini | 1 + .../browser_test_markers_parent_process.js | 40 +++++++++++++++++++ tools/profiler/tests/shared-head.js | 32 +++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tools/profiler/tests/browser/browser_test_markers_parent_process.js diff --git a/tools/profiler/tests/browser/browser.ini b/tools/profiler/tests/browser/browser.ini index 43cc8f4b118d..3c59197c22e9 100644 --- a/tools/profiler/tests/browser/browser.ini +++ b/tools/profiler/tests/browser/browser.ini @@ -12,5 +12,6 @@ support-files = [browser_test_feature_jsallocations.js] [browser_test_feature_nostacksampling.js] [browser_test_feature_preferencereads.js] +[browser_test_markers_parent_process.js] [browser_test_profile_single_frame_page_info.js] [browser_test_profile_multi_frame_page_info.js] diff --git a/tools/profiler/tests/browser/browser_test_markers_parent_process.js b/tools/profiler/tests/browser/browser_test_markers_parent_process.js new file mode 100644 index 000000000000..177222c3a984 --- /dev/null +++ b/tools/profiler/tests/browser/browser_test_markers_parent_process.js @@ -0,0 +1,40 @@ +/* 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 function test_markers_parent_process() { + info("Test markers that are generated by the browser's parent process."); + if (!AppConstants.MOZ_GECKO_PROFILER) { + return; + } + + info("Start the profiler in nostacksampling mode."); + startProfiler({ features: ["nostacksampling"] }); + + info("Dispatch a DOMEvent"); + window.dispatchEvent(new Event("synthetic")); + + info("Stop the profiler and get the profile."); + const profile = await stopAndGetProfile(); + + const markers = getInflatedMarkerData(profile.threads[0]); + { + const domEventStart = markers.find( + ({ phase, data }) => + phase === INTERVAL_START && data?.eventType === "synthetic" + ); + const domEventEnd = markers.find( + ({ phase, data }) => + phase === INTERVAL_END && data?.eventType === "synthetic" + ); + ok(domEventStart, "A start DOMEvent was generated"); + ok(domEventEnd, "An end DOMEvent was generated"); + ok( + domEventEnd.data.latency > 0, + "DOMEvent had a a latency value generated." + ); + ok(domEventEnd.data.type === "DOMEvent"); + ok(domEventEnd.name === "DOMEvent"); + } + // Add more marker tests. +}); diff --git a/tools/profiler/tests/shared-head.js b/tools/profiler/tests/shared-head.js index d2bb66508c20..1084db55fc4e 100644 --- a/tools/profiler/tests/shared-head.js +++ b/tools/profiler/tests/shared-head.js @@ -6,6 +6,12 @@ * This file contains utilities that can be shared between xpcshell tests and mochitests. */ +// The marker phases. +const INSTANT = 0; +const INTERVAL = 1; +const INTERVAL_START = 2; +const INTERVAL_END = 3; + // This Services declaration may shadow another from head.js, so define it as // a var rather than a const. var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); @@ -18,6 +24,11 @@ const defaultSettings = { }; function startProfiler(callersSettings) { + if (Services.profiler.IsActive()) { + throw new Error( + "The profiler must not be active before starting it in a test." + ); + } const settings = Object.assign({}, defaultSettings, callersSettings); Services.profiler.StartProfiler( settings.entries, @@ -89,6 +100,27 @@ function getPayloadsOfType(thread, type) { return results; } +/** + * Applies the marker schema to create individual objects for each marker + * + * @param {Object} thread The thread from a profile. + * @return {Array} The markers. + */ +function getInflatedMarkerData(thread) { + const { markers, stringTable } = thread; + return markers.data.map(markerTuple => { + const marker = {}; + for (const [key, tupleIndex] of Object.entries(markers.schema)) { + marker[key] = markerTuple[tupleIndex]; + if (key === "name") { + // Use the string from the string table. + marker[key] = stringTable[marker[key]]; + } + } + return marker; + }); +} + /** * It can be helpful to force the profiler to collect a JavaScript sample. This * function spins on a while loop until at least one more sample is collected.