chore(coding-agent): refine startup profiling tooling
This commit is contained in:
@@ -37,6 +37,7 @@ Options:
|
|||||||
--isolated-agent-dir Use a fresh temporary agent dir instead of the normal one
|
--isolated-agent-dir Use a fresh temporary agent dir instead of the normal one
|
||||||
--no-offline Do not force PI_OFFLINE=1 / PI_SKIP_VERSION_CHECK=1
|
--no-offline Do not force PI_OFFLINE=1 / PI_SKIP_VERSION_CHECK=1
|
||||||
--skip-build Reuse the current dist/cli.js without rebuilding first (Node only)
|
--skip-build Reuse the current dist/cli.js without rebuilding first (Node only)
|
||||||
|
--cpu-profile Write CPU profiles for benchmark runs
|
||||||
--help Show this help
|
--help Show this help
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
@@ -81,6 +82,7 @@ function parseArgs(argv) {
|
|||||||
runtime: "auto",
|
runtime: "auto",
|
||||||
agentDir: undefined,
|
agentDir: undefined,
|
||||||
isolatedAgentDir: false,
|
isolatedAgentDir: false,
|
||||||
|
cpuProfile: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let index = 0; index < argv.length; index++) {
|
for (let index = 0; index < argv.length; index++) {
|
||||||
@@ -106,6 +108,11 @@ function parseArgs(argv) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg === "--cpu-profile") {
|
||||||
|
options.cpuProfile = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(arg === "--mode" ||
|
(arg === "--mode" ||
|
||||||
arg === "--runs" ||
|
arg === "--runs" ||
|
||||||
@@ -222,14 +229,29 @@ async function waitForExit(child, errorPrefix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function runBuild() {
|
async function runBuild() {
|
||||||
process.stdout.write("Building packages/coding-agent...\n");
|
process.stdout.write("Building packages/tui, packages/ai, packages/agent, and packages/coding-agent...\n");
|
||||||
const startedAt = performance.now();
|
const startedAt = performance.now();
|
||||||
const child = spawn("npm", ["run", "build"], {
|
const child = spawn(
|
||||||
cwd: packageDir,
|
"npm",
|
||||||
env: process.env,
|
[
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
"run",
|
||||||
shell: process.platform === "win32",
|
"build",
|
||||||
});
|
"--workspace",
|
||||||
|
"packages/tui",
|
||||||
|
"--workspace",
|
||||||
|
"packages/ai",
|
||||||
|
"--workspace",
|
||||||
|
"packages/agent",
|
||||||
|
"--workspace",
|
||||||
|
"packages/coding-agent",
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cwd: repoRoot,
|
||||||
|
env: process.env,
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
shell: process.platform === "win32",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
let stderr = "";
|
let stderr = "";
|
||||||
@@ -256,34 +278,32 @@ async function runBuild() {
|
|||||||
process.stdout.write(`Build completed in ${formatMs(performance.now() - startedAt)}\n`);
|
process.stdout.write(`Build completed in ${formatMs(performance.now() - startedAt)}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRuntimeCommand(runtime, mode, profileDir, profileName) {
|
function getRuntimeCommand(runtime, mode, profileDir, profileName, cpuProfile) {
|
||||||
const benchmarkArgs = ["--no-session"];
|
const benchmarkArgs = ["--no-session"];
|
||||||
if (mode === "rpc") {
|
if (mode === "rpc") {
|
||||||
benchmarkArgs.push("--mode", "rpc");
|
benchmarkArgs.push("--mode", "rpc");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime === "bun") {
|
if (runtime === "bun") {
|
||||||
|
const args = [];
|
||||||
|
if (cpuProfile) {
|
||||||
|
args.push("--cpu-prof", `--cpu-prof-dir=${profileDir}`, `--cpu-prof-name=${profileName}`);
|
||||||
|
}
|
||||||
|
args.push(srcCliPath, ...benchmarkArgs);
|
||||||
return {
|
return {
|
||||||
executable: "bun",
|
executable: "bun",
|
||||||
args: [
|
args,
|
||||||
"--cpu-prof",
|
|
||||||
`--cpu-prof-dir=${profileDir}`,
|
|
||||||
`--cpu-prof-name=${profileName}`,
|
|
||||||
srcCliPath,
|
|
||||||
...benchmarkArgs,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const args = [];
|
||||||
|
if (cpuProfile) {
|
||||||
|
args.push("--cpu-prof", `--cpu-prof-dir=${profileDir}`, `--cpu-prof-name=${profileName}`);
|
||||||
|
}
|
||||||
|
args.push(distCliPath, ...benchmarkArgs);
|
||||||
return {
|
return {
|
||||||
executable: process.execPath,
|
executable: process.execPath,
|
||||||
args: [
|
args,
|
||||||
"--cpu-prof",
|
|
||||||
`--cpu-prof-dir=${profileDir}`,
|
|
||||||
`--cpu-prof-name=${profileName}`,
|
|
||||||
distCliPath,
|
|
||||||
...benchmarkArgs,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +334,7 @@ async function runTuiBenchmarkRun({ runtime, runIndex, measuredIndex, options, p
|
|||||||
mkdirSync(isolatedAgentDir, { recursive: true });
|
mkdirSync(isolatedAgentDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = getRuntimeCommand(runtime, "tui", profileDir, profileName);
|
const command = getRuntimeCommand(runtime, "tui", profileDir, profileName, options.cpuProfile);
|
||||||
const child = spawn(command.executable, command.args, {
|
const child = spawn(command.executable, command.args, {
|
||||||
cwd: packageDir,
|
cwd: packageDir,
|
||||||
env: createBenchmarkEnv(options, isolatedAgentDir),
|
env: createBenchmarkEnv(options, isolatedAgentDir),
|
||||||
@@ -337,8 +357,8 @@ async function runTuiBenchmarkRun({ runtime, runIndex, measuredIndex, options, p
|
|||||||
throw new Error(stderr.trim() || `Benchmark child exited with code ${exitCode}`);
|
throw new Error(stderr.trim() || `Benchmark child exited with code ${exitCode}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const profilePath = join(profileDir, profileName);
|
const profilePath = options.cpuProfile ? join(profileDir, profileName) : undefined;
|
||||||
if (!existsSync(profilePath)) {
|
if (profilePath && !existsSync(profilePath)) {
|
||||||
throw new Error(`CPU profile was not written: ${profilePath}`);
|
throw new Error(`CPU profile was not written: ${profilePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +393,7 @@ async function runRpcBenchmarkRun({ runtime, runIndex, measuredIndex, options, p
|
|||||||
mkdirSync(isolatedAgentDir, { recursive: true });
|
mkdirSync(isolatedAgentDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = getRuntimeCommand(runtime, "rpc", profileDir, profileName);
|
const command = getRuntimeCommand(runtime, "rpc", profileDir, profileName, options.cpuProfile);
|
||||||
const child = spawn(command.executable, command.args, {
|
const child = spawn(command.executable, command.args, {
|
||||||
cwd: packageDir,
|
cwd: packageDir,
|
||||||
env: createBenchmarkEnv(options, isolatedAgentDir),
|
env: createBenchmarkEnv(options, isolatedAgentDir),
|
||||||
@@ -439,8 +459,8 @@ async function runRpcBenchmarkRun({ runtime, runIndex, measuredIndex, options, p
|
|||||||
throw new Error(stderr.trim() || `Benchmark child exited with code ${exitCode}`);
|
throw new Error(stderr.trim() || `Benchmark child exited with code ${exitCode}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const profilePath = join(profileDir, profileName);
|
const profilePath = options.cpuProfile ? join(profileDir, profileName) : undefined;
|
||||||
if (!existsSync(profilePath)) {
|
if (profilePath && !existsSync(profilePath)) {
|
||||||
throw new Error(`CPU profile was not written: ${profilePath}`);
|
throw new Error(`CPU profile was not written: ${profilePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,8 +547,10 @@ async function main() {
|
|||||||
process.stdout.write(` runtime: ${runtime}\n`);
|
process.stdout.write(` runtime: ${runtime}\n`);
|
||||||
process.stdout.write(` mode: ${options.mode}\n`);
|
process.stdout.write(` mode: ${options.mode}\n`);
|
||||||
process.stdout.write(` elapsed: ${formatMs(measuredRuns[0].elapsedMs)}\n`);
|
process.stdout.write(` elapsed: ${formatMs(measuredRuns[0].elapsedMs)}\n`);
|
||||||
process.stdout.write(` selected profile: ${toDisplayPath(maxElapsedRun.profilePath)}\n`);
|
if (options.cpuProfile && maxElapsedRun.profilePath) {
|
||||||
process.stdout.write(` profiles dir: ${toDisplayPath(profileDir)}\n`);
|
process.stdout.write(` selected profile: ${toDisplayPath(maxElapsedRun.profilePath)}\n`);
|
||||||
|
process.stdout.write(` profiles dir: ${toDisplayPath(profileDir)}\n`);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,8 +561,10 @@ async function main() {
|
|||||||
process.stdout.write(` elapsed median: ${formatMs(elapsedSummary.median)}\n`);
|
process.stdout.write(` elapsed median: ${formatMs(elapsedSummary.median)}\n`);
|
||||||
process.stdout.write(` elapsed avg: ${formatMs(elapsedSummary.avg)}\n`);
|
process.stdout.write(` elapsed avg: ${formatMs(elapsedSummary.avg)}\n`);
|
||||||
process.stdout.write(` elapsed max: ${formatMs(elapsedSummary.max)}\n`);
|
process.stdout.write(` elapsed max: ${formatMs(elapsedSummary.max)}\n`);
|
||||||
process.stdout.write(` selected profile: ${toDisplayPath(maxElapsedRun.profilePath)}\n`);
|
if (options.cpuProfile && maxElapsedRun.profilePath) {
|
||||||
process.stdout.write(` profiles dir: ${toDisplayPath(profileDir)}\n`);
|
process.stdout.write(` selected profile: ${toDisplayPath(maxElapsedRun.profilePath)}\n`);
|
||||||
|
process.stdout.write(` profiles dir: ${toDisplayPath(profileDir)}\n`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user