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: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2812>
This commit is contained in:
Florian Müllner 2023-06-13 02:13:01 +02:00
parent dbc9ebc6ab
commit 5e93791708
7 changed files with 57 additions and 75 deletions

View File

@ -1,8 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- 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_"] }] */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const St = imports.gi.St; 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. // 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'); console.debug('Running basic perf test');
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
@ -122,27 +118,27 @@ let notificationClosed = false;
let windowPickerShown = false; let windowPickerShown = false;
let appPickerShown = false; let appPickerShown = false;
function script_topBarNavDone() { export function script_topBarNavDone() {
topBarNav = true; topBarNav = true;
} }
function script_notificationShowDone() { export function script_notificationShowDone() {
notificationShown = true; notificationShown = true;
} }
function script_notificationCloseDone() { export function script_notificationCloseDone() {
notificationClosed = true; notificationClosed = true;
} }
function script_overviewShowDone() { export function script_overviewShowDone() {
windowPickerShown = true; windowPickerShown = true;
} }
function script_applicationsShowDone() { export function script_applicationsShowDone() {
appPickerShown = true; appPickerShown = true;
} }
function finish() { export function finish() {
if (!topBarNav) if (!topBarNav)
throw new Error('Failed to navigate top bar'); throw new Error('Failed to navigate top bar');

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported run */
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
@ -8,7 +7,7 @@ const Main = imports.ui.main;
const Scripting = imports.ui.scripting; const Scripting = imports.ui.scripting;
/** Run test. */ /** Run test. */
async function run() { export async function run() {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
/* Make created windows remain visible during exit. */ /* Make created windows remain visible during exit. */

View File

@ -1,8 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- 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"] }] */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
const System = imports.system; 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 // someone should be able to get an idea of how well the shell is performing
// on a particular system. // on a particular system.
var METRICS = { export var METRICS = {
overviewLatencyFirst: { overviewLatencyFirst: {
description: 'Time to first frame after triggering overview, first time', description: 'Time to first frame after triggering overview, first time',
units: 'us', units: 'us',
@ -97,7 +93,7 @@ const WINDOW_CONFIGS = [{
alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha', alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha',
}]; }];
async function run() { export async function run() {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
@ -179,25 +175,25 @@ let haveSwapComplete = false;
let applicationsShowStart; let applicationsShowStart;
let applicationsShowCount = 0; let applicationsShowCount = 0;
function script_overviewShowStart(time) { export function script_overviewShowStart(time) {
showingOverview = true; showingOverview = true;
finishedShowingOverview = false; finishedShowingOverview = false;
overviewShowStart = time; overviewShowStart = time;
overviewFrames = 0; 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 // 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 // need to wait for one more frame to paint before we count
// ourselves as done. // ourselves as done.
finishedShowingOverview = true; finishedShowingOverview = true;
} }
function script_applicationsShowStart(time) { export function script_applicationsShowStart(time) {
applicationsShowStart = time; applicationsShowStart = time;
} }
function script_applicationsShowDone(time) { export function script_applicationsShowDone(time) {
applicationsShowCount++; applicationsShowCount++;
if (applicationsShowCount == 1) if (applicationsShowCount == 1)
METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart; METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
@ -205,14 +201,14 @@ function script_applicationsShowDone(time) {
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart; METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
} }
function script_afterShowHide(_time) { export function script_afterShowHide(_time) {
if (overviewShowCount == 1) if (overviewShowCount == 1)
METRICS.usedAfterOverview.value = mallocUsedSize; METRICS.usedAfterOverview.value = mallocUsedSize;
else else
METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value; METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value;
} }
function malloc_usedSize(time, bytes) { export function malloc_usedSize(time, bytes) {
mallocUsedSize = bytes; mallocUsedSize = bytes;
} }
@ -251,13 +247,13 @@ function _frameDone(time) {
} }
} }
function glx_swapComplete(time, swapTime) { export function glx_swapComplete(time, swapTime) {
haveSwapComplete = true; haveSwapComplete = true;
_frameDone(swapTime); _frameDone(swapTime);
} }
function clutter_stagePaintDone(time) { export function clutter_stagePaintDone(time) {
// If we aren't receiving GLXBufferSwapComplete events, then we approximate // If we aren't receiving GLXBufferSwapComplete events, then we approximate
// the time the user sees a frame with the time we finished doing drawing // 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 // commands for the frame. This doesn't take into account the time for

View File

@ -1,7 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- 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_"] }] */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const GLib = imports.gi.GLib; 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 // This script tests that the shell handles connecting monitors after startup
// is properly handled. // is properly handled.
var METRICS = {}; export var METRICS = {};
let _testMonitor = null; let _testMonitor = null;
/** /**
* init: * init:
*/ */
function init() { export function init() {
global.connect('shutdown', () => { global.connect('shutdown', () => {
_testMonitor?.destroy(); _testMonitor?.destroy();
}); });
@ -51,7 +48,7 @@ function init() {
/** /**
* run: * run:
*/ */
async function run() { export async function run() {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing'); Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding'); Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding');
@ -77,28 +74,28 @@ let overviewShown = false;
/** /**
* script_monitorsChanged: * script_monitorsChanged:
*/ */
function script_monitorsChanged() { export function script_monitorsChanged() {
monitorsChanged = true; monitorsChanged = true;
} }
/** /**
* script_overviewHideDone: * script_overviewHideDone:
*/ */
function script_overviewHideDone() { export function script_overviewHideDone() {
overviewHidden = true; overviewHidden = true;
} }
/** /**
* script_overviewShowDone: * script_overviewShowDone:
*/ */
function script_overviewShowDone() { export function script_overviewShowDone() {
overviewShown = true; overviewShown = true;
} }
/** /**
* finish: * finish:
*/ */
function finish() { export function finish() {
if (!monitorsChanged) if (!monitorsChanged)
throw new Error('Monitors never changed'); throw new Error('Monitors never changed');

View File

@ -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"] }] */ /* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@ -13,7 +5,7 @@ const Shell = imports.gi.Shell;
const Main = imports.ui.main; const Main = imports.ui.main;
const Scripting = imports.ui.scripting; const Scripting = imports.ui.scripting;
var METRICS = { export var METRICS = {
timeToDesktop: { timeToDesktop: {
description: 'Time from starting graphical.target to desktop showing', description: 'Time from starting graphical.target to desktop showing',
units: 'us', units: 'us',
@ -104,7 +96,7 @@ function extractBootTimestamp() {
return result; return result;
} }
async function run() { export async function run() {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("desktopShown", "Finished initial animation"); Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
@ -235,52 +227,52 @@ let redrawTiming;
let redrawTimes = {}; let redrawTimes = {};
let geditLaunchTime; let geditLaunchTime;
function script_desktopShown(time) { export function script_desktopShown(time) {
let bootTimestamp = extractBootTimestamp(); let bootTimestamp = extractBootTimestamp();
METRICS.timeToDesktop.value = time - bootTimestamp; METRICS.timeToDesktop.value = time - bootTimestamp;
} }
function script_overviewShowStart(time) { export function script_overviewShowStart(time) {
overviewShowStart = time; overviewShowStart = time;
} }
function script_overviewShowDone(time) { export function script_overviewShowDone(time) {
METRICS.overviewShowTime.value = time - overviewShowStart; METRICS.overviewShowTime.value = time - overviewShowStart;
} }
function script_applicationsShowStart(time) { export function script_applicationsShowStart(time) {
applicationsShowStart = time; applicationsShowStart = time;
} }
function script_applicationsShowDone(time) { export function script_applicationsShowDone(time) {
METRICS.applicationsShowTime.value = time - applicationsShowStart; METRICS.applicationsShowTime.value = time - applicationsShowStart;
} }
function script_mainViewDrawStart(_time) { export function script_mainViewDrawStart(_time) {
redrawTiming = 'mainView'; redrawTiming = 'mainView';
} }
function script_mainViewDrawDone(_time) { export function script_mainViewDrawDone(_time) {
redrawTiming = null; redrawTiming = null;
} }
function script_overviewDrawStart(_time) { export function script_overviewDrawStart(_time) {
redrawTiming = 'overview'; redrawTiming = 'overview';
} }
function script_overviewDrawDone(_time) { export function script_overviewDrawDone(_time) {
redrawTiming = null; redrawTiming = null;
} }
function script_redrawTestStart(_time) { export function script_redrawTestStart(_time) {
redrawTiming = 'application'; redrawTiming = 'application';
} }
function script_redrawTestDone(_time) { export function script_redrawTestDone(_time) {
redrawTiming = null; redrawTiming = null;
} }
function script_collectTimings(_time) { export function script_collectTimings(_time) {
for (let timing in redrawTimes) { for (let timing in redrawTimes) {
let times = redrawTimes[timing]; let times = redrawTimes[timing];
times.sort((a, b) => a - b); 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; geditLaunchTime = time;
} }
function script_geditFirstFrame(time) { export function script_geditFirstFrame(time) {
METRICS.geditStartTime.value = time - geditLaunchTime; METRICS.geditStartTime.value = time - geditLaunchTime;
} }
function clutter_stagePaintStart(time) { export function clutter_stagePaintStart(time) {
stagePaintStart = time; stagePaintStart = time;
} }
function clutter_paintCompletedTimestamp(time) { export function clutter_paintCompletedTimestamp(time) {
if (redrawTiming != null && stagePaintStart != null) { if (redrawTiming != null && stagePaintStart != null) {
if (!(redrawTiming in redrawTimes)) if (!(redrawTiming in redrawTimes))
redrawTimes[redrawTiming] = []; redrawTimes[redrawTiming] = [];

View File

@ -1,6 +1,6 @@
import {setConsoleLogDomain} from 'console'; import {setConsoleLogDomain} from 'console';
import GLib from 'gi://GLib'; import GLib from 'gi://GLib';
import {exit} from 'system'; import Gio from 'gi://Gio';
setConsoleLogDomain('GNOME Shell'); setConsoleLogDomain('GNOME Shell');
@ -11,12 +11,12 @@ imports.ui.environment.init();
imports._promiseNative.setMainLoopHook(() => { imports._promiseNative.setMainLoopHook(() => {
// Queue starting the shell // Queue starting the shell
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
try { imports.ui.main.start().catch(e => {
imports.ui.main.start(); const error = new GLib.Error(
} catch (e) { Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED,
logError(e); e.message);
exit(1); global.context.terminate_with_error(error);
} });
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });

View File

@ -165,7 +165,8 @@ function _loggingFunc(...args) {
GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields); GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields);
} }
function start() { /** @returns {void} */
async function start() {
globalThis.log = _loggingFunc; globalThis.log = _loggingFunc;
// These are here so we don't break compatibility. // These are here so we don't break compatibility.
@ -190,7 +191,7 @@ function start() {
// Initialize ParentalControlsManager before the UI // Initialize ParentalControlsManager before the UI
ParentalControlsManager.getDefault(); ParentalControlsManager.getDefault();
_initializeUI(); await _initializeUI();
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus(); shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus(); shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus();
@ -205,7 +206,8 @@ function start() {
_sessionUpdated(); _sessionUpdated();
} }
function _initializeUI() { /** @private */
async function _initializeUI() {
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem // also initialize ShellAppSystem first. ShellAppSystem
// needs to load all the .desktop files, and ShellWindowTracker // needs to load all the .desktop files, and ShellWindowTracker
@ -326,7 +328,7 @@ function _initializeUI() {
let perfModule; let perfModule;
const perfModuleName = GLib.getenv('SHELL_PERF_MODULE'); const perfModuleName = GLib.getenv('SHELL_PERF_MODULE');
if (perfModuleName) { if (perfModuleName) {
perfModule = eval(`imports.perf.${perfModuleName};`); perfModule = await import(`../perf/${perfModuleName}.js`);
if (perfModule.init) if (perfModule.init)
perfModule.init(); perfModule.init();
} }