tests: Stop bundling "perf" tests with gnome-shell

Now that scripts are loaded as external modules, there's no reason
anymore for bundling them with the gnome-shell executable. Just
move the scripts into a dedicated folder in tests/ and run them
from there.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2812>
This commit is contained in:
Florian Müllner
2023-06-27 20:27:53 +02:00
parent e4da6a347b
commit e7d290bbfb
7 changed files with 1 additions and 7 deletions

View File

@ -35,12 +35,6 @@
<file>misc/util.js</file>
<file>misc/weather.js</file>
<file>perf/basic.js</file>
<file>perf/closeWithActiveWindows.js</file>
<file>perf/core.js</file>
<file>perf/headlessStart.js</file>
<file>perf/hwtest.js</file>
<file>ui/accessDialog.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>

View File

@ -1,156 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const St = imports.gi.St;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Scripting = imports.ui.scripting;
// This script tests the most important (basic) functionality of the shell.
export var METRICS = {};
export async function run() {
console.debug('Running basic perf test');
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent('topBarNavStart', 'Starting to navigate the top bar');
Scripting.defineScriptEvent('topBarNavDone', 'Done navigating the top bar');
Scripting.defineScriptEvent('notificationShowStart', 'Showing a notification');
Scripting.defineScriptEvent('notificationShowDone', 'Done showing a notification');
Scripting.defineScriptEvent('notificationCloseStart', 'Closing a notification');
Scripting.defineScriptEvent('notificationCloseDone', 'Done closing a notification');
Scripting.defineScriptEvent('overviewShowStart', 'Starting to show the overview');
Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
Scripting.defineScriptEvent('applicationsShowStart', 'Starting to switch to applications view');
Scripting.defineScriptEvent('applicationsShowDone', 'Done switching to applications view');
Main.overview.connect('shown',
() => Scripting.scriptEvent('overviewShowDone'));
await Scripting.sleep(1000);
// navigate through top bar
console.debug('Navigate through top bar');
Scripting.scriptEvent('topBarNavStart');
Main.panel.statusArea.quickSettings.menu.open();
await Scripting.sleep(400);
const { menuManager } = Main.panel;
while (menuManager.activeMenu &&
Main.panel.navigate_focus(menuManager.activeMenu.sourceActor,
St.DirectionType.TAB_BACKWARD, false))
await Scripting.sleep(400);
Scripting.scriptEvent('topBarNavDone');
await Scripting.sleep(1000);
// notification
console.debug('Show notification message');
const source = new MessageTray.SystemNotificationSource();
Main.messageTray.add(source);
Scripting.scriptEvent('notificationShowStart');
source.connect('notification-show',
() => Scripting.scriptEvent('notificationShowDone'));
const notification = new MessageTray.Notification(source,
'A test notification');
source.showNotification(notification);
await Scripting.sleep(400);
console.debug('Show date menu');
Main.panel.statusArea.dateMenu.menu.open();
await Scripting.sleep(400);
Scripting.scriptEvent('notificationCloseStart');
notification.connect('destroy',
() => Scripting.scriptEvent('notificationCloseDone'));
console.debug('Destroy notification message');
notification.destroy();
await Scripting.sleep(400);
console.debug('Close date menu');
Main.panel.statusArea.dateMenu.menu.close();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (window picker)
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (app picker)
console.debug('Showing overview');
Main.overview.show();
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowStart');
console.debug('Showing applications');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
console.debug('Hiding applications');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure();
console.debug('Hiding overview');
Main.overview.hide();
await Scripting.waitLeisure();
/* eslint-enable no-await-in-loop */
console.debug('Finished basic perf test');
}
let topBarNav = false;
let notificationShown = false;
let notificationClosed = false;
let windowPickerShown = false;
let appPickerShown = false;
export function script_topBarNavDone() {
topBarNav = true;
}
export function script_notificationShowDone() {
notificationShown = true;
}
export function script_notificationCloseDone() {
notificationClosed = true;
}
export function script_overviewShowDone() {
windowPickerShown = true;
}
export function script_applicationsShowDone() {
appPickerShown = true;
}
export function finish() {
if (!topBarNav)
throw new Error('Failed to navigate top bar');
if (!notificationShown)
throw new Error('Failed to show notification');
if (!notificationClosed)
throw new Error('Failed to close notification');
if (!windowPickerShown)
throw new Error('Failed to show window picker');
if (!appPickerShown)
throw new Error('Failed to show app picker');
}

View File

@ -1,35 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
/** Run test. */
export async function run() {
/* eslint-disable no-await-in-loop */
/* Make created windows remain visible during exit. */
await Scripting.disableHelperAutoExit();
const seat = Clutter.get_default_backend().get_default_seat();
const virtualDevice_ =
seat.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
Main.overview.hide();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
await Scripting.createTestWindow({
width: 640,
height: 480,
textInput: true,
});
await Scripting.waitTestWindows();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
/* eslint-enable no-await-in-loop */
}

View File

@ -1,267 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
const System = imports.system;
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
// This performance script measure the most important (core) performance
// metrics for the shell. By looking at the output metrics of this script
// someone should be able to get an idea of how well the shell is performing
// on a particular system.
export var METRICS = {
overviewLatencyFirst: {
description: 'Time to first frame after triggering overview, first time',
units: 'us',
},
overviewFpsFirst: {
description: 'Frame rate when going to the overview, first time',
units: 'frames / s',
},
overviewLatencySubsequent: {
description: 'Time to first frame after triggering overview, second time',
units: 'us',
},
overviewFpsSubsequent: {
description: 'Frames rate when going to the overview, second time',
units: 'frames / s',
},
overviewFps5Windows: {
description: 'Frames rate when going to the overview, 5 windows open',
units: 'frames / s',
},
overviewFps10Windows: {
description: 'Frames rate when going to the overview, 10 windows open',
units: 'frames / s',
},
overviewFps5Maximized: {
description: 'Frames rate when going to the overview, 5 maximized windows open',
units: 'frames / s',
},
overviewFps10Maximized: {
description: 'Frames rate when going to the overview, 10 maximized windows open',
units: 'frames / s',
},
overviewFps5Alpha: {
description: 'Frames rate when going to the overview, 5 alpha-transparent windows open',
units: 'frames / s',
},
overviewFps10Alpha: {
description: 'Frames rate when going to the overview, 10 alpha-transparent windows open',
units: 'frames / s',
},
usedAfterOverview: {
description: "Malloc'ed bytes after the overview is shown once",
units: 'B',
},
leakedAfterOverview: {
description: "Additional malloc'ed bytes the second time the overview is shown",
units: 'B',
},
applicationsShowTimeFirst: {
description: 'Time to switch to applications view, first time',
units: 'us',
},
applicationsShowTimeSubsequent: {
description: 'Time to switch to applications view, second time',
units: 'us',
},
};
const WINDOW_CONFIGS = [{
width: 640, height: 480,
alpha: false, maximized: false, count: 1, metric: 'overviewFpsSubsequent',
}, {
width: 640, height: 480,
alpha: false, maximized: false, count: 5, metric: 'overviewFps5Windows',
}, {
width: 640, height: 480,
alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows',
}, {
width: 640, height: 480,
alpha: false, maximized: true, count: 5, metric: 'overviewFps5Maximized',
}, {
width: 640, height: 480,
alpha: false, maximized: true, count: 10, metric: 'overviewFps10Maximized',
}, {
width: 640, height: 480,
alpha: true, maximized: false, count: 5, metric: 'overviewFps5Alpha',
}, {
width: 640, height: 480,
alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha',
}];
export async function run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
// Enable recording of timestamps for different points in the frame cycle
global.frame_timestamps = true;
Main.overview.connect('shown', () => {
Scripting.scriptEvent('overviewShowDone');
});
await Scripting.sleep(1000);
for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
// We go to the overview twice for each configuration; the first time
// to calculate the mipmaps for the windows, the second time to get
// a clean set of numbers.
if ((i % 2) == 0) {
let config = WINDOW_CONFIGS[i / 2];
await Scripting.destroyTestWindows();
for (let k = 0; k < config.count; k++) {
await Scripting.createTestWindow({
width: config.width,
height: config.height,
alpha: config.alpha,
maximized: config.maximized,
});
}
await Scripting.waitTestWindows();
await Scripting.sleep(1000);
await Scripting.waitLeisure();
}
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
System.gc();
await Scripting.sleep(1000);
Scripting.collectStatistics();
Scripting.scriptEvent('afterShowHide');
}
await Scripting.destroyTestWindows();
await Scripting.sleep(1000);
Main.overview.show();
await Scripting.waitLeisure();
for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure();
}
/* eslint-enable no-await-in-loop */
}
let showingOverview = false;
let finishedShowingOverview = false;
let overviewShowStart;
let overviewFrames;
let overviewLatency;
let mallocUsedSize = 0;
let overviewShowCount = 0;
let haveSwapComplete = false;
let applicationsShowStart;
let applicationsShowCount = 0;
export function script_overviewShowStart(time) {
showingOverview = true;
finishedShowingOverview = false;
overviewShowStart = time;
overviewFrames = 0;
}
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;
}
export function script_applicationsShowStart(time) {
applicationsShowStart = time;
}
export function script_applicationsShowDone(time) {
applicationsShowCount++;
if (applicationsShowCount == 1)
METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
else
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
}
export function script_afterShowHide(_time) {
if (overviewShowCount == 1)
METRICS.usedAfterOverview.value = mallocUsedSize;
else
METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value;
}
export function malloc_usedSize(time, bytes) {
mallocUsedSize = bytes;
}
function _frameDone(time) {
if (showingOverview) {
if (overviewFrames == 0)
overviewLatency = time - overviewShowStart;
overviewFrames++;
}
if (finishedShowingOverview) {
showingOverview = false;
finishedShowingOverview = false;
overviewShowCount++;
let dt = (time - (overviewShowStart + overviewLatency)) / 1000000;
// If we see a start frame and an end frame, that would
// be 1 frame for a FPS computation, hence the '- 1'
let fps = (overviewFrames - 1) / dt;
if (overviewShowCount == 1) {
METRICS.overviewLatencyFirst.value = overviewLatency;
METRICS.overviewFpsFirst.value = fps;
} else if (overviewShowCount == 2) {
METRICS.overviewLatencySubsequent.value = overviewLatency;
}
// Other than overviewFpsFirst, we collect FPS metrics the second
// we show each window configuration. overviewShowCount is 1,2,3...
if (overviewShowCount % 2 == 0) {
let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
METRICS[config.metric].value = fps;
}
}
}
export function glx_swapComplete(time, swapTime) {
haveSwapComplete = true;
_frameDone(swapTime);
}
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
// the GPU to finish painting, and the time for waiting for the buffer
// swap, but if this are uniform - every frame takes the same time to draw -
// then it won't upset our FPS calculation, though the latency value
// will be slightly too low.
if (!haveSwapComplete)
_frameDone(time);
}

View File

@ -1,107 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const GLib = imports.gi.GLib;
const MetaTest = imports.gi.MetaTest;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
// This script tests that the shell handles connecting monitors after startup
// is properly handled.
export var METRICS = {};
let _testMonitor = null;
/**
* init:
*/
export function init() {
global.connect('shutdown', () => {
_testMonitor?.destroy();
});
GLib.timeout_add_seconds(
GLib.PRIORITY_LOW, 2,
() => {
log('Connecting 1280x720 test monitor');
_testMonitor = MetaTest.TestMonitor.new(
global.context, 1280, 720, 60.0);
});
Scripting.defineScriptEvent('monitorsChanged', 'Monitors changed');
const display = global.display;
console.assert(display.get_n_monitors() === 0, 'Not running headless');
const monitorManager = global.backend.get_monitor_manager();
const monitorsChangedHandlerId = monitorManager.connect('monitors-changed',
() => {
console.assert(display.get_n_monitors() === 1,
'Expected a single monitor');
Scripting.scriptEvent('monitorsChanged');
monitorManager.disconnect(monitorsChangedHandlerId);
});
Shell.PerfLog.get_default().set_enabled(true);
}
/**
* run:
*/
export async function run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding');
Main.overview.connect('shown',
() => Scripting.scriptEvent('overviewShowDone'));
Main.overview.connect('hidden',
() => Scripting.scriptEvent('overviewHideDone'));
Main.overview.hide();
await Scripting.waitLeisure();
Main.overview.show();
await Scripting.waitLeisure();
/* eslint-enable no-await-in-loop */
}
let monitorsChanged = false;
let overviewHidden = false;
let overviewShown = false;
/**
* script_monitorsChanged:
*/
export function script_monitorsChanged() {
monitorsChanged = true;
}
/**
* script_overviewHideDone:
*/
export function script_overviewHideDone() {
overviewHidden = true;
}
/**
* script_overviewShowDone:
*/
export function script_overviewShowDone() {
overviewShown = true;
}
/**
* finish:
*/
export function finish() {
if (!monitorsChanged)
throw new Error('Monitors never changed');
if (!overviewHidden)
throw new Error('Failed to hide overview');
if (!overviewShown)
throw new Error('Failed to show overview');
}

View File

@ -1,313 +0,0 @@
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
export var METRICS = {
timeToDesktop: {
description: 'Time from starting graphical.target to desktop showing',
units: 'us',
},
overviewShowTime: {
description: 'Time to switch to overview view, first time',
units: 'us',
},
applicationsShowTime: {
description: 'Time to switch to applications view, first time',
units: 'us',
},
mainViewRedrawTime: {
description: 'Time to redraw the main view, full screen',
units: 'us',
},
overviewRedrawTime: {
description: 'Time to redraw the overview, full screen, 5 windows',
units: 'us',
},
applicationRedrawTime: {
description: 'Time to redraw frame with a maximized application update',
units: 'us',
},
geditStartTime: {
description: 'Time from gedit launch to window drawn',
units: 'us',
},
};
function waitAndDraw(milliseconds) {
let cb;
let timeline = new Clutter.Timeline({ duration: milliseconds });
timeline.start();
timeline.connect('new-frame', (_timeline, _frame) => {
global.stage.queue_redraw();
});
timeline.connect('completed', () => {
timeline.stop();
if (cb)
cb();
});
return callback => (cb = callback);
}
function waitSignal(object, signal) {
let cb;
let id = object.connect(signal, () => {
object.disconnect(id);
if (cb)
cb();
});
return callback => (cb = callback);
}
function extractBootTimestamp() {
const sp = Gio.Subprocess.new([
'journalctl', '-b',
'MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5',
'UNIT=graphical.target',
'-o',
'json',
], Gio.SubprocessFlags.STDOUT_PIPE);
let result = null;
let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
while (true) { // eslint-disable-line no-constant-condition
let [line, length_] = datastream.read_line_utf8(null);
if (line === null)
break;
let fields = JSON.parse(line);
result = Number(fields['__MONOTONIC_TIMESTAMP']);
}
datastream.close(null);
return result;
}
export async function run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
Scripting.defineScriptEvent("mainViewDrawStart", "Drawing main view");
Scripting.defineScriptEvent("mainViewDrawDone", "Ending timing main view drawing");
Scripting.defineScriptEvent("overviewDrawStart", "Drawing overview");
Scripting.defineScriptEvent("overviewDrawDone", "Ending timing overview drawing");
Scripting.defineScriptEvent("redrawTestStart", "Drawing application window");
Scripting.defineScriptEvent("redrawTestDone", "Ending timing application window drawing");
Scripting.defineScriptEvent("collectTimings", "Accumulate frame timings from redraw tests");
Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
await Scripting.waitLeisure();
Scripting.scriptEvent('desktopShown');
let interfaceSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.interface',
});
interfaceSettings.set_boolean('enable-animations', false);
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
await Scripting.waitLeisure();
Scripting.scriptEvent('overviewShowDone');
await Scripting.sleep(1000);
Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
await Scripting.sleep(1000);
Main.overview.hide();
await Scripting.waitLeisure();
// --------------------- //
// Tests of redraw speed //
// --------------------- //
global.frame_timestamps = true;
global.frame_finish_timestamp = true;
for (let k = 0; k < 5; k++)
await Scripting.createTestWindow({ maximized: true });
await Scripting.waitTestWindows();
await Scripting.sleep(1000);
Scripting.scriptEvent('mainViewDrawStart');
await waitAndDraw(1000);
Scripting.scriptEvent('mainViewDrawDone');
Main.overview.show();
Scripting.waitLeisure();
await Scripting.sleep(1500);
Scripting.scriptEvent('overviewDrawStart');
await waitAndDraw(1000);
Scripting.scriptEvent('overviewDrawDone');
await Scripting.destroyTestWindows();
Main.overview.hide();
await Scripting.createTestWindow({
maximized: true,
redraws: true,
});
await Scripting.waitTestWindows();
await Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestStart');
await Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestDone');
await Scripting.sleep(1000);
Scripting.scriptEvent('collectTimings');
await Scripting.destroyTestWindows();
global.frame_timestamps = false;
global.frame_finish_timestamp = false;
await Scripting.sleep(1000);
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop');
Scripting.scriptEvent('geditLaunch');
app.activate();
let windows = app.get_windows();
if (windows.length > 0)
throw new Error('gedit was already running');
while (windows.length == 0) {
await waitSignal(global.display, 'window-created');
windows = app.get_windows();
}
let actor = windows[0].get_compositor_private();
await waitSignal(actor, 'first-frame');
Scripting.scriptEvent('geditFirstFrame');
await Scripting.sleep(1000);
windows[0].delete(global.get_current_time());
await Scripting.sleep(1000);
interfaceSettings.set_boolean('enable-animations', true);
/* eslint-enable no-await-in-loop */
}
let overviewShowStart;
let applicationsShowStart;
let stagePaintStart;
let redrawTiming;
let redrawTimes = {};
let geditLaunchTime;
export function script_desktopShown(time) {
let bootTimestamp = extractBootTimestamp();
METRICS.timeToDesktop.value = time - bootTimestamp;
}
export function script_overviewShowStart(time) {
overviewShowStart = time;
}
export function script_overviewShowDone(time) {
METRICS.overviewShowTime.value = time - overviewShowStart;
}
export function script_applicationsShowStart(time) {
applicationsShowStart = time;
}
export function script_applicationsShowDone(time) {
METRICS.applicationsShowTime.value = time - applicationsShowStart;
}
export function script_mainViewDrawStart(_time) {
redrawTiming = 'mainView';
}
export function script_mainViewDrawDone(_time) {
redrawTiming = null;
}
export function script_overviewDrawStart(_time) {
redrawTiming = 'overview';
}
export function script_overviewDrawDone(_time) {
redrawTiming = null;
}
export function script_redrawTestStart(_time) {
redrawTiming = 'application';
}
export function script_redrawTestDone(_time) {
redrawTiming = null;
}
export function script_collectTimings(_time) {
for (let timing in redrawTimes) {
let times = redrawTimes[timing];
times.sort((a, b) => a - b);
let len = times.length;
let median;
if (len == 0)
median = -1;
else if (len % 2 == 1)
median = times[(len - 1) / 2];
else
median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
METRICS[`${timing}RedrawTime`].value = median;
}
}
export function script_geditLaunch(time) {
geditLaunchTime = time;
}
export function script_geditFirstFrame(time) {
METRICS.geditStartTime.value = time - geditLaunchTime;
}
export function clutter_stagePaintStart(time) {
stagePaintStart = time;
}
export function clutter_paintCompletedTimestamp(time) {
if (redrawTiming != null && stagePaintStart != null) {
if (!(redrawTiming in redrawTimes))
redrawTimes[redrawTiming] = [];
redrawTimes[redrawTiming].push(time - stagePaintStart);
}
stagePaintStart = null;
}