mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Add stress test for Bun.serve() routes hot reloading
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
bun
|
|
||||||
next
|
|
||||||
src/*.mov
|
|
||||||
src/*.blob
|
|
||||||
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
SLEEP_INTERVAL ?= 32
|
|
||||||
SCREEN_WIDTH ?= $(shell system_profiler -json SPDisplaysDataType 2>/dev/null | jq -r '.. | objects | select(.spdisplays_main) | ._spdisplays_pixels | split(" ")[0]')
|
|
||||||
SCREEN_HEIGHT ?= $(shell system_profiler -json SPDisplaysDataType 2>/dev/null | jq -r '.. | objects | select(.spdisplays_main) | ._spdisplays_pixels | split(" ")[2]')
|
|
||||||
PROJECT ?= bun
|
|
||||||
PACKAGE_NAME ?= bun-cli
|
|
||||||
RUN_COUNT ?= 128
|
|
||||||
ENDPOINT ?= /
|
|
||||||
|
|
||||||
ifeq ($(PROJECT),bun)
|
|
||||||
PACKAGE_NAME := bun-cli
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(PROJECT),next)
|
|
||||||
PACKAGE_NAME := next
|
|
||||||
endif
|
|
||||||
|
|
||||||
generate:
|
|
||||||
@killall -9 bun next node || echo ""
|
|
||||||
PROJECT=$(PROJECT) SCREEN_WIDTH=$(SCREEN_WIDTH) SCREEN_HEIGHT=$(SCREEN_HEIGHT) ENDPOINT=$(ENDPOINT) node browser.js
|
|
||||||
|
|
||||||
generate-css-in-js:
|
|
||||||
@killall -9 bun next node || echo ""
|
|
||||||
PROJECT=$(PROJECT) SCREEN_WIDTH=$(SCREEN_WIDTH) SCREEN_HEIGHT=$(SCREEN_HEIGHT) ENDPOINT=/css-in-js node browser.js
|
|
||||||
loop:
|
|
||||||
cp src/colors.css.0 src/colors.css
|
|
||||||
sleep 3
|
|
||||||
osascript -e 'tell application "System Events" to tell process "Chromium"' \
|
|
||||||
-e 'set frontmost to true' \
|
|
||||||
-e 'if windows is not {} then perform action "AXRaise" of item 1 of windows' \
|
|
||||||
-e 'end tell'
|
|
||||||
sleep 0.5
|
|
||||||
cd src; zig run -Doptimize=ReleaseFast ../color-looper.zig -- ./colors.css:0 $(SLEEP_INTERVAL)
|
|
||||||
cp src/colors.css.blob $(PROJECT)/colors.css.blob
|
|
||||||
|
|
||||||
loop-emotion:
|
|
||||||
cp src/css-in-js-styles.0 src/css-in-js-styles.tsx
|
|
||||||
sleep 3
|
|
||||||
osascript -e 'tell application "System Events" to tell process "Chromium"' \
|
|
||||||
-e 'set frontmost to true' \
|
|
||||||
-e 'if windows is not {} then perform action "AXRaise" of item 1 of windows' \
|
|
||||||
-e 'end tell'
|
|
||||||
sleep 0.5
|
|
||||||
cd src; zig run -Doptimize=ReleaseFast ../color-looper.emotion.zig -- ./css-in-js-styles.tsx:0 $(SLEEP_INTERVAL)
|
|
||||||
cp src/css-in-js-styles.tsx.blob $(PROJECT)/css-in-js-styles.blob
|
|
||||||
|
|
||||||
process_video:
|
|
||||||
rm -rf $(FRAMES_DIR); mkdir -p $(FRAMES_DIR); ffmpeg -i src/colors.css.mov -vf fps=120,format=gray $(FRAMES_DIR)/%d.tif
|
|
||||||
|
|
||||||
FRAMES_DIR ?= $(shell mkdir -p ./$(PROJECT)/frames; realpath ./$(PROJECT)/frames)
|
|
||||||
|
|
||||||
TIF_FILES := $(wildcard $(FRAMES_DIR)/*.tif)
|
|
||||||
TXT_FILES := $(wildcard $(FRAMES_DIR)/*.txt)
|
|
||||||
|
|
||||||
OBJ_FILES := $(patsubst $(SRC_DIR)/%.tif,$(OBJ_DIR)/%.txt,$(TIF_FILES))
|
|
||||||
TRIM_FILES := $(patsubst $(SRC_DIR)/%.txt,$(OBJ_DIR)/%.trim,$(TXT_FILES))
|
|
||||||
|
|
||||||
frames: $(OBJ_FILES)
|
|
||||||
|
|
||||||
|
|
||||||
$(FRAMES_DIR)/%.txt: $(FRAMES_DIR)/%.tif
|
|
||||||
tesseract -l eng $< $@
|
|
||||||
|
|
||||||
trim: $(TRIM_FILES) cleanup print
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(FRAMES_DIR)/%.trim: $(FRAMES_DIR)/%.txt
|
|
||||||
(grep "Ran:" $< || echo "\n") >> $(PROJECT)/frames.all
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
sed 's/^Ran: *//' $(PROJECT)/frames.all | tr -d ' ' | sort | uniq > $(PROJECT)/frames.all.clean
|
|
||||||
|
|
||||||
print:
|
|
||||||
PACKAGE_NAME=$(PACKAGE_NAME) SLEEP_INTERVAL=$(SLEEP_INTERVAL) PROJECT=$(PROJECT) OUTFILE=timings/$(PACKAGE_NAME) node read-frames.js
|
|
||||||
|
|
||||||
print-emotion:
|
|
||||||
PACKAGE_NAME=$(PACKAGE_NAME) SLEEP_INTERVAL=$(SLEEP_INTERVAL) PROJECT=$(PROJECT) OUTFILE=timings/emotion_$(PACKAGE_NAME) node read-frames.js
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# CSS Stress Test
|
|
||||||
|
|
||||||
This benchmarks bundler performance for CSS hot reloading.
|
|
||||||
|
|
||||||
## Results
|
|
||||||
|
|
||||||
bun is 14x faster than Next.js at hot reloading CSS.
|
|
||||||
|
|
||||||
```
|
|
||||||
bun v0.0.34
|
|
||||||
Saving every 16ms
|
|
||||||
|
|
||||||
Frame time:
|
|
||||||
50th percentile: 22.2ms
|
|
||||||
75th percentile: 23.9ms
|
|
||||||
90th percentile: 25.3ms
|
|
||||||
95th percentile: 43.6ms
|
|
||||||
99th percentile: 49.1ms
|
|
||||||
Rendered frames: 922 / 1024 (90%)
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
Next.js v11.1.2
|
|
||||||
Saving every 16ms
|
|
||||||
|
|
||||||
Frame time:
|
|
||||||
50th percentile: 312ms
|
|
||||||
75th percentile: 337.6ms
|
|
||||||
90th percentile: 387.7ms
|
|
||||||
95th percentile: 446.9ms
|
|
||||||
99th percentile: 591.7ms
|
|
||||||
Rendered frames: 64 / 1024 (6%)
|
|
||||||
```
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
It times pixels instead of builds. `color-looper.zig` writes color updates and the timestamp to a css file, while simultaneously screen recording a non-headless Chromium instance. After it finishes, it OCRs the video frames and verifies the scanned timestamps against the actual data. This data measures (1) how long each update took from saving to disk up to the pixels visible on the screen and (2) what % of frames were rendered.
|
|
||||||
|
|
||||||
The intent is to be as accurate as possible. Measuring times reported client-side is simpler, but lower accuracy since those times may not correspond to pixels on the screen and do not start from when the data was written to disk (at best, they measure when the filesystem watcher detected the update, but often not that either). `color-looper.zig` must run separately from `browser.js` or the results will be inaccurate.
|
|
||||||
|
|
||||||
It works like this:
|
|
||||||
|
|
||||||
1. `browser.js` loads either bun or Next.js and a Chromium instance opened to the correct webpage
|
|
||||||
2. `color-looper.zig` updates [`./src/colors.css`](./src/colors.css) in a loop up to `1024` times (1024 is arbitrary), sleeping every `16`ms or `32`ms (a CLI arg you can pass it). The `var(--timestamp)` CSS variable contains the UTC timestamp with precision of milliseconds and one extra decimal point
|
|
||||||
3. `color-looper.zig` automatically records the screen via `screencapture` (builtin on macOS) and saves it, along with a `BigUint64Array` containing all the expected timestamps. When it's done, it writes to a designated file on disk which `browser.js` picks up as the signal to close the browser.
|
|
||||||
4. `ffmpeg` converts each frame into a black and white `.tif` file, which `tesseract` then OCRs
|
|
||||||
5. Various cleanup scripts extract the timestamp from each of those OCR'd frames into a single file
|
|
||||||
6. Using the OCR'd data, `./read-frames.js` calculates the 50th, 75th, 90th, 95th, and 99th percentile frame time, along with how many frames were skipped. Frame time is the metric here that matters here because that's how much time elapsed between each update. It includes the artificial sleep interval, so it will not be faster than the sleep interval.
|
|
||||||
|
|
||||||
The script `run.sh` runs all the commands necessary to do this work unattended. It takes awhile though. The slow part is OCR'ing all the frames.
|
|
||||||
|
|
||||||
To run this, you need:
|
|
||||||
|
|
||||||
- `zig`
|
|
||||||
- `bun-cli`
|
|
||||||
- `node`
|
|
||||||
- `tesseract`
|
|
||||||
- `screencapture` (macOS builtin)
|
|
||||||
- `ffmpeg`
|
|
||||||
- `puppeteer` (from the package.json)
|
|
||||||
|
|
||||||
You will need to run `bun bun --use next` first, with `next@11.1.2`. It will only run on macOS due to the dependencies on `screencapture`, how it detects screen resolution (so that Chromium is maximized), and how it auto-focuses Chromium (apple script)
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
const puppeteer = require("puppeteer");
|
|
||||||
const http = require("http");
|
|
||||||
const path = require("path");
|
|
||||||
const url = require("url");
|
|
||||||
const fs = require("fs");
|
|
||||||
const child_process = require("child_process");
|
|
||||||
const serverURL = process.env.TEST_SERVER_URL || "http://localhost:8080";
|
|
||||||
|
|
||||||
if (process.env.PROJECT === "bun") {
|
|
||||||
const bunFlags = [`--origin=${serverURL}`].filter(Boolean);
|
|
||||||
const bunExec = process.env.BUN_BIN || "bun";
|
|
||||||
const bunProcess = child_process.spawn(bunExec, bunFlags, {
|
|
||||||
cwd: process.cwd(),
|
|
||||||
stdio: "ignore",
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
DISABLE_BUN_ANALYTICS: "1",
|
|
||||||
},
|
|
||||||
|
|
||||||
shell: false,
|
|
||||||
});
|
|
||||||
console.log("$", bunExec, bunFlags.join(" "));
|
|
||||||
const isDebug = bunExec.endsWith("-debug");
|
|
||||||
|
|
||||||
// bunProcess.stderr.pipe(process.stderr);
|
|
||||||
// bunProcess.stdout.pipe(process.stdout);
|
|
||||||
bunProcess.once("error", err => {
|
|
||||||
console.error("❌ bun error", err);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
process.on("beforeExit", () => {
|
|
||||||
bunProcess?.kill(0);
|
|
||||||
});
|
|
||||||
} else if (process.env.PROJECT === "next") {
|
|
||||||
const bunProcess = child_process.spawn("./node_modules/.bin/next", ["--port", "8080"], {
|
|
||||||
cwd: process.cwd(),
|
|
||||||
stdio: "ignore",
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
},
|
|
||||||
|
|
||||||
shell: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const delay = new Promise((resolve, reject) => {
|
|
||||||
const watcher = fs.watch(path.resolve(process.cwd(), "src/colors.css.blob"));
|
|
||||||
watcher.once("change", () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve();
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const browser = await puppeteer.launch({
|
|
||||||
headless: false,
|
|
||||||
waitForInitialPage: true,
|
|
||||||
args: [
|
|
||||||
`--window-size=${parseInt(process.env.SCREEN_WIDTH || "1024", 10) / 2},${
|
|
||||||
parseInt(process.env.SCREEN_HEIGHT || "1024", 10) / 2
|
|
||||||
}`,
|
|
||||||
],
|
|
||||||
defaultViewport: {
|
|
||||||
width: parseInt(process.env.SCREEN_WIDTH || "1024", 10) / 2,
|
|
||||||
height: parseInt(process.env.SCREEN_HEIGHT || "1024", 10) / 2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const promises = [];
|
|
||||||
let allTestsPassed = true;
|
|
||||||
|
|
||||||
async function runPage(key) {
|
|
||||||
var page;
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log("Opening page");
|
|
||||||
page = await browser.newPage();
|
|
||||||
|
|
||||||
console.log(`Navigating to "http://localhost:8080/"`);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
await page.goto("http://localhost:8080/", { waitUntil: "load" });
|
|
||||||
break;
|
|
||||||
} catch (exception) {
|
|
||||||
if (!exception.toString().includes("ERR_CONNECTION_REFUSED")) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.bringToFront();
|
|
||||||
|
|
||||||
await delay;
|
|
||||||
|
|
||||||
// runner.stdout.pipe(process.stdout);
|
|
||||||
// runner.stderr.pipe(process.stderr);
|
|
||||||
var didResolve = false;
|
|
||||||
|
|
||||||
console.log(`Completed. Done.`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
await page.close();
|
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return runPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(error =>
|
|
||||||
setTimeout(() => {
|
|
||||||
throw error;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=16 PROJECT=bun node read-frames.js
|
|
||||||
bun
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 22.2ms
|
|
||||||
75th percentile: 23.9ms
|
|
||||||
90th percentile: 25.3ms
|
|
||||||
95th percentile: 43.6ms
|
|
||||||
99th percentile: 49.1ms
|
|
||||||
Rendered frames: 922 / 1024 (90%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=24 PROJECT=bun node read-frames.js
|
|
||||||
bun
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 33.4ms
|
|
||||||
75th percentile: 34.5ms
|
|
||||||
90th percentile: 35.8ms
|
|
||||||
95th percentile: 65.5ms
|
|
||||||
99th percentile: 87.9ms
|
|
||||||
Rendered frames: 937 / 1024 (92%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=32 PROJECT=bun node read-frames.js
|
|
||||||
bun
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 40.7ms
|
|
||||||
75th percentile: 42.3ms
|
|
||||||
90th percentile: 43.5ms
|
|
||||||
95th percentile: 76.4ms
|
|
||||||
99th percentile: 118.8ms
|
|
||||||
Rendered frames: 958 / 1024 (94%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=8 PROJECT=bun node read-frames.js
|
|
||||||
bun
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 20ms
|
|
||||||
75th percentile: 24.4ms
|
|
||||||
90th percentile: 41ms
|
|
||||||
95th percentile: 53.9ms
|
|
||||||
99th percentile: 90.4ms
|
|
||||||
Rendered frames: 475 / 1024 (46%)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,218 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const Counter = extern struct {
|
|
||||||
timestamp: usize,
|
|
||||||
percent: f64,
|
|
||||||
rotate: u32,
|
|
||||||
color_values: [8 * 3]u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
const RUN_COUNT = 1024;
|
|
||||||
|
|
||||||
var counters: [RUN_COUNT]Counter = undefined;
|
|
||||||
|
|
||||||
pub const Blob = extern struct {
|
|
||||||
run_count: u32,
|
|
||||||
interval: u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub var all_timestamps: [RUN_COUNT + 1]usize = undefined;
|
|
||||||
|
|
||||||
// usage:
|
|
||||||
// ./file-path:0 10
|
|
||||||
// 1 2 3
|
|
||||||
|
|
||||||
// 1. file path
|
|
||||||
// 2. Byte offset in file
|
|
||||||
// 3. ms update interval
|
|
||||||
var color_buf: [8192 + SIMULATE_LONG_FILE.len]u8 = undefined;
|
|
||||||
|
|
||||||
pub fn main() anyerror!void {
|
|
||||||
var allocator = std.heap.c_allocator;
|
|
||||||
var timer = try std.time.Timer.start();
|
|
||||||
|
|
||||||
var args = std.mem.span(try std.process.argsAlloc(allocator));
|
|
||||||
|
|
||||||
var basepath_with_colon: []u8 = args[args.len - 2];
|
|
||||||
var basepath: []u8 = "";
|
|
||||||
var position_str: []u8 = "";
|
|
||||||
if (std.mem.lastIndexOfScalar(u8, basepath_with_colon, ':')) |colon| {
|
|
||||||
basepath = basepath_with_colon[0..colon];
|
|
||||||
position_str = basepath_with_colon[colon + 1 ..];
|
|
||||||
}
|
|
||||||
var position = try std.fmt.parseInt(u32, position_str, 10);
|
|
||||||
const filepath = try std.fs.path.resolve(allocator, &.{basepath});
|
|
||||||
var file = try std.fs.openFileAbsolute(filepath, .{ .write = true });
|
|
||||||
var ms = @as(u64, @truncate((try std.fmt.parseInt(u128, args[args.len - 1], 10)) * std.time.ns_per_ms));
|
|
||||||
std.debug.assert(ms > 0);
|
|
||||||
// std.debug.assert(std.math.isFinite(position));
|
|
||||||
var prng = std.rand.DefaultPrng.init(0);
|
|
||||||
var stdout = std.io.getStdOut();
|
|
||||||
var log = stdout.writer();
|
|
||||||
var colors = std.mem.zeroes([4][3]u32);
|
|
||||||
var progress_bar: f64 = 0.0;
|
|
||||||
var destination_count: f64 = 18.0;
|
|
||||||
|
|
||||||
// Randomize initial colors
|
|
||||||
colors[0][0] = prng.random.int(u32);
|
|
||||||
colors[0][1] = prng.random.int(u32);
|
|
||||||
colors[0][2] = prng.random.int(u32);
|
|
||||||
|
|
||||||
colors[1][0] = prng.random.int(u32);
|
|
||||||
colors[1][1] = prng.random.int(u32);
|
|
||||||
colors[1][2] = prng.random.int(u32);
|
|
||||||
|
|
||||||
colors[2][0] = prng.random.int(u32);
|
|
||||||
colors[2][1] = prng.random.int(u32);
|
|
||||||
colors[2][2] = prng.random.int(u32);
|
|
||||||
|
|
||||||
colors[3][0] = prng.random.int(u32);
|
|
||||||
colors[3][1] = prng.random.int(u32);
|
|
||||||
colors[3][2] = prng.random.int(u32);
|
|
||||||
var rotate: u32 = 0;
|
|
||||||
var counter: usize = 0;
|
|
||||||
const video = std.fmt.allocPrint(allocator, "{s}.mov", .{filepath}) catch unreachable;
|
|
||||||
std.fs.deleteFileAbsolute(video) catch {};
|
|
||||||
var screen_recorder_argv = [_][]const u8{ "screencapture", "-v", video };
|
|
||||||
|
|
||||||
var recorder = std.ChildProcess.init(&screen_recorder_argv, allocator);
|
|
||||||
recorder.stdin_behavior = .Pipe;
|
|
||||||
try recorder.spawn();
|
|
||||||
std.time.sleep(std.time.ns_per_s);
|
|
||||||
var wrote: []u8 = undefined;
|
|
||||||
while (counter < RUN_COUNT) {
|
|
||||||
colors[0][0] += 1;
|
|
||||||
colors[0][1] += 1;
|
|
||||||
colors[0][2] += 1;
|
|
||||||
colors[1][0] += 1;
|
|
||||||
colors[1][1] += 1;
|
|
||||||
colors[1][2] += 1;
|
|
||||||
colors[2][0] += 1;
|
|
||||||
colors[2][1] += 1;
|
|
||||||
colors[2][2] += 1;
|
|
||||||
colors[3][0] += 1;
|
|
||||||
colors[3][1] += 1;
|
|
||||||
colors[3][2] += 1;
|
|
||||||
rotate += 1;
|
|
||||||
const fmtd: []const u8 = comptime brk: {
|
|
||||||
break :brk (
|
|
||||||
\\
|
|
||||||
\\import {{ Global }} from "@emotion/react";
|
|
||||||
\\export function CSSInJSStyles() {{
|
|
||||||
\\ return (
|
|
||||||
\\ <Global
|
|
||||||
\\ styles={{`
|
|
||||||
\\:root {{
|
|
||||||
\\ --timestamp: "{d}";
|
|
||||||
\\ --interval: "{s}";
|
|
||||||
\\ --progress-bar: {d}%;
|
|
||||||
\\ --spinner-1-muted: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-1-primary: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-2-muted: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-2-primary: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-3-muted: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-3-primary: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-4-muted: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-4-primary: rgb({d}, {d}, {d});
|
|
||||||
\\ --spinner-rotate: {d}deg;
|
|
||||||
\\}}
|
|
||||||
++ SIMULATE_LONG_FILE ++
|
|
||||||
\\ `}}
|
|
||||||
\\ />
|
|
||||||
\\ );
|
|
||||||
\\}}
|
|
||||||
\\
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
counters[counter].timestamp = @as(u64, @truncate(@as(u128, @intCast(std.time.nanoTimestamp())) / (std.time.ns_per_ms / 10)));
|
|
||||||
counters[counter].rotate = rotate % 360;
|
|
||||||
counters[counter].percent = std.math.mod(f64, std.math.round(((progress_bar + 1.0) / destination_count) * 1000) / 1000, 100) catch 0;
|
|
||||||
counters[counter].color_values[0] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[0][0] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[1] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[0][1] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[2] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[0][2] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[3] = (colors[0][0] + 1) % 256;
|
|
||||||
counters[counter].color_values[4] = (colors[0][1] + 1) % 256;
|
|
||||||
counters[counter].color_values[5] = (colors[0][2] + 1) % 256;
|
|
||||||
counters[counter].color_values[6] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[1][0] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[7] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[1][1] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[8] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[1][2] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[9] = (colors[1][0] + 1) % 256;
|
|
||||||
counters[counter].color_values[10] = (colors[1][1] + 1) % 256;
|
|
||||||
counters[counter].color_values[11] = (colors[1][2] + 1) % 256;
|
|
||||||
counters[counter].color_values[12] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[2][0] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[13] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[2][1] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[14] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[2][2] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[15] = (colors[2][0] + 1) % 256;
|
|
||||||
counters[counter].color_values[16] = (colors[2][1] + 1) % 256;
|
|
||||||
counters[counter].color_values[17] = (colors[2][2] + 1) % 256;
|
|
||||||
counters[counter].color_values[18] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[3][0] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[19] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[3][1] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[20] = @as(u32, @intFromFloat(std.math.round(@as(f64, @floatFromInt(((colors[3][2] + 1) % 256))) * 0.8)));
|
|
||||||
counters[counter].color_values[21] = (colors[3][0] + 1) % 256;
|
|
||||||
counters[counter].color_values[22] = (colors[3][1] + 1) % 256;
|
|
||||||
counters[counter].color_values[23] = (colors[3][2] + 1) % 256;
|
|
||||||
|
|
||||||
file = try std.fs.createFileAbsolute(filepath, .{ .truncate = true });
|
|
||||||
wrote = try std.fmt.bufPrint(&color_buf, fmtd, .{
|
|
||||||
counters[counter].timestamp,
|
|
||||||
args[args.len - 1],
|
|
||||||
counters[counter].percent,
|
|
||||||
counters[counter].color_values[0],
|
|
||||||
counters[counter].color_values[1],
|
|
||||||
counters[counter].color_values[2],
|
|
||||||
counters[counter].color_values[3],
|
|
||||||
counters[counter].color_values[4],
|
|
||||||
counters[counter].color_values[5],
|
|
||||||
counters[counter].color_values[6],
|
|
||||||
counters[counter].color_values[7],
|
|
||||||
counters[counter].color_values[8],
|
|
||||||
counters[counter].color_values[9],
|
|
||||||
counters[counter].color_values[10],
|
|
||||||
counters[counter].color_values[11],
|
|
||||||
counters[counter].color_values[12],
|
|
||||||
counters[counter].color_values[13],
|
|
||||||
counters[counter].color_values[14],
|
|
||||||
counters[counter].color_values[15],
|
|
||||||
counters[counter].color_values[16],
|
|
||||||
counters[counter].color_values[17],
|
|
||||||
counters[counter].color_values[18],
|
|
||||||
counters[counter].color_values[19],
|
|
||||||
counters[counter].color_values[20],
|
|
||||||
counters[counter].color_values[21],
|
|
||||||
counters[counter].color_values[22],
|
|
||||||
counters[counter].color_values[23],
|
|
||||||
counters[counter].rotate,
|
|
||||||
});
|
|
||||||
progress_bar += 1.0;
|
|
||||||
_ = try file.writeAll(wrote);
|
|
||||||
|
|
||||||
try log.print("[{d}] \"{s}\":{d}\n", .{
|
|
||||||
std.time.nanoTimestamp(),
|
|
||||||
filepath,
|
|
||||||
position,
|
|
||||||
});
|
|
||||||
counter += 1;
|
|
||||||
// If we don't close the file, Parcel seems to never recognize it
|
|
||||||
file.close();
|
|
||||||
std.time.sleep(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
try recorder.stdin.?.writeAll(&[_]u8{ 3, ';' });
|
|
||||||
|
|
||||||
_ = try recorder.wait();
|
|
||||||
|
|
||||||
all_timestamps[0] = wrote.len;
|
|
||||||
for (counters, 0..) |count, i| {
|
|
||||||
all_timestamps[i + 1] = count.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
std.time.sleep(std.time.ns_per_s);
|
|
||||||
var blob_file = try std.fs.createFileAbsolute(std.fmt.allocPrint(std.heap.c_allocator, "{s}.blob", .{filepath}) catch unreachable, .{ .truncate = true });
|
|
||||||
try blob_file.writeAll(std.mem.asBytes(&all_timestamps));
|
|
||||||
blob_file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
const SIMULATE_LONG_FILE =
|
|
||||||
\\
|
|
||||||
;
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;700&family=Space+Mono:wght@400;700&display=swap"
|
|
||||||
/>
|
|
||||||
<link rel="stylesheet" href="src/index.css" />
|
|
||||||
<script async src="src/index.tsx" type="module"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="reactroot"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
export { React };
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/types/global" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
swcLoader: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=16 PROJECT=next node read-frames.js
|
|
||||||
next
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 312ms
|
|
||||||
75th percentile: 337.6ms
|
|
||||||
90th percentile: 387.7ms
|
|
||||||
95th percentile: 446.9ms
|
|
||||||
99th percentile: 591.7ms
|
|
||||||
Rendered frames: 64 / 1024 (6%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=24 PROJECT=next node read-frames.js
|
|
||||||
next
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 310.1ms
|
|
||||||
75th percentile: 360.3ms
|
|
||||||
90th percentile: 461.6ms
|
|
||||||
95th percentile: 660.4ms
|
|
||||||
99th percentile: 1009.9ms
|
|
||||||
Rendered frames: 78 / 1024 (8%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=32 PROJECT=next node read-frames.js
|
|
||||||
next
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 306.7ms
|
|
||||||
75th percentile: 324.7ms
|
|
||||||
90th percentile: 380ms
|
|
||||||
95th percentile: 483.6ms
|
|
||||||
99th percentile: 933.6ms
|
|
||||||
Rendered frames: 116 / 1024 (11%)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SLEEP_INTERVAL=8 PROJECT=next node read-frames.js
|
|
||||||
next
|
|
||||||
--------------------------------------------------
|
|
||||||
CSS HMR FRAME TIME
|
|
||||||
|
|
||||||
50th percentile: 320.4ms
|
|
||||||
75th percentile: 368.8ms
|
|
||||||
90th percentile: 527.2ms
|
|
||||||
95th percentile: 532.4ms
|
|
||||||
99th percentile: 532.4ms
|
|
||||||
Rendered frames: 32 / 1024 (3%)
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "simple-react",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@emotion/core": "latest",
|
|
||||||
"@emotion/css": "latest",
|
|
||||||
"@emotion/react": "latest",
|
|
||||||
"@vitejs/plugin-react-refresh": "^1.3.3",
|
|
||||||
"antd": "^4.16.1",
|
|
||||||
"bun-framework-next": "latest",
|
|
||||||
"left-pad": "^1.3.0",
|
|
||||||
"next": "^12",
|
|
||||||
"parcel": "2.0.0-beta.3",
|
|
||||||
"path-browserify": "^1.0.1",
|
|
||||||
"percentile": "^1.5.0",
|
|
||||||
"puppeteer": "^10.4.0",
|
|
||||||
"puppeteer-video-recorder": "^1.0.5",
|
|
||||||
"react": "^17.0.2",
|
|
||||||
"react-bootstrap": "^1.6.1",
|
|
||||||
"react-dom": "^17.0.2",
|
|
||||||
"react-form": "^4.0.1",
|
|
||||||
"react-hook-form": "^7.8.3",
|
|
||||||
"url": "^0.11.0",
|
|
||||||
"wipwipwipwip-next-donotuse": "4.0.0"
|
|
||||||
},
|
|
||||||
"parcel": "parceldist/index.js",
|
|
||||||
"targets": {
|
|
||||||
"parcel": {
|
|
||||||
"outputFormat": "esmodule",
|
|
||||||
"sourceMap": false,
|
|
||||||
"optimize": false,
|
|
||||||
"engines": {
|
|
||||||
"chrome": "last 1 version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
|
||||||
"@snowpack/plugin-react-refresh": "^2.5.0",
|
|
||||||
"typescript": "^4.3.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import "../src/index.css";
|
|
||||||
|
|
||||||
import App from "next/app";
|
|
||||||
|
|
||||||
class MyApp extends App {
|
|
||||||
render() {
|
|
||||||
const { Component, pageProps } = this.props;
|
|
||||||
return <Component {...pageProps} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyApp;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Main } from "src/main";
|
|
||||||
export function IndexPage() {
|
|
||||||
return (
|
|
||||||
<Main
|
|
||||||
productName={
|
|
||||||
// @ts-ignore
|
|
||||||
typeof location !== "undefined" ? location.search.substring(1) : ""
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IndexPage;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default as React } from "react";
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const path = require("path");
|
|
||||||
const PROJECT = process.env.PROJECT || "bun";
|
|
||||||
const percentile = require("percentile");
|
|
||||||
const PACKAGE_NAME = process.env.PACKAGE_NAME;
|
|
||||||
const label = `${PACKAGE_NAME}@${require(PACKAGE_NAME + "/package.json").version}`;
|
|
||||||
|
|
||||||
const BASEFOLDER = path.resolve(PROJECT);
|
|
||||||
const OUTFILE = path.join(process.cwd(), process.env.OUTFILE);
|
|
||||||
|
|
||||||
const buf = fs.readFileSync(BASEFOLDER + "/colors.css.blob");
|
|
||||||
const VALID_TIMES = new BigUint64Array(buf.buffer).subarray(1);
|
|
||||||
const cssFileSize = new BigUint64Array(buf.buffer)[0];
|
|
||||||
|
|
||||||
const TOTAL_FRAMES = VALID_TIMES.length;
|
|
||||||
|
|
||||||
const timings = fs
|
|
||||||
.readFileSync(BASEFOLDER + "/frames.all.clean", "utf8")
|
|
||||||
.split("\n")
|
|
||||||
.map(a => a.replace(/[Ran:'\.]?/gm, "").trim())
|
|
||||||
.filter(a => parseInt(a, 10))
|
|
||||||
.filter(a => a.length > 0 && VALID_TIMES.includes(BigInt(parseInt(a, 10))))
|
|
||||||
.map(num => BigInt(num));
|
|
||||||
|
|
||||||
timings.sort();
|
|
||||||
|
|
||||||
const frameTimesCount = timings.length;
|
|
||||||
|
|
||||||
var frameTime = new Array(Math.floor(frameTimesCount / 2));
|
|
||||||
|
|
||||||
for (let i = 0; i < frameTime.length; i++) {
|
|
||||||
const i1 = i * 2;
|
|
||||||
const i2 = i * 2 + 1;
|
|
||||||
|
|
||||||
frameTime[i] = Math.max(Number(timings[i2] - timings[i1]), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const report = {
|
|
||||||
label,
|
|
||||||
cssFileSize: Number(cssFileSize),
|
|
||||||
at: new Date().toISOString(),
|
|
||||||
sleep: process.env.SLEEP_INTERVAL,
|
|
||||||
package: {
|
|
||||||
name: PACKAGE_NAME,
|
|
||||||
version: require(PACKAGE_NAME + "/package.json").version,
|
|
||||||
},
|
|
||||||
timestamps: timings.map(a => Number(a)),
|
|
||||||
frameTimes: frameTime,
|
|
||||||
percentileMs: {
|
|
||||||
50: percentile(50, frameTime) / 10,
|
|
||||||
75: percentile(75, frameTime) / 10,
|
|
||||||
90: percentile(90, frameTime) / 10,
|
|
||||||
95: percentile(95, frameTime) / 10,
|
|
||||||
99: percentile(99, frameTime) / 10,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(
|
|
||||||
path.dirname(OUTFILE),
|
|
||||||
path.basename(OUTFILE) +
|
|
||||||
"@" +
|
|
||||||
report.package.version +
|
|
||||||
"." +
|
|
||||||
process.env.SLEEP_INTERVAL +
|
|
||||||
"ms." +
|
|
||||||
`${process.platform}-${process.arch === "arm64" ? "aarch64" : process.arch}` +
|
|
||||||
".json",
|
|
||||||
),
|
|
||||||
JSON.stringify(report, null, 2),
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
label + "\n",
|
|
||||||
"-".repeat(50) + "\n",
|
|
||||||
"CSS HMR FRAME TIME\n" + "\n",
|
|
||||||
|
|
||||||
"50th percentile:",
|
|
||||||
percentile(50, frameTime) / 10 + "ms",
|
|
||||||
"\n",
|
|
||||||
"75th percentile:",
|
|
||||||
percentile(75, frameTime) / 10 + "ms",
|
|
||||||
"\n",
|
|
||||||
"90th percentile:",
|
|
||||||
percentile(90, frameTime) / 10 + "ms",
|
|
||||||
"\n",
|
|
||||||
"95th percentile:",
|
|
||||||
percentile(95, frameTime) / 10 + "ms",
|
|
||||||
"\n",
|
|
||||||
"99th percentile:",
|
|
||||||
percentile(99, frameTime) / 10 + "ms",
|
|
||||||
"\n",
|
|
||||||
"Rendered frames:",
|
|
||||||
timings.length,
|
|
||||||
"/",
|
|
||||||
TOTAL_FRAMES,
|
|
||||||
"(" + Math.round(Math.max(Math.min(1.0, timings.length / TOTAL_FRAMES), 0) * 100) + "%)",
|
|
||||||
);
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
echo "Running next at 24ms"
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make generate &
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make process_video
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make frames -j$(nproc)
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make trim
|
|
||||||
cp src/colors.css.blob next/colors.css.blob
|
|
||||||
PROJECT=next SLEEP_INTERVAL=24 make print > "next.latest.24ms.txt"
|
|
||||||
|
|
||||||
echo "Running bun at 24ms"
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make generate &
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make process_video
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make frames -j$(nproc)
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make trim
|
|
||||||
cp src/colors.css.blob bun/colors.css.blob
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=24 make print > "bun.latest.24ms.txt"
|
|
||||||
|
|
||||||
echo "Running next at 16ms"
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make generate &
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make process_video
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make frames -j$(nproc)
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make trim
|
|
||||||
cp src/colors.css.blob next/colors.css.blob
|
|
||||||
PROJECT=next SLEEP_INTERVAL=16 make print > "next.latest.16ms.txt"
|
|
||||||
|
|
||||||
echo "Running bun at 16ms"
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make generate &
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make process_video
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make frames -j$(nproc)
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make trim
|
|
||||||
cp src/colors.css.blob bun/colors.css.blob
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=16 make print > "bun.latest.16ms.txt"
|
|
||||||
|
|
||||||
echo "Running bun at 8ms"
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make generate &
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make process_video
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make frames -j$(nproc)
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make trim
|
|
||||||
cp src/colors.css.blob bun/colors.css.blob
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=8 make print > "bun.latest.8ms.txt"
|
|
||||||
|
|
||||||
|
|
||||||
echo "Running next at 8ms"
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make generate &
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make process_video
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make frames -j$(nproc)
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make trim
|
|
||||||
cp src/colors.css.blob next/colors.css.blob
|
|
||||||
PROJECT=next SLEEP_INTERVAL=8 make print > "next.latest.8ms.txt"
|
|
||||||
|
|
||||||
echo "Running bun at 32ms"
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make generate &
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make process_video
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make frames -j$(nproc)
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make trim
|
|
||||||
cp src/colors.css.blob bun/colors.css.blob
|
|
||||||
PROJECT=bun SLEEP_INTERVAL=32 make print > "bun.latest.32ms.txt"
|
|
||||||
|
|
||||||
echo "Running next at 32ms"
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make generate &
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make loop
|
|
||||||
killall Chromium || echo "";
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make process_video
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make frames -j$(nproc)
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make trim
|
|
||||||
cp src/colors.css.blob next/colors.css.blob
|
|
||||||
PROJECT=next SLEEP_INTERVAL=32 make print > "next.latest.32ms.txt"
|
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
:root {
|
|
||||||
--timestamp: "0";
|
|
||||||
--interval: "8";
|
|
||||||
--progress-bar: 0%;
|
|
||||||
--spinner-1-muted: rgb(179, 6, 202);
|
|
||||||
--spinner-1-primary: rgb(224, 8, 253);
|
|
||||||
--spinner-2-muted: rgb(22, 188, 124);
|
|
||||||
--spinner-2-primary: rgb(27, 235, 155);
|
|
||||||
--spinner-3-muted: rgb(89, 72, 0);
|
|
||||||
--spinner-3-primary: rgb(111, 90, 0);
|
|
||||||
--spinner-4-muted: rgb(18, 84, 202);
|
|
||||||
--spinner-4-primary: rgb(23, 105, 253);
|
|
||||||
--spinner-rotate: 304deg;
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { Global } from "@emotion/react";
|
|
||||||
export function CSSInJSStyles() {
|
|
||||||
return (
|
|
||||||
<Global
|
|
||||||
styles={`
|
|
||||||
:root {
|
|
||||||
--timestamp: "0";
|
|
||||||
--interval: "8";
|
|
||||||
--progress-bar: 11.83299999999997%;
|
|
||||||
--spinner-1-muted: rgb(142, 6, 182);
|
|
||||||
--spinner-1-primary: rgb(177, 8, 227);
|
|
||||||
--spinner-2-muted: rgb(110, 148, 190);
|
|
||||||
--spinner-2-primary: rgb(138, 185, 238);
|
|
||||||
--spinner-3-muted: rgb(75, 45, 64);
|
|
||||||
--spinner-3-primary: rgb(94, 56, 80);
|
|
||||||
--spinner-4-muted: rgb(155, 129, 108);
|
|
||||||
--spinner-4-primary: rgb(194, 161, 135);
|
|
||||||
--spinner-rotate: 213deg;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { Global } from "@emotion/react";
|
|
||||||
export function CSSInJSStyles() {
|
|
||||||
return (
|
|
||||||
<Global
|
|
||||||
styles={`
|
|
||||||
:root {
|
|
||||||
--timestamp: "16336621338281";
|
|
||||||
--interval: "16";
|
|
||||||
--progress-bar: 56.889%;
|
|
||||||
--spinner-1-muted: rgb(179, 6, 202);
|
|
||||||
--spinner-1-primary: rgb(224, 8, 253);
|
|
||||||
--spinner-2-muted: rgb(22, 188, 124);
|
|
||||||
--spinner-2-primary: rgb(27, 235, 155);
|
|
||||||
--spinner-3-muted: rgb(89, 72, 0);
|
|
||||||
--spinner-3-primary: rgb(111, 90, 0);
|
|
||||||
--spinner-4-muted: rgb(18, 84, 202);
|
|
||||||
--spinner-4-primary: rgb(23, 105, 253);
|
|
||||||
--spinner-rotate: 304deg;
|
|
||||||
} `}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
@import "./colors.css";
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--heading-font: "Space Mono", system-ui;
|
|
||||||
--body-font: "IBM Plex Sans", system-ui;
|
|
||||||
|
|
||||||
--color-brand: #02ff00;
|
|
||||||
--color-brand-muted: rgb(2, 150, 0);
|
|
||||||
|
|
||||||
--padding-horizontal: 90px;
|
|
||||||
|
|
||||||
--page-background: black;
|
|
||||||
--page-background-alpha: rgba(0, 0, 0, 0.8);
|
|
||||||
|
|
||||||
--result__background-color: black;
|
|
||||||
--result__primary-color: var(--color-brand);
|
|
||||||
--result__foreground-color: white;
|
|
||||||
--result__muted-color: rgb(165, 165, 165);
|
|
||||||
|
|
||||||
--card-width: 352px;
|
|
||||||
|
|
||||||
--page-width: 1152px;
|
|
||||||
|
|
||||||
--snippets_container-background-unfocused: #171717;
|
|
||||||
--snippets_container-background-focused: #0017e9;
|
|
||||||
--snippets_container-background: var(
|
|
||||||
--snippets_container-background-unfocused
|
|
||||||
);
|
|
||||||
--snippets_container-muted-color: rgb(153, 153, 153);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: white;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
padding: 0;
|
|
||||||
font-family: var(--body-font);
|
|
||||||
background-color: var(--page-background);
|
|
||||||
color: var(--result__muted-color);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Subtitle {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 4em;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 0.25em;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
#reactroot,
|
|
||||||
#__next,
|
|
||||||
body,
|
|
||||||
html {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Title {
|
|
||||||
color: var(--color-brand);
|
|
||||||
font-family: var(--heading-font);
|
|
||||||
font-weight: 700;
|
|
||||||
margin-top: 48px;
|
|
||||||
font-size: 48px;
|
|
||||||
text-transform: capitalize;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Description {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
header,
|
|
||||||
.main {
|
|
||||||
width: 650px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
width: 650px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
margin-bottom: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#reactroot,
|
|
||||||
#__next {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
height: 300px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ran,
|
|
||||||
.timer {
|
|
||||||
white-space: nowrap;
|
|
||||||
font-weight: bold;
|
|
||||||
-webkit-text-stroke: white;
|
|
||||||
-webkit-text-stroke-width: 2px;
|
|
||||||
color: white;
|
|
||||||
font-size: 100px;
|
|
||||||
}
|
|
||||||
.ran {
|
|
||||||
}
|
|
||||||
|
|
||||||
.ProgressBar-container {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-left: 10px solid red;
|
|
||||||
border-right: 10px solid pink;
|
|
||||||
border-top: 10px solid yellow;
|
|
||||||
border-bottom: 10px solid orange;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
height: 92px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ProgressBar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: block;
|
|
||||||
background-color: var(--color-brand);
|
|
||||||
transform-origin: top left;
|
|
||||||
border-radius: 4px;
|
|
||||||
transform: scaleX(var(--progress-bar, 0%));
|
|
||||||
}
|
|
||||||
|
|
||||||
.Bundler-container {
|
|
||||||
background-color: var(--snippets_container-background-focused);
|
|
||||||
font-size: 64px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: white;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 0.8em 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Bundler-updateRate {
|
|
||||||
font-size: 0.8em;
|
|
||||||
font-weight: normal;
|
|
||||||
display: flex;
|
|
||||||
color: var(--result__muted-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.interval:before {
|
|
||||||
content: var(--interval, "16");
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight {
|
|
||||||
margin-left: 0.5ch;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timer:after {
|
|
||||||
content: var(--timestamp);
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
|
|
||||||
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
|
||||||
display: inline;
|
|
||||||
font-weight: 500;
|
|
||||||
color: white;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SectionLabel {
|
|
||||||
font-weight: 300;
|
|
||||||
font-family: var(--heading-font);
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.FooterLabel {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner-container {
|
|
||||||
--spinner-muted: rgb(0, 255, 0);
|
|
||||||
--spinner-primary: rgb(0, 60, 255);
|
|
||||||
|
|
||||||
width: 96px;
|
|
||||||
height: 96px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--page-background);
|
|
||||||
border-top: 1.1em solid var(--spinner-muted);
|
|
||||||
border-right: 1.1em solid var(--spinner-muted);
|
|
||||||
border-bottom: 1.1em solid var(--spinner-muted);
|
|
||||||
border-left: 1.1em solid var(--spinner-primary);
|
|
||||||
|
|
||||||
transform: rotate(var(--spinner-rotate, 12deg));
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinners {
|
|
||||||
display: grid;
|
|
||||||
grid-auto-flow: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner-1.Spinner-container {
|
|
||||||
--spinner-muted: var(--spinner-1-muted);
|
|
||||||
--spinner-primary: var(--spinner-1-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner-2.Spinner-container {
|
|
||||||
--spinner-muted: var(--spinner-2-muted);
|
|
||||||
--spinner-primary: var(--spinner-2-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner-3.Spinner-container {
|
|
||||||
--spinner-muted: var(--spinner-3-muted);
|
|
||||||
--spinner-primary: var(--spinner-3-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner-4.Spinner-container {
|
|
||||||
--spinner-muted: var(--spinner-4-muted);
|
|
||||||
--spinner-primary: var(--spinner-4-primary);
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import ReactDOM from "react-dom";
|
|
||||||
import { Main } from "./main";
|
|
||||||
|
|
||||||
const Base = () => {
|
|
||||||
const name = typeof location !== "undefined" ? decodeURIComponent(location.search.substring(1)) : null;
|
|
||||||
return <Main productName={name} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
function startReact() {
|
|
||||||
ReactDOM.hydrate(<Base />, document.querySelector("#reactroot"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
globalThis.addEventListener("DOMContentLoaded", () => {
|
|
||||||
startReact();
|
|
||||||
});
|
|
||||||
|
|
||||||
startReact();
|
|
||||||
}
|
|
||||||
|
|
||||||
export { Base };
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
export const Main = (props: { productName: string; cssInJS?: string }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<header>
|
|
||||||
<div className="Title">CSS HMR Stress Test!</div>
|
|
||||||
<p className="Description">
|
|
||||||
This page visually tests how quickly a bundler can update {props.cssInJS ? "CSS-in-JS" : "CSS"} over Hot
|
|
||||||
Module Reloading.
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
<main className="main">
|
|
||||||
<section className="ProgressSection">
|
|
||||||
<p className="Subtitle">
|
|
||||||
<span className="Subtitle-part ran">
|
|
||||||
Ran: <span className="timer"></span>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="ProgressBar-container">
|
|
||||||
<div className="ProgressBar"></div>
|
|
||||||
</div>
|
|
||||||
<div className="SectionLabel">The progress bar should move from left to right smoothly.</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<div className="Spinners">
|
|
||||||
<div className="Spinner-container Spinner-1">
|
|
||||||
<div className="Spinner"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="Spinner-container Spinner-2">
|
|
||||||
<div className="Spinner"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="Spinner-container Spinner-3">
|
|
||||||
<div className="Spinner"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="Spinner-container Spinner-4">
|
|
||||||
<div className="Spinner"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="SectionLabel">The spinners should rotate & change color smoothly.</div>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
<footer>
|
|
||||||
<div className="SectionLabel FooterLabel">There are no CSS animations on this page.</div>
|
|
||||||
|
|
||||||
<div className="Bundler-container">
|
|
||||||
<div className="Bundler">{props.productName}</div>
|
|
||||||
<div className="Bundler-updateRate">{props.cssInJS ? "CSS-in-JS framework: " + props.cssInJS : ""}</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
{
|
|
||||||
"label": "bun-cli@0.0.34",
|
|
||||||
"at": "2021-10-08T01:01:18.129Z",
|
|
||||||
"sleep": "32",
|
|
||||||
"package": {
|
|
||||||
"name": "bun-cli",
|
|
||||||
"version": "0.0.34"
|
|
||||||
},
|
|
||||||
"timestamps": [
|
|
||||||
16336202536562, 16336202536908, 16336202537294, 16336202537705, 16336202538114, 16336202538534, 16336202538941,
|
|
||||||
16336202539323, 16336202539742, 16336202540159, 16336202540877, 16336202541310, 16336202541749, 16336202542159,
|
|
||||||
16336202542565, 16336202542996, 16336202543333, 16336202543761, 16336202544159, 16336202544534, 16336202544944,
|
|
||||||
16336202545345, 16336202545744, 16336202546159, 16336202546573, 16336202546986, 16336202547399, 16336202547781,
|
|
||||||
16336202548202, 16336202548564, 16336202548949, 16336202549329, 16336202549762, 16336202550168, 16336202550534,
|
|
||||||
16336202550887, 16336202551305, 16336202551659, 16336202552060, 16336202552449, 16336202552854, 16336202553270,
|
|
||||||
16336202553609, 16336202554034, 16336202554437, 16336202554783, 16336202555191, 16336202555623, 16336202556034,
|
|
||||||
16336202556449, 16336202556890, 16336202557283, 16336202557669, 16336202558084, 16336202558496, 16336202558863,
|
|
||||||
16336202559271, 16336202559659, 16336202560051, 16336202560452, 16336202560873, 16336202561290, 16336202561659,
|
|
||||||
16336202562035, 16336202562440, 16336202562862, 16336202563284, 16336202563659, 16336202564034, 16336202564444,
|
|
||||||
16336202564853, 16336202565245, 16336202565659, 16336202566034, 16336202566455, 16336202566873, 16336202567284,
|
|
||||||
16336202567659, 16336202568034, 16336202568386, 16336202568790, 16336202569204, 16336202569620, 16336202570384,
|
|
||||||
16336202570768, 16336202571188, 16336202571551, 16336202572327, 16336202572717, 16336202573116, 16336202573541,
|
|
||||||
16336202573959, 16336202574319, 16336202574682, 16336202575040, 16336202575375, 16336202577001, 16336202577342,
|
|
||||||
16336202577680, 16336202578066, 16336202578451, 16336202579166, 16336202579534, 16336202579960, 16336202580370,
|
|
||||||
16336202580789, 16336202581159, 16336202581576, 16336202581949, 16336202582294, 16336202583087, 16336202583496,
|
|
||||||
16336202583858, 16336202584203, 16336202584606, 16336202585034, 16336202585386, 16336202585788, 16336202586211,
|
|
||||||
16336202586604, 16336202587034, 16336202587459, 16336202587869, 16336202588295, 16336202588668, 16336202589092,
|
|
||||||
16336202589452, 16336202589831, 16336202590197, 16336202590608, 16336202591034, 16336202591460, 16336202591880,
|
|
||||||
16336202592295, 16336202592727, 16336202593172, 16336202593567, 16336202593994, 16336202594397, 16336202594795,
|
|
||||||
16336202595224, 16336202595659, 16336202596058, 16336202596463, 16336202596890, 16336202597322, 16336202597732,
|
|
||||||
16336202598159, 16336202598534, 16336202598951, 16336202599365, 16336202599785, 16336202600159, 16336202600593,
|
|
||||||
16336202601005, 16336202601402, 16336202601807, 16336202602214, 16336202602556, 16336202602895, 16336202603307,
|
|
||||||
16336202603661, 16336202604075, 16336202604491, 16336202604853, 16336202605268, 16336202605670, 16336202606034,
|
|
||||||
16336202606393, 16336202606748, 16336202607170, 16336202607568, 16336202607982, 16336202608411, 16336202608836,
|
|
||||||
16336202609197, 16336202609596, 16336202609965, 16336202610333, 16336202610740, 16336202611159, 16336202611573,
|
|
||||||
16336202611975, 16336202612317, 16336202612691, 16336202613060, 16336202613474, 16336202613903, 16336202614341,
|
|
||||||
16336202614707, 16336202615094, 16336202615534, 16336202615883, 16336202616296, 16336202616671, 16336202617034,
|
|
||||||
16336202617391, 16336202617727, 16336202618159, 16336202618534, 16336202618937, 16336202619360, 16336202619770,
|
|
||||||
16336202620179, 16336202620716, 16336202621143, 16336202621534, 16336202622303, 16336202622659, 16336202623085,
|
|
||||||
16336202623498, 16336202623850, 16336202624220, 16336202624606, 16336202625034, 16336202625387, 16336202625805,
|
|
||||||
16336202626210, 16336202626599, 16336202627034, 16336202627386, 16336202627748, 16336202628159, 16336202628534,
|
|
||||||
16336202628954, 16336202629373, 16336202629809, 16336202630197, 16336202630535, 16336202630916, 16336202631290,
|
|
||||||
16336202631666, 16336202632034, 16336202632369, 16336202633152, 16336202633534, 16336202633883, 16336202634309,
|
|
||||||
16336202634717, 16336202635106, 16336202635871, 16336202636253, 16336202636671, 16336202637070, 16336202637434,
|
|
||||||
16336202637798, 16336202638184, 16336202638539, 16336202638938, 16336202639307, 16336202639666, 16336202640095,
|
|
||||||
16336202640534, 16336202640962, 16336202641307, 16336202641659, 16336202642087, 16336202642521, 16336202642886,
|
|
||||||
16336202643309, 16336202643662, 16336202644067, 16336202644491, 16336202644853, 16336202645226, 16336202645659,
|
|
||||||
16336202646074, 16336202646497, 16336202646890, 16336202647311, 16336202647749, 16336202648169, 16336202648976,
|
|
||||||
16336202649378, 16336202649810, 16336202650165, 16336202650534, 16336202650875, 16336202651250, 16336202651659,
|
|
||||||
16336202652093, 16336202652516, 16336202652921, 16336202653332, 16336202653722, 16336202654142, 16336202654534,
|
|
||||||
16336202654880, 16336202655221, 16336202655562, 16336202655997, 16336202656378, 16336202656811, 16336202657161,
|
|
||||||
16336202657588, 16336202657944, 16336202658360, 16336202658708, 16336202659089, 16336202659428, 16336202659849,
|
|
||||||
16336202660273, 16336202660685, 16336202661105, 16336202661534, 16336202661873, 16336202662228, 16336202662658,
|
|
||||||
16336202663438, 16336202663843, 16336202664219, 16336202664646, 16336202665050, 16336202665487, 16336202665838,
|
|
||||||
16336202666211, 16336202666573, 16336202666927, 16336202667334, 16336202667746, 16336202668158, 16336202668563,
|
|
||||||
16336202668980, 16336202669406, 16336202669753, 16336202670192, 16336202670554, 16336202670903, 16336202671324,
|
|
||||||
16336202671734, 16336202672159, 16336202672573, 16336202672982, 16336202673346, 16336202673680, 16336202674087,
|
|
||||||
16336202674499, 16336202674909, 16336202675260, 16336202676110, 16336202676535, 16336202676913, 16336202677312,
|
|
||||||
16336202677658, 16336202678044, 16336202678413, 16336202678793, 16336202679208, 16336202679604, 16336202680034,
|
|
||||||
16336202680385, 16336202680799, 16336202681213, 16336202681595, 16336202682004, 16336202682346, 16336202682726,
|
|
||||||
16336202683158, 16336202683586, 16336202683990, 16336202684323, 16336202684742, 16336202685175, 16336202685578,
|
|
||||||
16336202685979, 16336202686805, 16336202687206, 16336202687614, 16336202688038, 16336202688473, 16336202688848,
|
|
||||||
16336202689221, 16336202689559, 16336202689971, 16336202690368, 16336202690776, 16336202691159, 16336202691585,
|
|
||||||
16336202692010, 16336202692373, 16336202692780, 16336202693179, 16336202693580, 16336202693991, 16336202694324,
|
|
||||||
16336202694727, 16336202695159, 16336202695588, 16336202695991, 16336202696335, 16336202697160, 16336202697542,
|
|
||||||
16336202697929, 16336202698323, 16336202698674, 16336202699060, 16336202699492, 16336202699835, 16336202700238,
|
|
||||||
16336202700658, 16336202701059, 16336202701420, 16336202701815, 16336202702229, 16336202702659, 16336202703857,
|
|
||||||
16336202704256, 16336202704659, 16336202705497, 16336202706309, 16336202706660, 16336202707085, 16336202707511,
|
|
||||||
16336202707866, 16336202708210, 16336202708552, 16336202708925, 16336202709287, 16336202709670, 16336202710045,
|
|
||||||
16336202710402, 16336202710802, 16336202711167, 16336202711533, 16336202712249, 16336202712660, 16336202713088,
|
|
||||||
16336202713519, 16336202713936, 16336202714355, 16336202714740, 16336202715160, 16336202715533, 16336202715878,
|
|
||||||
16336202716290, 16336202716708, 16336202717102, 16336202718290, 16336202718699, 16336202719052, 16336202719388,
|
|
||||||
16336202719808, 16336202720225, 16336202720659, 16336202721052, 16336202721414, 16336202721828, 16336202722925,
|
|
||||||
16336202723664, 16336202724063, 16336202724405, 16336202726003, 16336202726736, 16336202727158, 16336202727543,
|
|
||||||
16336202727930, 16336202728336, 16336202728703, 16336202729061, 16336202729483, 16336202729832, 16336202730222,
|
|
||||||
16336202730659, 16336202731084, 16336202731500, 16336202731911, 16336202732326, 16336202733158, 16336202733585,
|
|
||||||
16336202734001, 16336202734691, 16336202735042, 16336202735442, 16336202735863, 16336202736255, 16336202736671,
|
|
||||||
16336202737043, 16336202737884, 16336202738671, 16336202739110, 16336202739533, 16336202739886, 16336202740283,
|
|
||||||
16336202740706, 16336202741143, 16336202741534, 16336202741942, 16336202742352, 16336202742697, 16336202743103,
|
|
||||||
16336202743940, 16336202745172, 16336202745542, 16336202745937, 16336202746339, 16336202746758, 16336202747531,
|
|
||||||
16336202747877, 16336202748232, 16336202748658, 16336202749055, 16336202749468, 16336202749859, 16336202750416,
|
|
||||||
16336202750839, 16336202751178, 16336202751572, 16336202752002, 16336202752419, 16336202753269, 16336202753678,
|
|
||||||
16336202754086, 16336202754432, 16336202754835, 16336202755260, 16336202755683, 16336202756059, 16336202756402,
|
|
||||||
16336202756837, 16336202758084, 16336202758507, 16336202758879, 16336202759270, 16336202759674, 16336202760044,
|
|
||||||
16336202760400, 16336202760801, 16336202761659, 16336202762053, 16336202762397, 16336202763199, 16336202763547,
|
|
||||||
16336202763948, 16336202764714, 16336202765113, 16336202765947, 16336202766329, 16336202766664, 16336202767085,
|
|
||||||
16336202768233, 16336202769056, 16336202769758, 16336202770178, 16336202770585, 16336202770929, 16336202771325,
|
|
||||||
16336202772158, 16336202772594, 16336202773033, 16336202773403, 16336202773801, 16336202774179, 16336202774555,
|
|
||||||
16336202774989, 16336202775393, 16336202775809, 16336202776209, 16336202776618, 16336202777033, 16336202777421,
|
|
||||||
16336202777845, 16336202778246, 16336202778658, 16336202779055, 16336202779411, 16336202779761, 16336202780175,
|
|
||||||
16336202780594, 16336202781002, 16336202781848, 16336202782658, 16336202783033, 16336202783857, 16336202784211,
|
|
||||||
16336202784557, 16336202784972, 16336202785377, 16336202785810, 16336202786172, 16336202786934, 16336202787343,
|
|
||||||
16336202787765, 16336202788201, 16336202788563, 16336202788970, 16336202789329, 16336202789672, 16336202790055,
|
|
||||||
16336202790456, 16336202790802, 16336202791580, 16336202791920, 16336202792326, 16336202793158, 16336202793953,
|
|
||||||
16336202794368, 16336202795187, 16336202795622, 16336202796033, 16336202796393, 16336202796777, 16336202797173,
|
|
||||||
16336202797540, 16336202797975, 16336202798317, 16336202798739, 16336202799158, 16336202799567, 16336202799966,
|
|
||||||
16336202800378, 16336202800803, 16336202801232, 16336202801658, 16336202802033, 16336202802374, 16336202802759,
|
|
||||||
16336202803158, 16336202803533, 16336202803947, 16336202804354, 16336202804729, 16336202805158, 16336202805534,
|
|
||||||
16336202805950, 16336202806390, 16336202806805, 16336202807219, 16336202807643, 16336202808033, 16336202808377,
|
|
||||||
16336202808790, 16336202809211, 16336202809560, 16336202809920, 16336202810355, 16336202810758, 16336202811187,
|
|
||||||
16336202811596, 16336202811943, 16336202812348, 16336202812710, 16336202813060, 16336202813398, 16336202813791,
|
|
||||||
16336202814158, 16336202814533, 16336202814878, 16336202815246, 16336202815658, 16336202816079, 16336202816851,
|
|
||||||
16336202817202, 16336202817540, 16336202817905, 16336202818244, 16336202818663, 16336202819068, 16336202819418,
|
|
||||||
16336202819777, 16336202820193, 16336202820599, 16336202821033, 16336202821395, 16336202821745, 16336202822158,
|
|
||||||
16336202822590, 16336202822996, 16336202823396, 16336202823804, 16336202824210, 16336202824581, 16336202824991,
|
|
||||||
16336202825406, 16336202825806, 16336202826210, 16336202826598, 16336202827033, 16336202827446, 16336202827839,
|
|
||||||
16336202828201, 16336202828577, 16336202828968, 16336202829362, 16336202829709, 16336202830096, 16336202830533,
|
|
||||||
16336202830917, 16336202831290, 16336202831699, 16336202832035, 16336202832406, 16336202832804, 16336202833200,
|
|
||||||
16336202833604, 16336202834033, 16336202834386, 16336202834759, 16336202835190, 16336202835621, 16336202836033,
|
|
||||||
16336202836405, 16336202837191, 16336202837613, 16336202838033, 16336202838374, 16336202838798, 16336202839200,
|
|
||||||
16336202839603, 16336202840034, 16336202840389, 16336202840783, 16336202841200, 16336202841617, 16336202842034,
|
|
||||||
16336202842390, 16336202842737, 16336202843158, 16336202843585, 16336202843923, 16336202844313, 16336202844724,
|
|
||||||
16336202845158, 16336202845576, 16336202845939, 16336202846368, 16336202846728, 16336202847158, 16336202847568,
|
|
||||||
16336202847911, 16336202848291, 16336202848695, 16336202849103, 16336202849533, 16336202849942, 16336202850368,
|
|
||||||
16336202850747, 16336202851158, 16336202851549, 16336202851978, 16336202852383, 16336202852725, 16336202853158,
|
|
||||||
16336202853554, 16336202853961, 16336202854308, 16336202854704, 16336202855060, 16336202855418, 16336202855776,
|
|
||||||
16336202856203, 16336202856617, 16336202857036, 16336202857455, 16336202857884, 16336202858262, 16336202858658,
|
|
||||||
16336202859071, 16336202859847, 16336202860237, 16336202860658, 16336202861037, 16336202861452, 16336202861869,
|
|
||||||
16336202862218, 16336202862590, 16336202863001, 16336202863422, 16336202863857, 16336202864219, 16336202864658,
|
|
||||||
16336202865047, 16336202865404, 16336202865789, 16336202866210, 16336202866624, 16336202867033, 16336202867380,
|
|
||||||
16336202867797, 16336202868227, 16336202868658, 16336202869083, 16336202869500, 16336202869906, 16336202870246,
|
|
||||||
16336202870658, 16336202871086, 16336202871441, 16336202871820, 16336202872204, 16336202872546, 16336202872943,
|
|
||||||
16336202873380, 16336202873811, 16336202874213, 16336202874566, 16336202874918, 16336202875261, 16336202875655,
|
|
||||||
16336202876047, 16336202876771, 16336202877202, 16336202877612, 16336202878033, 16336202878412, 16336202878846,
|
|
||||||
16336202879241, 16336202879658, 16336202880072, 16336202880508, 16336202880901, 16336202881308, 16336202881725,
|
|
||||||
16336202882158, 16336202882579, 16336202882945, 16336202883286, 16336202883657, 16336202884048, 16336202884404,
|
|
||||||
16336202884752, 16336202885158, 16336202885533, 16336202885938, 16336202886364, 16336202886759, 16336202887175,
|
|
||||||
16336202887585, 16336202887929, 16336202888345, 16336202888743, 16336202889157, 16336202889570, 16336202889970,
|
|
||||||
16336202890382, 16336202890761, 16336202891187, 16336202891600, 16336202892033, 16336202892454, 16336202892794,
|
|
||||||
16336202893178, 16336202893533, 16336202893903, 16336202894264, 16336202894668, 16336202895049, 16336202895400,
|
|
||||||
16336202895774, 16336202896157, 16336202896537, 16336202896883, 16336202897232, 16336202897658, 16336202898065,
|
|
||||||
16336202898493, 16336202898884, 16336202899251, 16336202899673, 16336202900047, 16336202900467, 16336202900883,
|
|
||||||
16336202901300, 16336202901676, 16336202902068, 16336202902479, 16336202902902, 16336202903260, 16336202903675,
|
|
||||||
16336202904094, 16336202904476, 16336202904824, 16336202905158, 16336202905533, 16336202905934, 16336202906289,
|
|
||||||
16336202906717, 16336202907158, 16336202907547, 16336202907904, 16336202908294, 16336202908717, 16336202909157,
|
|
||||||
16336202909582, 16336202910005, 16336202910399, 16336202910800, 16336202911220, 16336202911657, 16336202912064,
|
|
||||||
16336202912405, 16336202912779, 16336202913158, 16336202913553, 16336202913966, 16336202914376, 16336202914719,
|
|
||||||
16336202915091, 16336202915515, 16336202915887, 16336202916293, 16336202916649, 16336202917438, 16336202917869,
|
|
||||||
16336202918221, 16336202919053, 16336202919425, 16336202919833, 16336202920234, 16336202920658, 16336202921033,
|
|
||||||
16336202921433, 16336202921801, 16336202922161, 16336202922589, 16336202923017, 16336202923418, 16336202923804,
|
|
||||||
16336202924199, 16336202924593, 16336202925033, 16336202925449, 16336202925818, 16336202926223, 16336202926662,
|
|
||||||
16336202927431, 16336202927812, 16336202928227, 16336202928658, 16336202929061, 16336202929473, 16336202929891,
|
|
||||||
16336202930241, 16336202930657, 16336202931057, 16336202931396, 16336202931811, 16336202932225, 16336202932657,
|
|
||||||
16336202933058, 16336202933445, 16336202933790, 16336202934157, 16336202934562, 16336202934988, 16336202935391,
|
|
||||||
16336202935777, 16336202936160, 16336202936562, 16336202936986, 16336202937396, 16336202937751, 16336202938158,
|
|
||||||
16336202938578, 16336202938985, 16336202939396, 16336202939752, 16336202940157, 16336202940585
|
|
||||||
],
|
|
||||||
"frameTimes": [
|
|
||||||
346, 411, 420, 382, 417, 433, 410, 431, 428, 375, 401, 415, 413, 382, 362, 380, 406, 353, 354, 389, 416, 425, 346,
|
|
||||||
432, 415, 393, 415, 367, 388, 401, 417, 376, 422, 375, 410, 392, 375, 418, 375, 352, 414, 764, 420, 776, 399, 418,
|
|
||||||
363, 335, 341, 386, 715, 426, 419, 417, 345, 409, 345, 428, 402, 393, 425, 426, 424, 379, 411, 426, 415, 445, 427,
|
|
||||||
398, 435, 405, 432, 427, 417, 420, 434, 397, 407, 339, 354, 416, 415, 364, 355, 398, 429, 361, 369, 407, 414, 342,
|
|
||||||
369, 429, 366, 440, 413, 363, 336, 375, 423, 409, 427, 769, 426, 352, 386, 353, 405, 435, 362, 375, 419, 388, 381,
|
|
||||||
376, 335, 382, 426, 389, 382, 399, 364, 355, 369, 429, 428, 352, 434, 423, 405, 362, 433, 423, 421, 420, 402, 355,
|
|
||||||
341, 409, 423, 411, 420, 346, 341, 381, 350, 356, 348, 339, 424, 420, 339, 430, 405, 427, 437, 373, 354, 412, 405,
|
|
||||||
426, 439, 349, 410, 414, 364, 407, 410, 850, 378, 346, 369, 415, 430, 414, 382, 342, 432, 404, 419, 403, 826, 408,
|
|
||||||
435, 373, 412, 408, 426, 363, 399, 411, 403, 429, 344, 382, 394, 386, 343, 420, 361, 414, 1198, 403, 812, 425, 355,
|
|
||||||
342, 362, 375, 400, 366, 411, 431, 419, 420, 345, 418, 1188, 353, 420, 434, 362, 1097, 399, 1598, 422, 387, 367,
|
|
||||||
422, 390, 425, 411, 832, 416, 351, 421, 416, 841, 439, 353, 423, 391, 410, 406, 1232, 395, 419, 346, 426, 413, 557,
|
|
||||||
339, 430, 850, 408, 403, 423, 343, 1247, 372, 404, 356, 858, 344, 348, 766, 834, 335, 1148, 702, 407, 396, 436, 370,
|
|
||||||
378, 434, 416, 409, 388, 401, 397, 350, 419, 846, 375, 354, 415, 433, 762, 422, 362, 359, 383, 346, 340, 832, 415,
|
|
||||||
435, 360, 396, 435, 422, 409, 412, 429, 375, 385, 375, 407, 429, 416, 415, 424, 344, 421, 360, 403, 409, 405, 350,
|
|
||||||
393, 375, 368, 421, 351, 365, 419, 350, 416, 434, 350, 432, 400, 406, 410, 400, 388, 413, 362, 391, 347, 437, 373,
|
|
||||||
336, 398, 404, 353, 431, 412, 786, 420, 424, 403, 355, 417, 417, 347, 427, 390, 434, 363, 360, 410, 380, 408, 409,
|
|
||||||
379, 391, 405, 433, 407, 396, 358, 427, 419, 429, 396, 776, 421, 415, 349, 411, 435, 439, 357, 421, 409, 417, 431,
|
|
||||||
417, 340, 428, 379, 342, 437, 402, 352, 394, 724, 410, 379, 395, 414, 393, 417, 421, 341, 391, 348, 375, 426, 416,
|
|
||||||
344, 398, 413, 412, 426, 433, 340, 355, 361, 381, 374, 380, 349, 407, 391, 422, 420, 417, 392, 423, 415, 382, 334,
|
|
||||||
401, 428, 389, 390, 440, 423, 401, 437, 341, 379, 413, 343, 424, 406, 789, 352, 372, 401, 375, 368, 428, 401, 395,
|
|
||||||
440, 369, 439, 381, 431, 412, 350, 400, 415, 432, 387, 367, 426, 386, 402, 410, 407, 407, 356, 428
|
|
||||||
],
|
|
||||||
"percentileMs": {
|
|
||||||
"50": 40.7,
|
|
||||||
"75": 42.3,
|
|
||||||
"90": 43.5,
|
|
||||||
"95": 76.4,
|
|
||||||
"99": 118.8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../../tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": ".",
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"paths": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import reactRefresh from "@vitejs/plugin-react-refresh";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
plugins: [reactRefresh()],
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Benchmarking hot module reloading
|
|
||||||
|
|
||||||
## Methodology
|
|
||||||
|
|
||||||
How do you benchmark hot module reloading? What do you call "done" and what do you call "start"?
|
|
||||||
|
|
||||||
The answer for "done" is certainly not compilation time. Compilation time is one step.
|
|
||||||
|
|
||||||
I think the answer should be different depending on the type of content loaded.
|
|
||||||
|
|
||||||
For CSS, the answer should be "when the updated stylesheet was drawn on the screen"
|
|
||||||
For JavaScript, the answer should be "when the rebuilt code completed execution such that any changes are applied"
|
|
||||||
For images & assets, the answer should be "when the updated asset finished loading"
|
|
||||||
|
|
||||||
The start time should be defined as "the timestamp the filesystem set as the write time". As in, the time the developer pressed save in their editor.
|
|
||||||
1
bench/stress/hot-reload-files/.gitignore
vendored
Normal file
1
bench/stress/hot-reload-files/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
modules
|
||||||
48
bench/stress/hot-reload-files/README.md
Normal file
48
bench/stress/hot-reload-files/README.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Hot Reload Files Stress Test
|
||||||
|
|
||||||
|
This is a stress test for Bun's hot reloading functionality, designed to test performance with a high number of interdependent files.
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
- Generates 1000 interconnected TypeScript modules
|
||||||
|
- Each module imports 2 other modules
|
||||||
|
- Uses IPC (Inter-Process Communication) to detect reloads
|
||||||
|
- Performs 1,000 hot reloads and tracks memory usage
|
||||||
|
- Reports statistics about hot reload performance
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run-stress-test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
|
||||||
|
1. Generate 1000 interconnected modules
|
||||||
|
2. Run the stress test that performs 10,000 hot reloads
|
||||||
|
3. Report complete performance statistics
|
||||||
|
|
||||||
|
## How The Test Works
|
||||||
|
|
||||||
|
The test utilizes Node.js's child_process fork API for communication:
|
||||||
|
|
||||||
|
1. The main process (stress-test.ts) creates a child process running Bun with hot reloading
|
||||||
|
2. The modules communicate with the parent process via IPC when they're reloaded
|
||||||
|
3. After detecting a successful reload, the parent modifies another file
|
||||||
|
4. This continues for 1,000 iterations
|
||||||
|
5. Memory usage is tracked throughout the process
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **generate.ts**: Creates 1000 interconnected modules with IPC signaling
|
||||||
|
- **stress-test.ts**: Controls the test, forks Bun, and tracks metrics
|
||||||
|
- **run-stress-test.sh**: Script to run the entire test from scratch
|
||||||
|
|
||||||
|
## Performance Metrics
|
||||||
|
|
||||||
|
The test reports:
|
||||||
|
|
||||||
|
- Total number of hot reloads completed
|
||||||
|
- Time taken to complete all reloads
|
||||||
|
- Average time per reload
|
||||||
|
- Initial and final RSS memory usage
|
||||||
166
bench/stress/hot-reload-files/generate.ts
Normal file
166
bench/stress/hot-reload-files/generate.ts
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import { mkdir, writeFile } from "fs/promises";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const MODULES_DIR = join(process.cwd(), "modules");
|
||||||
|
const NUM_MODULES = 1000;
|
||||||
|
|
||||||
|
// Create the modules directory if it doesn't exist
|
||||||
|
async function ensureModulesDir() {
|
||||||
|
try {
|
||||||
|
await mkdir(MODULES_DIR, { recursive: true });
|
||||||
|
console.log(`Created directory: ${MODULES_DIR}`);
|
||||||
|
} catch (err) {
|
||||||
|
if ((err as NodeJS.ErrnoException).code !== "EEXIST") {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hot Reload Stress Test</title>
|
||||||
|
<script src="./client_1.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hot Reload Stress Test</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Generate the HTTP server file (the last file)
|
||||||
|
async function generateServerFile() {
|
||||||
|
const content = `
|
||||||
|
// File: module_${NUM_MODULES}.ts
|
||||||
|
console.log("Server module loaded");
|
||||||
|
import html from './index.html';
|
||||||
|
|
||||||
|
// Create a server to prove things are running
|
||||||
|
const server = Bun.serve({
|
||||||
|
port: 0,
|
||||||
|
routes: {
|
||||||
|
"/": html,
|
||||||
|
},
|
||||||
|
fetch() {
|
||||||
|
return new Response("Hot reload stress test server running");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.send) {
|
||||||
|
process.send({
|
||||||
|
type: "server-started",
|
||||||
|
url: server.url.href,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(\`Server started on http://localhost:\${server.port}\`);
|
||||||
|
|
||||||
|
// Print RSS memory usage
|
||||||
|
const rss = process.memoryUsage().rss / 1024 / 1024;
|
||||||
|
console.log(\`RSS Memory: \${rss.toFixed(2)} MB\`);
|
||||||
|
`;
|
||||||
|
|
||||||
|
await writeFile(join(MODULES_DIR, `module_${NUM_MODULES}.ts`), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate interconnected module files
|
||||||
|
async function generateModuleFiles() {
|
||||||
|
// Generate modules 1 through NUM_MODULES-1
|
||||||
|
for (let i = 1; i < NUM_MODULES; i++) {
|
||||||
|
// Each module imports 2 other modules (except for the ones near the end that need to import the server)
|
||||||
|
const importIdx1 = Math.min(i + 1, NUM_MODULES);
|
||||||
|
const importIdx2 = Math.min(i + 2, NUM_MODULES);
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
// File: module_${i}.ts
|
||||||
|
import "./module_${importIdx1}";
|
||||||
|
import "./module_${importIdx2}";
|
||||||
|
|
||||||
|
// This value will be changed during hot reload stress testing
|
||||||
|
export const value${i} = {
|
||||||
|
moduleId: ${i},
|
||||||
|
timestamp: \`\${new Date().toISOString()}\`,
|
||||||
|
counter: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
await writeFile(join(MODULES_DIR, `module_${i}.ts`), content);
|
||||||
|
|
||||||
|
if (i % 100 === 0) {
|
||||||
|
console.log(`Generated ${i} modules`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the entry point file
|
||||||
|
async function generateEntryPoint() {
|
||||||
|
const content = `
|
||||||
|
|
||||||
|
if (!globalThis.hasLoadedOnce) {
|
||||||
|
globalThis.hasLoadedOnce = true;
|
||||||
|
console.log("Starting hot-reload stress test...");
|
||||||
|
|
||||||
|
// Print RSS memory usage
|
||||||
|
const rss = process.memoryUsage().rss / 1024 / 1024;
|
||||||
|
console.log(\`RSS Memory: \${rss.toFixed(2)} MB\`);
|
||||||
|
|
||||||
|
// Signal when the entry point is loaded
|
||||||
|
if (process.send && process.env.HOT_RELOAD_TEST === "true") {
|
||||||
|
process.send({
|
||||||
|
type: 'test-started',
|
||||||
|
rss: rss.toFixed(2)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print memory usage periodically
|
||||||
|
setInterval(() => {
|
||||||
|
const rss = process.memoryUsage().rss / 1024 / 1024;
|
||||||
|
console.log(\`[MEMORY] RSS: \${rss.toFixed(2)} MB at \${new Date().toISOString()}\`);
|
||||||
|
|
||||||
|
// Also send via IPC if available
|
||||||
|
if (process.send && process.env.HOT_RELOAD_TEST === "true") {
|
||||||
|
process.send({
|
||||||
|
type: 'memory-update',
|
||||||
|
rss: rss.toFixed(2),
|
||||||
|
time: Date.now()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
await import("./module_1");
|
||||||
|
|
||||||
|
process.send({
|
||||||
|
type: "module-reloaded",
|
||||||
|
rss: (process.memoryUsage.rss() / 1024 / 1024) | 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
await writeFile(join(MODULES_DIR, "index.ts"), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateClientFile() {
|
||||||
|
const content = `
|
||||||
|
// File: client_1.js
|
||||||
|
console.log("Client module loaded");
|
||||||
|
`;
|
||||||
|
await writeFile(join(MODULES_DIR, "client_1.js"), content);
|
||||||
|
await writeFile(join(MODULES_DIR, "index.html"), html);
|
||||||
|
console.log("Generated client module");
|
||||||
|
}
|
||||||
|
|
||||||
|
await ensureModulesDir();
|
||||||
|
console.log("Generating server module...");
|
||||||
|
await generateServerFile();
|
||||||
|
console.log("Generating client module...");
|
||||||
|
await generateClientFile();
|
||||||
|
console.log("Generating interconnected modules...");
|
||||||
|
await generateModuleFiles();
|
||||||
|
console.log("Generating entry point...");
|
||||||
|
await generateEntryPoint();
|
||||||
|
console.log("Generation complete!");
|
||||||
|
console.log("Run with: HOT_RELOAD_TEST=true RELOAD_ID=initial bun --hot modules/index.ts");
|
||||||
14
bench/stress/hot-reload-files/run-stress-test.sh
Executable file
14
bench/stress/hot-reload-files/run-stress-test.sh
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Clean up modules directory
|
||||||
|
rm -rf modules
|
||||||
|
|
||||||
|
# Generate the module files
|
||||||
|
echo "Generating 1000 module files..."
|
||||||
|
bun generate.ts
|
||||||
|
|
||||||
|
# Run the stress test
|
||||||
|
echo "Running stress test for 1000 reloads..."
|
||||||
|
bun stress-test.ts
|
||||||
|
|
||||||
|
# All done - the stress test manages the child process internally
|
||||||
161
bench/stress/hot-reload-files/stress-test.ts
Normal file
161
bench/stress/hot-reload-files/stress-test.ts
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import { Subprocess } from "bun";
|
||||||
|
import { readFile, writeFile } from "fs/promises";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const MODULES_DIR = join(process.cwd(), "modules");
|
||||||
|
const NUM_MODULES = 1000;
|
||||||
|
const TOTAL_RELOADS = 1000;
|
||||||
|
|
||||||
|
// Tracking metrics
|
||||||
|
let completedReloads = 0;
|
||||||
|
let startTime = 0;
|
||||||
|
let lastRss = 0;
|
||||||
|
|
||||||
|
// Function to write modified files
|
||||||
|
async function modifyFile(moduleNum: number, reloadId: string): Promise<void> {
|
||||||
|
const modulePath = join(MODULES_DIR, `module_${moduleNum}.ts`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read the current file content
|
||||||
|
const content = await readFile(modulePath, "utf8");
|
||||||
|
|
||||||
|
// Create a new timestamp
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
|
||||||
|
// Replace the timestamp and counter
|
||||||
|
const newContent = content.replace(
|
||||||
|
/export const value\d+ = \{[\s\S]*?\};/,
|
||||||
|
`export const value${moduleNum} = {
|
||||||
|
moduleId: ${moduleNum},
|
||||||
|
timestamp: "${timestamp}",
|
||||||
|
// comment ${completedReloads}!
|
||||||
|
counter: ${completedReloads + 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write the modified content back to the file
|
||||||
|
await writeFile(modulePath, newContent);
|
||||||
|
console.count("Modify");
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error modifying module_${moduleNum}.ts:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a random number between min and max (inclusive)
|
||||||
|
function getRandomInt(min: number, max: number): number {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the child process with Bun's hot reloading
|
||||||
|
function startBunProcess() {
|
||||||
|
// Start the Bun process with hot reloading enabled
|
||||||
|
const child = Bun.spawn({
|
||||||
|
cmd: [process.execPath, "--hot", "--no-clear-screen", "./modules/index.ts"],
|
||||||
|
stdio: ["inherit", "inherit", "inherit"],
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
HOT_RELOAD_TEST: "true",
|
||||||
|
RELOAD_ID: "initial",
|
||||||
|
},
|
||||||
|
ipc(message, subprocess) {
|
||||||
|
if (message.type === "test-started") {
|
||||||
|
console.log(`Test started with initial RSS: ${message.rss} MB`);
|
||||||
|
lastRss = parseFloat(message.rss);
|
||||||
|
startNextReload();
|
||||||
|
} else if (message.type === "module-reloaded") {
|
||||||
|
const { rss } = message;
|
||||||
|
lastRss = parseFloat(rss);
|
||||||
|
|
||||||
|
// Check if this is the current reload we're waiting for
|
||||||
|
completedReloads++;
|
||||||
|
console.log(`[${completedReloads}/${TOTAL_RELOADS}] Module reloaded - RSS: ${rss} MB`);
|
||||||
|
|
||||||
|
// Start the next reload or finish
|
||||||
|
if (completedReloads < TOTAL_RELOADS) {
|
||||||
|
startNextReload();
|
||||||
|
} else {
|
||||||
|
finishTest();
|
||||||
|
}
|
||||||
|
} else if (message.type === "memory-update") {
|
||||||
|
// Periodic memory updates from the child process
|
||||||
|
lastRss = parseFloat(message.rss);
|
||||||
|
} else if (message.type === "server-started") {
|
||||||
|
fetch(message.url).then(res => {
|
||||||
|
res.text().then(text => {
|
||||||
|
console.count("Request completed");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the next reload
|
||||||
|
async function startNextReload() {
|
||||||
|
const nextReloadNum = completedReloads + 1;
|
||||||
|
if (nextReloadNum > TOTAL_RELOADS) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Generate a unique reload ID for this reload
|
||||||
|
const reloadId = `reload-${nextReloadNum}`;
|
||||||
|
|
||||||
|
// Set the reload ID in the environment for the child process
|
||||||
|
process.env.RELOAD_ID = reloadId;
|
||||||
|
|
||||||
|
// Pick a random module to modify
|
||||||
|
const moduleNum = getRandomInt(1, NUM_MODULES - 1);
|
||||||
|
|
||||||
|
// Modify the file to trigger a hot reload
|
||||||
|
await modifyFile(moduleNum, reloadId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error during reload #${nextReloadNum}:`, error);
|
||||||
|
// Try the next reload immediately
|
||||||
|
startNextReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish the test and print statistics
|
||||||
|
function finishTest() {
|
||||||
|
const endTime = Date.now();
|
||||||
|
const duration = (endTime - startTime) / 1000;
|
||||||
|
|
||||||
|
console.log(`\nStress test complete!`);
|
||||||
|
console.log(`Performed ${completedReloads} hot reloads in ${duration.toFixed(2)} seconds`);
|
||||||
|
console.log(`Average: ${((duration / completedReloads) * 1000).toFixed(2)} ms per reload`);
|
||||||
|
console.log(`Final RSS: ${lastRss.toFixed(2)} MB`);
|
||||||
|
|
||||||
|
// Kill the child process and exit immediately
|
||||||
|
if (childProcess) {
|
||||||
|
childProcess.kill();
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the stress test
|
||||||
|
let childProcess: Subprocess | null = null;
|
||||||
|
|
||||||
|
async function runStressTest() {
|
||||||
|
console.log(`Starting stress test - will perform ${TOTAL_RELOADS} hot reloads`);
|
||||||
|
startTime = Date.now();
|
||||||
|
|
||||||
|
// Start the Bun process with hot reloading
|
||||||
|
childProcess = startBunProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the stress test
|
||||||
|
runStressTest();
|
||||||
|
|
||||||
|
// Handle process termination
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
console.log("\nTest interrupted by user");
|
||||||
|
if (childProcess) {
|
||||||
|
childProcess.kill();
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user