From 5e9379170826f2ba45e6387092e3293023140d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 13 Jun 2023 02:13:01 +0200 Subject: [PATCH] main: Load perf scripts as modules The perf scripts that can be used to script the gnome-shell UI for testing are sufficiently separate from the rest of the code base to allow porting them to ESM modules before the rest of the code base. Part-of: --- js/perf/basic.js | 20 ++++++-------- js/perf/closeWithActiveWindows.js | 3 +-- js/perf/core.js | 24 +++++++---------- js/perf/headlessStart.js | 17 +++++------- js/perf/hwtest.js | 44 +++++++++++++------------------ js/ui/init.js | 14 +++++----- js/ui/main.js | 10 ++++--- 7 files changed, 57 insertions(+), 75 deletions(-) diff --git a/js/perf/basic.js b/js/perf/basic.js index 3fbc0514e..ef75ca423 100644 --- a/js/perf/basic.js +++ b/js/perf/basic.js @@ -1,8 +1,4 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported run, finish, script_topBarNavDone, script_notificationShowDone, - script_notificationCloseDone, script_overviewShowDone, - script_applicationsShowStart, script_applicationsShowDone, METRICS, -*/ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */ const St = imports.gi.St; @@ -13,9 +9,9 @@ const Scripting = imports.ui.scripting; // This script tests the most important (basic) functionality of the shell. -var METRICS = {}; +export var METRICS = {}; -async function run() { +export async function run() { console.debug('Running basic perf test'); /* eslint-disable no-await-in-loop */ @@ -122,27 +118,27 @@ let notificationClosed = false; let windowPickerShown = false; let appPickerShown = false; -function script_topBarNavDone() { +export function script_topBarNavDone() { topBarNav = true; } -function script_notificationShowDone() { +export function script_notificationShowDone() { notificationShown = true; } -function script_notificationCloseDone() { +export function script_notificationCloseDone() { notificationClosed = true; } -function script_overviewShowDone() { +export function script_overviewShowDone() { windowPickerShown = true; } -function script_applicationsShowDone() { +export function script_applicationsShowDone() { appPickerShown = true; } -function finish() { +export function finish() { if (!topBarNav) throw new Error('Failed to navigate top bar'); diff --git a/js/perf/closeWithActiveWindows.js b/js/perf/closeWithActiveWindows.js index 0a2a68f7d..2d696792c 100644 --- a/js/perf/closeWithActiveWindows.js +++ b/js/perf/closeWithActiveWindows.js @@ -1,5 +1,4 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported run */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */ const Clutter = imports.gi.Clutter; @@ -8,7 +7,7 @@ const Main = imports.ui.main; const Scripting = imports.ui.scripting; /** Run test. */ -async function run() { +export async function run() { /* eslint-disable no-await-in-loop */ /* Make created windows remain visible during exit. */ diff --git a/js/perf/core.js b/js/perf/core.js index bd7e220f1..78d17d8c9 100644 --- a/js/perf/core.js +++ b/js/perf/core.js @@ -1,8 +1,4 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported run, script_overviewShowStart, script_overviewShowDone, - script_applicationsShowStart, script_applicationsShowDone, - script_afterShowHide, malloc_usedSize, glx_swapComplete, - clutter_stagePaintDone */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */ const System = imports.system; @@ -15,7 +11,7 @@ const Scripting = imports.ui.scripting; // someone should be able to get an idea of how well the shell is performing // on a particular system. -var METRICS = { +export var METRICS = { overviewLatencyFirst: { description: 'Time to first frame after triggering overview, first time', units: 'us', @@ -97,7 +93,7 @@ const WINDOW_CONFIGS = [{ alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha', }]; -async function run() { +export async function run() { /* eslint-disable no-await-in-loop */ Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); @@ -179,25 +175,25 @@ let haveSwapComplete = false; let applicationsShowStart; let applicationsShowCount = 0; -function script_overviewShowStart(time) { +export function script_overviewShowStart(time) { showingOverview = true; finishedShowingOverview = false; overviewShowStart = time; overviewFrames = 0; } -function script_overviewShowDone(_time) { +export function script_overviewShowDone(_time) { // We've set up the state at the end of the zoom out, but we // need to wait for one more frame to paint before we count // ourselves as done. finishedShowingOverview = true; } -function script_applicationsShowStart(time) { +export function script_applicationsShowStart(time) { applicationsShowStart = time; } -function script_applicationsShowDone(time) { +export function script_applicationsShowDone(time) { applicationsShowCount++; if (applicationsShowCount == 1) METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart; @@ -205,14 +201,14 @@ function script_applicationsShowDone(time) { METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart; } -function script_afterShowHide(_time) { +export function script_afterShowHide(_time) { if (overviewShowCount == 1) METRICS.usedAfterOverview.value = mallocUsedSize; else METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value; } -function malloc_usedSize(time, bytes) { +export function malloc_usedSize(time, bytes) { mallocUsedSize = bytes; } @@ -251,13 +247,13 @@ function _frameDone(time) { } } -function glx_swapComplete(time, swapTime) { +export function glx_swapComplete(time, swapTime) { haveSwapComplete = true; _frameDone(swapTime); } -function clutter_stagePaintDone(time) { +export function clutter_stagePaintDone(time) { // If we aren't receiving GLXBufferSwapComplete events, then we approximate // the time the user sees a frame with the time we finished doing drawing // commands for the frame. This doesn't take into account the time for diff --git a/js/perf/headlessStart.js b/js/perf/headlessStart.js index 1a427be91..6f4157b2b 100644 --- a/js/perf/headlessStart.js +++ b/js/perf/headlessStart.js @@ -1,7 +1,4 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported init, run, finish, script_monitorsChanged, script_overviewHideDone, - script_overviewShowDone, METRICS, -*/ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */ const GLib = imports.gi.GLib; @@ -14,14 +11,14 @@ const Scripting = imports.ui.scripting; // This script tests that the shell handles connecting monitors after startup // is properly handled. -var METRICS = {}; +export var METRICS = {}; let _testMonitor = null; /** * init: */ -function init() { +export function init() { global.connect('shutdown', () => { _testMonitor?.destroy(); }); @@ -51,7 +48,7 @@ function init() { /** * run: */ -async function run() { +export async function run() { /* eslint-disable no-await-in-loop */ Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing'); Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding'); @@ -77,28 +74,28 @@ let overviewShown = false; /** * script_monitorsChanged: */ -function script_monitorsChanged() { +export function script_monitorsChanged() { monitorsChanged = true; } /** * script_overviewHideDone: */ -function script_overviewHideDone() { +export function script_overviewHideDone() { overviewHidden = true; } /** * script_overviewShowDone: */ -function script_overviewShowDone() { +export function script_overviewShowDone() { overviewShown = true; } /** * finish: */ -function finish() { +export function finish() { if (!monitorsChanged) throw new Error('Monitors never changed'); diff --git a/js/perf/hwtest.js b/js/perf/hwtest.js index fab958702..6e4cd7ea2 100644 --- a/js/perf/hwtest.js +++ b/js/perf/hwtest.js @@ -1,11 +1,3 @@ -/* exported run, script_desktopShown, script_overviewShowStart, - script_overviewShowDone, script_applicationsShowStart, - script_applicationsShowDone, script_mainViewDrawStart, - script_mainViewDrawDone, script_overviewDrawStart, - script_overviewDrawDone, script_redrawTestStart, - script_redrawTestDone, script_collectTimings, - script_geditLaunch, script_geditFirstFrame, - clutter_stagePaintStart, clutter_paintCompletedTimestamp */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */ const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; @@ -13,7 +5,7 @@ const Shell = imports.gi.Shell; const Main = imports.ui.main; const Scripting = imports.ui.scripting; -var METRICS = { +export var METRICS = { timeToDesktop: { description: 'Time from starting graphical.target to desktop showing', units: 'us', @@ -104,7 +96,7 @@ function extractBootTimestamp() { return result; } -async function run() { +export async function run() { /* eslint-disable no-await-in-loop */ Scripting.defineScriptEvent("desktopShown", "Finished initial animation"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); @@ -235,52 +227,52 @@ let redrawTiming; let redrawTimes = {}; let geditLaunchTime; -function script_desktopShown(time) { +export function script_desktopShown(time) { let bootTimestamp = extractBootTimestamp(); METRICS.timeToDesktop.value = time - bootTimestamp; } -function script_overviewShowStart(time) { +export function script_overviewShowStart(time) { overviewShowStart = time; } -function script_overviewShowDone(time) { +export function script_overviewShowDone(time) { METRICS.overviewShowTime.value = time - overviewShowStart; } -function script_applicationsShowStart(time) { +export function script_applicationsShowStart(time) { applicationsShowStart = time; } -function script_applicationsShowDone(time) { +export function script_applicationsShowDone(time) { METRICS.applicationsShowTime.value = time - applicationsShowStart; } -function script_mainViewDrawStart(_time) { +export function script_mainViewDrawStart(_time) { redrawTiming = 'mainView'; } -function script_mainViewDrawDone(_time) { +export function script_mainViewDrawDone(_time) { redrawTiming = null; } -function script_overviewDrawStart(_time) { +export function script_overviewDrawStart(_time) { redrawTiming = 'overview'; } -function script_overviewDrawDone(_time) { +export function script_overviewDrawDone(_time) { redrawTiming = null; } -function script_redrawTestStart(_time) { +export function script_redrawTestStart(_time) { redrawTiming = 'application'; } -function script_redrawTestDone(_time) { +export function script_redrawTestDone(_time) { redrawTiming = null; } -function script_collectTimings(_time) { +export function script_collectTimings(_time) { for (let timing in redrawTimes) { let times = redrawTimes[timing]; times.sort((a, b) => a - b); @@ -299,19 +291,19 @@ function script_collectTimings(_time) { } } -function script_geditLaunch(time) { +export function script_geditLaunch(time) { geditLaunchTime = time; } -function script_geditFirstFrame(time) { +export function script_geditFirstFrame(time) { METRICS.geditStartTime.value = time - geditLaunchTime; } -function clutter_stagePaintStart(time) { +export function clutter_stagePaintStart(time) { stagePaintStart = time; } -function clutter_paintCompletedTimestamp(time) { +export function clutter_paintCompletedTimestamp(time) { if (redrawTiming != null && stagePaintStart != null) { if (!(redrawTiming in redrawTimes)) redrawTimes[redrawTiming] = []; diff --git a/js/ui/init.js b/js/ui/init.js index 32d3c68ba..f71a014d3 100644 --- a/js/ui/init.js +++ b/js/ui/init.js @@ -1,6 +1,6 @@ import {setConsoleLogDomain} from 'console'; import GLib from 'gi://GLib'; -import {exit} from 'system'; +import Gio from 'gi://Gio'; setConsoleLogDomain('GNOME Shell'); @@ -11,12 +11,12 @@ imports.ui.environment.init(); imports._promiseNative.setMainLoopHook(() => { // Queue starting the shell GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - try { - imports.ui.main.start(); - } catch (e) { - logError(e); - exit(1); - } + imports.ui.main.start().catch(e => { + const error = new GLib.Error( + Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED, + e.message); + global.context.terminate_with_error(error); + }); return GLib.SOURCE_REMOVE; }); diff --git a/js/ui/main.js b/js/ui/main.js index 5cc6a1ce2..e277224b9 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -165,7 +165,8 @@ function _loggingFunc(...args) { GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields); } -function start() { +/** @returns {void} */ +async function start() { globalThis.log = _loggingFunc; // These are here so we don't break compatibility. @@ -190,7 +191,7 @@ function start() { // Initialize ParentalControlsManager before the UI ParentalControlsManager.getDefault(); - _initializeUI(); + await _initializeUI(); shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus(); shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus(); @@ -205,7 +206,8 @@ function start() { _sessionUpdated(); } -function _initializeUI() { +/** @private */ +async function _initializeUI() { // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will // also initialize ShellAppSystem first. ShellAppSystem // needs to load all the .desktop files, and ShellWindowTracker @@ -326,7 +328,7 @@ function _initializeUI() { let perfModule; const perfModuleName = GLib.getenv('SHELL_PERF_MODULE'); if (perfModuleName) { - perfModule = eval(`imports.perf.${perfModuleName};`); + perfModule = await import(`../perf/${perfModuleName}.js`); if (perfModule.init) perfModule.init(); }