-
Notifications
You must be signed in to change notification settings - Fork 346
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2558 from cloudflare/harris/inspector-test
EW-8447 Add regression test for CPU profiling
- Loading branch information
Showing
11 changed files
with
353 additions
and
18 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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,14 @@ | ||
load("@aspect_rules_js//js:defs.bzl", "js_library") | ||
load("@aspect_rules_js//npm:defs.bzl", "npm_package") | ||
|
||
js_library( | ||
name = "server-harness_js_lib", | ||
srcs = [ "server-harness.mjs" ], | ||
) | ||
|
||
npm_package( | ||
name = "test_js", | ||
srcs = [":server-harness_js_lib"], | ||
publishable = False, | ||
visibility = ["//visibility:public"], | ||
) |
This file contains 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,18 @@ | ||
sh_test( | ||
name = "helloworld_compile_test", | ||
size = "small", | ||
srcs = ["compile-test.sh"], | ||
args = [ | ||
"$(location //src/workerd/server:workerd)", | ||
"$(location //samples:helloworld/config.capnp)", | ||
"$(location compile-helloworld-test.ok)", | ||
], | ||
data = [ | ||
"compile-helloworld-test.ok", | ||
"//src/workerd/server:workerd", | ||
"//samples:helloworld/config.capnp", | ||
"//samples:helloworld/worker.js", | ||
], | ||
tags = ["no-qemu"], | ||
) | ||
|
This file contains 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,19 @@ | ||
load("@aspect_rules_js//js:defs.bzl", "js_test") | ||
|
||
js_test( | ||
name = "inspector-test", | ||
entry_point = "driver.mjs", | ||
env = { | ||
"WORKERD_BINARY": "$(rootpath //src/workerd/server:workerd)", | ||
"WORKERD_CONFIG": "$(rootpath :config.capnp)", | ||
}, | ||
data = [ | ||
"//:node_modules/chrome-remote-interface", | ||
"//:node_modules/@workerd/test", | ||
"//src/workerd/server:workerd", | ||
":config.capnp", | ||
":index.mjs", | ||
], | ||
tags = ["js-test"], | ||
) | ||
|
This file contains 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,19 @@ | ||
# config.capnp | ||
using Workerd = import "/workerd/workerd.capnp"; | ||
|
||
const config :Workerd.Config = ( | ||
services = [ | ||
( name = "main", worker = .worker ), | ||
], | ||
sockets = [ | ||
( name = "http", address = "*:0", http = (), service = "main" ), | ||
] | ||
); | ||
|
||
const worker :Workerd.Worker = ( | ||
modules = [ | ||
( name = "./index.mjs", esModule = embed "index.mjs" ) | ||
], | ||
compatibilityDate = "2024-01-01", | ||
compatibilityFlags = ["nodejs_compat"], | ||
); |
This file contains 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,89 @@ | ||
import { env } from "node:process"; | ||
import { beforeEach, afterEach, test } from "node:test"; | ||
import assert from "node:assert"; | ||
import CDP from "chrome-remote-interface"; | ||
import { WorkerdServerHarness } from "@workerd/test/server-harness.mjs"; | ||
|
||
// Globals that are reset for each test. | ||
let workerd; | ||
let inspectorClient; | ||
|
||
assert(env.WORKERD_BINARY !== undefined, "You must set the WORKERD_BINARY environment variable."); | ||
assert(env.WORKERD_CONFIG !== undefined, "You must set the WORKERD_CONFIG environment variable."); | ||
|
||
// Start workerd and connect to its inspector port with our CDP library. | ||
beforeEach(async () => { | ||
workerd = new WorkerdServerHarness({ | ||
workerdBinary: env.WORKERD_BINARY, | ||
workerdConfig: env.WORKERD_CONFIG, | ||
|
||
// Hard-coded to match a socket name expected in the `workerdConfig` file. | ||
listenPortNames: [ "http" ], | ||
}); | ||
|
||
await workerd.start(); | ||
|
||
inspectorClient = await CDP({ | ||
port: await workerd.getListenInspectorPort(), | ||
|
||
// Hard-coded to match a service name expected in the `workerdConfig` file. | ||
target: "/main", | ||
|
||
// Required to avoid trying to load the Protocol (schema, I guess?) from workerd, which doesn't | ||
// implement the inspector protocol message in question. | ||
local: true, | ||
}); | ||
}); | ||
|
||
// Stop both our CDP client and workerd. | ||
afterEach(async () => { | ||
await inspectorClient.close(); | ||
inspectorClient = null; | ||
|
||
const [code, signal] = await workerd.stop(); | ||
assert(code === 0 || signal === "SIGTERM"); | ||
workerd = null; | ||
}); | ||
|
||
test("Profiler mostly sees deriveBits() frames", async () => { | ||
// Enable and start profiling. | ||
await inspectorClient.Profiler.enable(); | ||
await inspectorClient.Profiler.start(); | ||
|
||
// Drive the worker with a test request. A single one is sufficient. | ||
let httpPort = await workerd.getListenPort("http"); | ||
const response = await fetch(`http://localhost:${httpPort}`); | ||
await response.arrayBuffer(); | ||
|
||
// Stop and disable profiling. | ||
const profile = await inspectorClient.Profiler.stop(); | ||
await inspectorClient.Profiler.disable(); | ||
|
||
// Figure out which function name was most frequently sampled. | ||
let hitCountMap = new Map(); | ||
|
||
for (let node of profile.profile.nodes) { | ||
if (hitCountMap.get(node.callFrame.functionName) === undefined) { | ||
hitCountMap.set(node.callFrame.functionName, 0); | ||
} | ||
hitCountMap.set(node.callFrame.functionName, | ||
hitCountMap.get(node.callFrame.functionName) + node.hitCount); | ||
} | ||
|
||
let max = { | ||
name: null, | ||
count: 0, | ||
}; | ||
|
||
for (let [name, count] of hitCountMap) { | ||
if (count > max.count) { | ||
max.name = name; | ||
max.count = count; | ||
} | ||
} | ||
|
||
// The most CPU-intensive function our test script runs is `deriveBits()`, so we expect that to be | ||
// the most frequently sampled function. | ||
assert.equal(max.name, "deriveBits"); | ||
assert.notEqual(max.count, 0); | ||
}); |
This file contains 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,23 @@ | ||
// index.mjs | ||
import { Buffer } from "node:buffer"; | ||
|
||
const encoder = new TextEncoder(); | ||
|
||
async function pbkdf2Derive(password) { | ||
const passwordArray = encoder.encode(password); | ||
const passwordKey = await crypto.subtle.importKey( | ||
"raw", passwordArray, "PBKDF2", false, ["deriveBits"] | ||
); | ||
const saltArray = crypto.getRandomValues(new Uint8Array(16)); | ||
const keyBuffer = await crypto.subtle.deriveBits( | ||
{ name: "PBKDF2", hash: "SHA-256", salt: saltArray, iterations: 1_000_000 }, | ||
passwordKey, 256 | ||
); | ||
return Buffer.from(keyBuffer).toString("base64"); | ||
} | ||
|
||
export default { | ||
async fetch(request, env, ctx) { | ||
return new Response(await pbkdf2Derive("hello!")); | ||
} | ||
} |
Oops, something went wrong.