103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
||
import { bunEnv, bunExe, isWindows, tempDir } from "harness";
|
||
import { join } from "node:path";
|
||
|
||
// @datadog/[email protected] ships node-gyp-build prebuilds for linux-{x64,arm64}
|
||
// (glibc + musl), darwin-{x64,arm64} and win32-x64 at ABI 147, matching Bun's
|
||
// process.versions.modules. win32-arm64 has no prebuild — skip there rather
|
||
// than fall through to a node-gyp source build.
|
||
const hasPrebuild = !(isWindows && process.arch === "arm64");
|
||
|
||
describe.skipIf(!hasPrebuild)("@datadog/pprof", () => {
|
||
test("TimeProfiler start/stop returns a populated profile", async () => {
|
||
using dir = tempDir("datadog-pprof", {
|
||
"package.json": JSON.stringify({
|
||
name: "datadog-pprof-fixture",
|
||
version: "0.0.0",
|
||
dependencies: {
|
||
"@datadog/pprof": "5.17.0",
|
||
},
|
||
trustedDependencies: ["@datadog/pprof"],
|
||
}),
|
||
"index.js": /* js */ `
|
||
const { time } = require("@datadog/pprof");
|
||
|
||
function hotLoop() {
|
||
// Busy-spin long enough for the 1ms wall sampler to capture real
|
||
// samples on slow debug/ASAN builds; this is CPU work, not a sleep.
|
||
const start = Date.now();
|
||
let acc = 0;
|
||
while (Date.now() - start < 300) {
|
||
for (let i = 0; i < 1000; i++) acc += Math.sqrt(i);
|
||
}
|
||
return acc;
|
||
}
|
||
|
||
time.start({ intervalMicros: 1000, durationMillis: 60000 });
|
||
hotLoop();
|
||
const profile = time.stop();
|
||
|
||
const strings = profile.stringTable.strings;
|
||
const summary = {
|
||
sampleCount: profile.sample.length,
|
||
locationCount: profile.location.length,
|
||
functionCount: profile.function.length,
|
||
stringCount: strings.length,
|
||
hasHotLoop: strings.includes("hotLoop"),
|
||
period: Number(profile.period),
|
||
};
|
||
process.stdout.write(JSON.stringify(summary) + "\\n");
|
||
`,
|
||
});
|
||
|
||
{
|
||
await using install = Bun.spawn({
|
||
cmd: [bunExe(), "install"],
|
||
env: bunEnv,
|
||
cwd: String(dir),
|
||
stdout: "pipe",
|
||
stderr: "pipe",
|
||
});
|
||
const [stdout, stderr, exitCode] = await Promise.all([
|
||
install.stdout.text(),
|
||
install.stderr.text(),
|
||
install.exited,
|
||
]);
|
||
if (exitCode !== 0) {
|
||
throw new Error(`bun install failed (exit ${exitCode})\nstdout:\n${stdout}\nstderr:\n${stderr}`);
|
||
}
|
||
}
|
||
|
||
await using proc = Bun.spawn({
|
||
cmd: [bunExe(), join(String(dir), "index.js")],
|
||
env: bunEnv,
|
||
cwd: String(dir),
|
||
stdout: "pipe",
|
||
stderr: "pipe",
|
||
});
|
||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||
|
||
expect(stderr).toBe("");
|
||
|
||
const summary = JSON.parse(stdout.trim());
|
||
expect(summary).toEqual({
|
||
sampleCount: expect.any(Number),
|
||
locationCount: expect.any(Number),
|
||
functionCount: expect.any(Number),
|
||
stringCount: expect.any(Number),
|
||
hasHotLoop: true,
|
||
period: expect.any(Number),
|
||
});
|
||
expect(summary.sampleCount).toBeGreaterThan(0);
|
||
expect(summary.locationCount).toBeGreaterThan(0);
|
||
expect(summary.functionCount).toBeGreaterThan(0);
|
||
expect(summary.stringCount).toBeGreaterThan(0);
|
||
// serializeTimeProfile recomputes intervalMicros from wall-clock/hit-count,
|
||
// clamps it to [intervalMicros, 2*intervalMicros], then ×1000 → nanoseconds.
|
||
expect(summary.period).toBeGreaterThanOrEqual(1_000_000);
|
||
expect(summary.period).toBeLessThanOrEqual(2_000_000);
|
||
|
||
expect(exitCode).toBe(0);
|
||
}, 120_000);
|
||
});
|