-
Notifications
You must be signed in to change notification settings - Fork 15
New Workload: JSDOM + d3 #124
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
camillobruni
wants to merge
30
commits into
WebKit:main
Choose a base branch
from
camillobruni:2025-08-11_d3
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
24e8065
adding files
camillobruni c924f3f
adding more
camillobruni f5f6127
adding more
camillobruni 2999c23
fix data
camillobruni 8972aa9
re-adding data
camillobruni 8803b58
adding more
camillobruni 9bf6bf2
save
camillobruni 3a318f8
update packages
camillobruni e1711de
cleanup
camillobruni 492d7f8
fixing rendering
camillobruni 005e47e
adding data license files
camillobruni b90a7d7
adding dist LICENSE files
camillobruni 2df0ab3
adidng mock text encoding for smaller package
camillobruni bdac8e0
Merge branch 'main' of github.com:camillobruni/JetStream into 2025-08…
camillobruni b4e8623
update benchmark
camillobruni 47d0a6c
rename
camillobruni 21e164b
remove unused filed3-startup/build/loader.mjs
camillobruni 3b9ec49
fix tags
camillobruni c8aee7f
Merge branch 'main' into 2025-08-11_d3
camillobruni d83c139
move files
camillobruni 7d69135
adding back files
camillobruni 5eef7e3
merge main and warm up hash
camillobruni 2b8b532
Merge branch 'main' into 2025-08-11_d3
camillobruni 1bd445e
Merge branch 'main' into 2025-08-11_d3
camillobruni 3dbb0d1
adding README
camillobruni 26fd058
adding readme
camillobruni 3203291
update
camillobruni 695a6b7
re-adding files
camillobruni d945426
Merge branch 'main' into 2025-08-11_d3
camillobruni c3457a8
use new JetStream global
camillobruni File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2024,6 +2024,22 @@ let BENCHMARKS = [ | |
], | ||
tags: ["Default", "Proxy"], | ||
}), | ||
new AsyncBenchmark({ | ||
name: "jsdom-d3-startup", | ||
files: [ | ||
"./jsdom-d3-startup/benchmark.js", | ||
], | ||
preload: { | ||
// Unminified sources for profiling. | ||
// SOURCE_CODE: "./jsdom-d3-startup/dist/bundle.js", | ||
SOURCE_CODE: "./jsdom-d3-startup/dist/bundle.min.js", | ||
US_DATA: "./jsdom-d3-startup/data/counties-albers-10m.json", | ||
AIRPORTS: "./jsdom-d3-startup/data/airports.csv", | ||
}, | ||
tags: ["d3", "startup", "jsdom"], | ||
iterations: 10, | ||
worstCaseCount: 4, | ||
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. Seems like a high worstCaseCount for the number of iterations. |
||
}), | ||
// Class fields | ||
new DefaultBenchmark({ | ||
name: "raytrace-public-class-fields", | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# JSDOM D3 Startup Benchmark | ||
|
||
The benchmark reads airport and US geography data, then uses D3 to create a Voronoi diagram of the airports overlaid on a map of the US. | ||
It uses jsdom to simulate a browser environment for D3 to render to an SVG element. | ||
|
||
## JetStream integration | ||
- We use a custom `./build/build/cache-buster-comment-plugin.cjs` which injects a known comment into every function in the bundle | ||
- The JetStream benchmark replaces these comments with a unique string per iteration | ||
- Each benchmark iteration includes parse and top-level eval time | ||
|
||
## Setup | ||
```bash | ||
# Install node deps from package-lock.json | ||
npm ci; | ||
# Bundle sources to dist/*. | ||
npm run build | ||
# Use build:dev for non-minified sources. | ||
npm run build:dev | ||
``` | ||
|
||
# Testing | ||
```bash | ||
# Run the basic node benchmark implementation for development. | ||
npm run test | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const { performance } = require('perf_hooks'); | ||
const fs = require('fs'); | ||
const d3 = require('d3'); | ||
|
||
async function main() { | ||
const { runTest } = await import('./src/test.mjs'); | ||
|
||
const usData = JSON.parse(fs.readFileSync('./data/counties-albers-10m.json', 'utf-8')); | ||
const airportsData = fs.readFileSync('.//data/airports.csv', 'utf-8'); | ||
|
||
const startTime = performance.now(); | ||
|
||
const svg = await runTest(airportsData, usData); | ||
|
||
const endTime = performance.now(); | ||
|
||
// console.log(svg); // The SVG output | ||
console.log(`Execution time: ${endTime - startTime} ms`); | ||
} | ||
|
||
main(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Load D3 and data loading utilities for d8 | ||
|
||
function quickHash(str) { | ||
let hash = 5381; | ||
let i = str.length; | ||
while (i > 0) { | ||
hash = (hash * 33) ^ (str.charCodeAt(i) | 0); | ||
i -= 919; | ||
} | ||
return hash | 0; | ||
} | ||
|
||
const CACHE_BUST_COMMENT = "/*ThouShaltNotCache*/"; | ||
const CACHE_BUST_COMMENT_RE = new RegExp(`\n${RegExp.escape(CACHE_BUST_COMMENT)}\n`, "g"); | ||
|
||
const EXPECTED_LAST_RESULT_LENGTH = 691366; | ||
const EXPECTED_LAST_RESULT_HASH = 144487595; | ||
|
||
globalThis.clearTimeout = () => { }; | ||
|
||
class Benchmark { | ||
measureStartup = true; | ||
|
||
sourceCode = ""; | ||
sourceHash = 0; | ||
iterationSourceCodes = []; | ||
lastResult = ""; | ||
currentIteration = 0; | ||
|
||
constructor(iterations) { | ||
this.iterations = iterations; | ||
} | ||
|
||
assert(test, message) { | ||
if (!test) { | ||
throw new Error(message); | ||
} | ||
} | ||
|
||
async init(verbose = 0) { | ||
this.sourceCode = await JetStream.getString(JetStream.preload.SOURCE_CODE); | ||
for (let i = 0; i < this.iterations; i++) | ||
this.iterationSourceCodes[i] = this.prepareCode(i); | ||
|
||
this.airportsCsvString = (await JetStream.getString(JetStream.preload.AIRPORTS)); | ||
this.assert(this.airportsCsvString.length == 145493, `Expected this.airportsCsvString.length to be 141490 but got ${this.airportsCsvString.length}`); | ||
this.usDataJsonString = await JetStream.getString(JetStream.preload.US_DATA); | ||
this.assert(this.usDataJsonString.length == 2880996, `Expected this.usData.length to be 2880996 but got ${this.usDataJsonString.length}`); | ||
this.usData = JSON.parse(this.usDataJsonString); | ||
} | ||
|
||
prepareCode(iteration) { | ||
if (!this.measureStartup) | ||
return this.sourceCode; | ||
// Alter the code per iteration to prevent caching. | ||
const iterationSourceCode = this.sourceCode.replaceAll(CACHE_BUST_COMMENT_RE, `/*${iteration}*/`); | ||
// Warm up hash function. | ||
this.sourceHash = quickHash(iterationSourceCode); | ||
return iterationSourceCode; | ||
} | ||
|
||
runIteration() { | ||
let iterationSourceCode = this.iterationSourceCodes[this.currentIteration]; | ||
if (!iterationSourceCode) | ||
throw new Error(`Could not find source for iteration ${this.currentIteration}`); | ||
// Module in sourceCode it assigned to the ReactRenderTest variable. | ||
let D3Test; | ||
eval(iterationSourceCode); | ||
const html = D3Test.runTest(this.airportsCsvString, this.usData); | ||
this.lastResult = { | ||
html, | ||
htmlHash: quickHash(html), | ||
}; | ||
this.currentIteration++; | ||
} | ||
|
||
validate() { | ||
if (this.lastResult.html.length != EXPECTED_LAST_RESULT_LENGTH) | ||
throw new Error(`Expected this.lastResult.html.length to be ${EXPECTED_LAST_RESULT_LENGTH} but got ${this.lastResult.length}`); | ||
if (this.lastResult.htmlHash != EXPECTED_LAST_RESULT_HASH) | ||
throw new Error(`Expected this.lastResult.htmlHash to be ${EXPECTED_LAST_RESULT_HASH} but got ${this.lastResult.htmlHash}`); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Babel plugin that adds CACHE_BUST_COMMENT to every function body. | ||
const CACHE_BUST_COMMENT = "ThouShaltNotCache"; | ||
|
||
|
||
module.exports = function({ types: t }) { | ||
return { | ||
visitor: { | ||
Function(path) { | ||
const bodyPath = path.get("body"); | ||
// Handle arrow functions: () => "value" | ||
// Convert them to block statements: () => { return "value"; } | ||
if (!bodyPath.isBlockStatement()) { | ||
const newBody = t.blockStatement([t.returnStatement(bodyPath.node)]); | ||
path.set("body", newBody); | ||
} | ||
|
||
// Handle empty function bodies: function foo() {} | ||
// Add an empty statement so we have a first node to attach the comment to. | ||
if (path.get("body.body").length === 0) { | ||
path.get("body").pushContainer("body", t.emptyStatement()); | ||
} | ||
|
||
const firstNode = path.node.body.body[0]; | ||
t.addComment(firstNode, "leading", CACHE_BUST_COMMENT); | ||
|
||
} | ||
}, | ||
}; | ||
}; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
These iterations are pretty fast, it seems like we could do more like 15-20.