-
Notifications
You must be signed in to change notification settings - Fork 76
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
Remote Runner / PostMessge api #456
Changes from 60 commits
614d2f5
c1450fb
4bddce7
a478795
a7c6fb0
28354b4
d1cff87
ee81ce3
0da54a0
627376c
6558c87
a5cf90b
09cf75d
25a8071
33c3f52
7d520e3
c10ac0c
482feec
8a91e44
7c2febb
71368c4
76db526
5eadca4
26f3e04
a8bc24e
36b4dd5
47beb33
2e1e00f
a9e386e
75f9c71
2c49e18
1186f4b
de2c065
f7caf32
35beb33
ae76076
9c8178f
b8d2ec7
b8ec788
671998e
4cbb74c
baaebd8
3aaa5e0
a698688
eddd017
ee3ceb4
849fddd
96353b4
f7038ca
3310491
34991de
99c148a
67820e8
28da4e9
147ec2c
4bfff88
7ec1fe7
2ced0b1
ec2b883
7b395c2
2f3c311
64e414d
428ffb0
ebff15a
544fe16
7280741
c073c4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/ofW8d8vHz4HS9u6cDJv4X/_buildManifest.js" defer=""></script><script src="./_next/static/ofW8d8vHz4HS9u6cDJv4X/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"ofW8d8vHz4HS9u6cDJv4X","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html> | ||
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/0WioSK_GYKwlHihOM6Gxq/_buildManifest.js" defer=""></script><script src="./_next/static/0WioSK_GYKwlHihOM6Gxq/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"0WioSK_GYKwlHihOM6Gxq","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
This file was deleted.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><link rel="preload" href="./_next/static/css/2cf5163b53bb0adb.css" as="style"/><link rel="stylesheet" href="./_next/static/css/2cf5163b53bb0adb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/743-fd706aeabb7828e3.js" defer=""></script><script src="./_next/static/chunks/pages/index-7fd4a7c8e35958df.js" defer=""></script><script src="./_next/static/ofW8d8vHz4HS9u6cDJv4X/_buildManifest.js" defer=""></script><script src="./_next/static/ofW8d8vHz4HS9u6cDJv4X/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"ofW8d8vHz4HS9u6cDJv4X","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html> | ||
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><link rel="preload" href="./_next/static/css/2cf5163b53bb0adb.css" as="style"/><link rel="stylesheet" href="./_next/static/css/2cf5163b53bb0adb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/743-fd706aeabb7828e3.js" defer=""></script><script src="./_next/static/chunks/pages/index-bca4656243ade034.js" defer=""></script><script src="./_next/static/0WioSK_GYKwlHihOM6Gxq/_buildManifest.js" defer=""></script><script src="./_next/static/0WioSK_GYKwlHihOM6Gxq/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"0WioSK_GYKwlHihOM6Gxq","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { BenchmarkStep, BenchmarkSuite, BenchmarkSuitesManager, forceLayout, getElement } from "speedometer-utils/workload-testing-utils.mjs"; | ||
|
||
export function getBenchmarkSuitesManager() { | ||
return new BenchmarkSuitesManager(window.name, [ | ||
new BenchmarkSuite("default", [ | ||
new BenchmarkStep("Navigate-to-US-page", () => { | ||
for (let i = 0; i < 25; i++) { | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
} | ||
|
||
getElement("#navbar-navlist-us-link").click(); | ||
forceLayout(); | ||
}), | ||
new BenchmarkStep("Navigate-to-World-page", () => { | ||
for (let i = 0; i < 25; i++) { | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
} | ||
|
||
getElement("#navbar-navlist-world-link").click(); | ||
forceLayout(); | ||
}), | ||
new BenchmarkStep("Navigate-to-Politics-page", () => { | ||
for (let i = 0; i < 25; i++) { | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
getElement("#navbar-dropdown-toggle").click(); | ||
forceLayout(); | ||
} | ||
|
||
getElement("#navbar-navlist-politics-link").click(); | ||
forceLayout(); | ||
}), | ||
]), | ||
]); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import { TestRunner } from "./test-runner.mjs"; | ||
import { Params } from "./params.mjs"; | ||
|
||
/** | ||
* BenchmarkStep | ||
* | ||
* A single test step, with a common interface to interact with. | ||
*/ | ||
export class BenchmarkStep { | ||
constructor(name, run) { | ||
this.name = name; | ||
this.run = run; | ||
} | ||
|
||
async runAndRecord(params, suite, test, callback) { | ||
const testRunner = new TestRunner(null, null, params, suite, test, callback); | ||
const result = await testRunner.runTest(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need an explicit await here? Can't we just return the result of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, since the RAFTestInvoker has this line:
|
||
return result; | ||
} | ||
} | ||
|
||
/** | ||
* BenchmarkSuite | ||
* | ||
* A single test suite that contains one or more test steps. | ||
*/ | ||
export class BenchmarkSuite { | ||
constructor(name, tests) { | ||
this.name = name; | ||
this.tests = tests; | ||
} | ||
|
||
record(_test, syncTime, asyncTime) { | ||
const total = syncTime + asyncTime; | ||
const results = { | ||
tests: { Sync: syncTime, Async: asyncTime }, | ||
total: total, | ||
}; | ||
|
||
return results; | ||
} | ||
|
||
async runAndRecord(params, onProgress) { | ||
const measuredValues = { | ||
tests: {}, | ||
total: 0, | ||
}; | ||
const suiteStartLabel = `suite-${this.name}-start`; | ||
const suiteEndLabel = `suite-${this.name}-end`; | ||
|
||
performance.mark(suiteStartLabel); | ||
|
||
for (const test of this.tests) { | ||
const result = await test.runAndRecord(params, this, test, this.record); | ||
measuredValues.tests[test.name] = result; | ||
measuredValues.total += result.total; | ||
onProgress?.(test.name); | ||
} | ||
|
||
performance.mark(suiteEndLabel); | ||
performance.measure(`suite-${this.name}`, suiteStartLabel, suiteEndLabel); | ||
|
||
return { | ||
type: "suite-tests-complete", | ||
status: "success", | ||
result: measuredValues, | ||
suitename: this.name, | ||
}; | ||
} | ||
} | ||
|
||
/** | ||
* BenchmarkSuitesManager | ||
* | ||
* A collection of test suites for a single workload. | ||
*/ | ||
export class BenchmarkSuitesManager { | ||
constructor(name, suites) { | ||
this.name = name; | ||
this.suites = suites; | ||
} | ||
|
||
getSuiteByName(name) { | ||
return this.suites.find((suite) => suite.name === name); | ||
} | ||
} | ||
|
||
/** ********************************************************************** | ||
* BenchmarkConnector | ||
* | ||
* postMessage is used to communicate between app and benchmark. | ||
* When the app is ready, an 'app-ready' message is sent to signal that the app can receive instructions. | ||
* | ||
* A prepare script within the apps appends window.name and window.version from the package.json file. | ||
* The appId is build by appending name-version | ||
* It's used as an additional safe-guard to ensure the correct app responds to a message. | ||
*************************************************************************/ | ||
export class BenchmarkConnector { | ||
constructor(benchmarkSuitesManager, name, version) { | ||
this.benchmarkSuitesManager = benchmarkSuitesManager; | ||
this.name = name; | ||
this.version = version; | ||
|
||
if (!name || !version) | ||
console.warn("No name or version supplied, to create a unique appId"); | ||
|
||
this.appId = name && version ? `${name}-${version}` : -1; | ||
this.onMessage = this.onMessage.bind(this); | ||
} | ||
|
||
async onMessage(event) { | ||
if (event.data.id !== this.appId || event.data.key !== "benchmark-connector") | ||
return; | ||
|
||
switch (event.data.type) { | ||
case "benchmark-suite": | ||
// eslint-disable-next-line no-case-declarations | ||
const params = new Params(new URLSearchParams(window.location.search)); | ||
// eslint-disable-next-line no-case-declarations | ||
const { result } = await this.benchmarkSuitesManager.getSuiteByName(event.data.name).runAndRecord(params, (test) => this.sendMessage({ type: "step-complete", status: "success", appId: this.appId, name: this.name, test })); | ||
this.sendMessage({ type: "suite-complete", status: "success", appId: this.appId, result }); | ||
this.disconnect(); | ||
break; | ||
default: | ||
console.error(`Message data type not supported: ${event.data.type}`); | ||
} | ||
} | ||
|
||
sendMessage(message) { | ||
window.top.postMessage(message, "*"); | ||
} | ||
|
||
connect() { | ||
window.addEventListener("message", this.onMessage); | ||
this.sendMessage({ type: "app-ready", status: "success", appId: this.appId }); | ||
} | ||
|
||
disconnect() { | ||
window.removeEventListener("message", this.onMessage); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* Helper Methods | ||
* | ||
* Various methods that are extracted from the Page class. | ||
*/ | ||
export function getParent(lookupStartNode, path) { | ||
lookupStartNode = lookupStartNode.shadowRoot ?? lookupStartNode; | ||
const parent = path.reduce((root, selector) => { | ||
const node = root.querySelector(selector); | ||
return node.shadowRoot ?? node; | ||
}, lookupStartNode); | ||
|
||
return parent; | ||
} | ||
|
||
export function getElement(selector, path = [], lookupStartNode = document) { | ||
const element = getParent(lookupStartNode, path).querySelector(selector); | ||
return element; | ||
} | ||
|
||
export function getAllElements(selector, path = [], lookupStartNode = document) { | ||
const elements = Array.from(getParent(lookupStartNode, path).querySelectorAll(selector)); | ||
return elements; | ||
} | ||
|
||
export function forceLayout() { | ||
const rect = document.body.getBoundingClientRect(); | ||
const e = document.elementFromPoint((rect.width / 2) | 0, (rect.height / 2) | 0); | ||
return e; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "speedometer-utils", | ||
"version": "1.0.0", | ||
"description": "Utility files for Speedometer & Workloads" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
class Params { | ||
export class Params { | ||
viewport = { | ||
width: 800, | ||
height: 600, | ||
|
@@ -146,21 +146,28 @@ class Params { | |
return shuffleSeed; | ||
} | ||
|
||
toSearchParams() { | ||
toSearchParams(forRemote = false) { | ||
const rawParams = { ...this }; | ||
flashdesignory marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rawParams["viewport"] = `${this.viewport.width}x${this.viewport.height}`; | ||
|
||
// Only returning params that are useful for the workload. | ||
// Both, 'suites' and 'tags', are specific to the debug menu. | ||
if (forRemote) { | ||
delete rawParams["suites"]; | ||
delete rawParams["tags"]; | ||
} | ||
flashdesignory marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return new URLSearchParams(rawParams).toString(); | ||
} | ||
} | ||
|
||
export const defaultParams = new Params(); | ||
|
||
const searchParams = new URLSearchParams(window.location.search); | ||
const searchParams = new URLSearchParams(typeof window !== "undefined" ? window.location.search : undefined); | ||
let maybeCustomParams = new Params(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when is it happening that window isn't present? optional nit: use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Next.js throws an error during the build process. |
||
try { | ||
maybeCustomParams = new Params(searchParams); | ||
} catch (e) { | ||
console.error("Invalid URL Param", e, "\nUsing defaults as fallback:", maybeCustomParams); | ||
alert(`Invalid URL Param: ${e}`); | ||
} | ||
export const params = maybeCustomParams; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So a bunch of tests are all going to have their own getBenchmarkSuitesManager?
That would make grep'ing harder. Why not name this after each suite?
e.g.
import { NewsNextSuite } from "@/workload-test.mjs";
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A workload can have multiple suites, but we could name it after the workload.
What's the benefit of renaming it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with the mentioned suites object, which is exported as default, we could easily rename the import if that's desired.