Skip to content

Customize Force Layout #510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions resources/benchmark-runner.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metric } from "./metric.mjs";
import { params } from "./shared/params.mjs";
import { forceLayout } from "./shared/helpers.mjs";
import { SUITE_RUNNER_LOOKUP } from "./suite-runner.mjs";

const performance = globalThis.performance;
Expand Down Expand Up @@ -30,8 +31,9 @@ class Page {
}

layout() {
const body = this._frame.contentDocument.body.getBoundingClientRect();
this.layout.e = document.elementFromPoint((body.width / 2) | 0, (body.height / 2) | 0);
const body = this._frame ? this._frame.contentDocument.body : document.body;
const value = forceLayout(body, params.layoutMode);
body._leakedLayoutValue = value; // Prevent dead code elimination.
}

async waitForElement(selector) {
Expand Down
28 changes: 27 additions & 1 deletion resources/developer-mode.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Suites, Tags } from "./tests.mjs";
import { params } from "./shared/params.mjs";
import { params, LAYOUT_MODES } from "./shared/params.mjs";

export function createDeveloperModeContainer() {
const container = document.createElement("div");
Expand All @@ -23,6 +23,7 @@ export function createDeveloperModeContainer() {
settings.append(createUIForWarmupBeforeSync());
settings.append(createUIForSyncStepDelay());
settings.append(createUIForAsyncSteps());
settings.append(createUIForLayoutMode());

content.append(document.createElement("hr"));
content.append(settings);
Expand Down Expand Up @@ -114,6 +115,31 @@ function createTimeRangeUI(labelText, paramKey, unit = "ms", min = 0, max = 1000
return label;
}

function createUIForLayoutMode() {
return createSelectUI("Force layout mode", params.layoutMode, LAYOUT_MODES, (value) => {
params.layoutMode = value;
});
}

function createSelectUI(labelValue, initialValue, choices, paramsUpdateCallback) {
const select = document.createElement("select");
select.onchange = () => {
paramsUpdateCallback(select.value);
updateURL();
};

choices.forEach((choice) => {
const option = new Option(choice, choice);
select.add(option);
});
select.value = initialValue;

const label = document.createElement("label");
label.append(span(labelValue), select);

return label;
}

function createUIForSuites() {
const control = document.createElement("nav");
control.className = "suites";
Expand Down
10 changes: 6 additions & 4 deletions resources/shared/helpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ export function getAllElements(selector, path = [], lookupStartNode = document)
return elements;
}

export function forceLayout() {
const rect = document.body.getBoundingClientRect();
const e = document.elementFromPoint((rect.width / 2) | 0, (rect.height / 2) | 0);
return e;
export function forceLayout(body, layoutMode = "getBoundingRectAndElementFromPoint") {
body ??= document.body;
const rect = body.getBoundingClientRect();
if (layoutMode === "getBoundingRectAndElementFromPoint")
return document.elementFromPoint((rect.width / 2) | 0, (rect.height / 2) | 0);
return rect.height;
}
23 changes: 14 additions & 9 deletions resources/shared/params.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const LAYOUT_MODES = Object.freeze(["getBoundingClientRect", "getBoundingRectAndElementFromPoint"]);

export class Params {
viewport = {
width: 800,
Expand Down Expand Up @@ -27,6 +29,8 @@ export class Params {
// "generate": generate a random seed
// <integer>: use the provided integer as a seed
shuffleSeed = "off";
// Choices: "getBoundingClientRect" or "getBoundingRectAndElementFromPoint"
layoutMode = LAYOUT_MODES[0];
// Measure more workload prepare time.
measurePrepare = false;

Expand Down Expand Up @@ -57,8 +61,9 @@ export class Params {
this.useAsyncSteps = this._parseBooleanParam(searchParams, "useAsyncSteps");
this.waitBeforeSync = this._parseIntParam(searchParams, "waitBeforeSync", 0);
this.warmupBeforeSync = this._parseIntParam(searchParams, "warmupBeforeSync", 0);
this.measurementMethod = this._parseMeasurementMethod(searchParams);
this.measurementMethod = this._parseEnumParam(searchParams, "measurementMethod", ["raf"]);
this.shuffleSeed = this._parseShuffleSeed(searchParams);
this.layoutMode = this._parseEnumParam(searchParams, "layoutMode", LAYOUT_MODES);
this.measurePrepare = this._parseBooleanParam(searchParams, "measurePrepare");

const unused = Array.from(searchParams.keys());
Expand Down Expand Up @@ -124,14 +129,14 @@ export class Params {
return tags;
}

_parseMeasurementMethod(searchParams) {
if (!searchParams.has("measurementMethod"))
return defaultParams.measurementMethod;
const measurementMethod = searchParams.get("measurementMethod");
if (measurementMethod !== "raf")
throw new Error(`Invalid measurement method: '${measurementMethod}', must be 'raf'.`);
searchParams.delete("measurementMethod");
return measurementMethod;
_parseEnumParam(searchParams, paramKey, enumArray) {
if (!searchParams.has(paramKey))
return defaultParams[paramKey];
const value = searchParams.get(paramKey);
if (!enumArray.includes(value))
throw new Error(`Got invalid ${paramKey}: '${value}', choices are ${enumArray}`);
searchParams.delete(paramKey);
return value;
}

_parseShuffleSeed(searchParams) {
Expand Down
5 changes: 1 addition & 4 deletions resources/shared/test-runner.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,9 @@ export class TestRunner {
asyncStartTime = syncEndTime;
};
const measureAsync = () => {
const bodyReference = this.#frame ? this.#frame.contentDocument.body : document.body;
const windowReference = this.#frame ? this.#frame.contentWindow : window;
// Some browsers don't immediately update the layout for paint.
// Force the layout here to ensure we're measuring the layout time.
const height = bodyReference.getBoundingClientRect().height;
windowReference._unusedHeightValue = height; // Prevent dead code elimination.
this.page.layout();

const asyncEndTime = performance.now();
performance.mark(asyncEndLabel);
Expand Down