| 1 | import assert from "node:assert/strict" |
| 2 | import { writeFileSync } from "node:fs" |
| 3 | import { Session } from "node:inspector/promises" |
| 4 | import { fixture, validate } from "./fixtures.mts" |
| 5 | |
| 6 | const [mode, name, countArgument = "1000", intervalArgument = "0", profilePath] = process.argv.slice(2) |
| 7 | if (mode === "validate") { |
| 8 | validate(name) |
| 9 | process.stdout.write(JSON.stringify({ validated: name })) |
| 10 | } else { |
| 11 | assert.equal(mode, "measure") |
| 12 | const count = Number(countArgument) |
| 13 | const interval = Number(intervalArgument) |
| 14 | assert.ok(Number.isSafeInteger(count) && count > 0) |
| 15 | assert.ok(Number.isSafeInteger(interval) && interval >= 0) |
| 16 | const { build } = fixture(name) |
| 17 | const roots = new Array(count) |
| 18 | // This frame delimits the construction samples. Inspector and hrtime clocks |
| 19 | // have different origins on some platforms, so they must not be compared. |
| 20 | function constructBatch() { |
| 21 | const start = process.hrtime.bigint() |
| 22 | for (let index = 0; index < count; index++) roots[index] = build(index) |
| 23 | return Number(process.hrtime.bigint() - start) / 1e6 |
| 24 | } |
| 25 | const session = new Session() |
| 26 | try { |
| 27 | if (interval > 0) { |
| 28 | assert.ok(profilePath) |
| 29 | session.connect() |
| 30 | await session.post("Profiler.enable") |
| 31 | await session.post("Profiler.setSamplingInterval", { interval }) |
| 32 | await session.post("Profiler.start") |
| 33 | } |
| 34 | const elapsedMs = constructBatch() |
| 35 | if (interval > 0) { |
| 36 | const { profile } = await session.post("Profiler.stop") |
| 37 | writeFileSync(profilePath, JSON.stringify(profile)) |
| 38 | } |
| 39 | // Do not prepare a decoder, traverse ASTs, or warm the construction path |
| 40 | // before timing. Full semantic validation runs in separate processes. |
| 41 | assert.equal(roots.length, count) |
| 42 | for (const root of roots) assert.equal(typeof root, "function") |
| 43 | assert.notEqual(roots[0], count > 1 ? roots[count - 1] : undefined) |
| 44 | process.stdout.write(JSON.stringify({ name, count, interval, elapsedMs, profilePath })) |
| 45 | } finally { |
| 46 | session.disconnect() |
| 47 | } |
| 48 | } |