diff --git a/src/workerd/server/tests/inspector/driver.mjs b/src/workerd/server/tests/inspector/driver.mjs index 90c7e0a3abc0..96fa2801c1f5 100644 --- a/src/workerd/server/tests/inspector/driver.mjs +++ b/src/workerd/server/tests/inspector/driver.mjs @@ -54,68 +54,71 @@ async function connectInspector(port) { }); } -// TODO(soon): This test reproduces a null pointer dereference in workerd (possibly the same issue -// as https://github.com/cloudflare/workerd/issues/2564), but the test doesn't fail. :( -test('Can repeatedly connect and disconnect to the inspector port', async () => { - for (let i = 0; i < 5; ++i) { - let inspectorClient = await connectInspector( - await workerd.getListenInspectorPort() +async function profileAndExpectDeriveBitsFrames(inspectorClient) { + // 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 ); + } - // Drive the worker with a test request. - let httpPort = await workerd.getListenPort('http'); - const response = await fetch(`http://localhost:${httpPort}`); - let body = await response.arrayBuffer(); - console.log(body); + let max = { + name: null, + count: 0, + }; - await inspectorClient.close(); + 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); +} + +// Regression test for https://github.com/cloudflare/workerd/issues/1754. +// +// At one time, workerd produced only "(program)" frames. +test('Profiler mostly sees deriveBits() frames', async () => { + let inspectorClient = await connectInspector( + await workerd.getListenInspectorPort() + ); + await profileAndExpectDeriveBitsFrames(inspectorClient); + await inspectorClient.close(); }); -// TODO(soon): Re-enable once https://github.com/cloudflare/workerd/issues/2564 is solved. -// test("Profiler mostly sees deriveBits() frames", async () => { -// let inspectorClient = await connectInspector(await workerd.getListenInspectorPort()); - -// // 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); - -// await inspectorClient.close(); -// }); +// Regression test for https://github.com/cloudflare/workerd/issues/2564. +// +// At one time, workerd segfaulted on the second inspector connection. +test('Can repeatedly reconnect the inspector and profiling still works', async () => { + for (let i = 0; i < 4; ++i) { + let inspectorClient = await connectInspector( + await workerd.getListenInspectorPort() + ); + await profileAndExpectDeriveBitsFrames(inspectorClient); + await inspectorClient.close(); + } +});