chore(coding-agent): add startup phase timings

This commit is contained in:
Mario Zechner
2026-03-21 22:55:22 +01:00
parent 6dc43d6dd1
commit 648e96a611
2 changed files with 23 additions and 1 deletions

View File

@@ -7,6 +7,12 @@ const ENABLED = process.env.PI_TIMING === "1";
const timings: Array<{ label: string; ms: number }> = []; const timings: Array<{ label: string; ms: number }> = [];
let lastTime = Date.now(); let lastTime = Date.now();
export function resetTimings(): void {
if (!ENABLED) return;
timings.length = 0;
lastTime = Date.now();
}
export function time(label: string): void { export function time(label: string): void {
if (!ENABLED) return; if (!ENABLED) return;
const now = Date.now(); const now = Date.now();

View File

@@ -27,7 +27,7 @@ import { DefaultResourceLoader } from "./core/resource-loader.js";
import { type CreateAgentSessionOptions, createAgentSession } from "./core/sdk.js"; import { type CreateAgentSessionOptions, createAgentSession } from "./core/sdk.js";
import { SessionManager } from "./core/session-manager.js"; import { SessionManager } from "./core/session-manager.js";
import { SettingsManager } from "./core/settings-manager.js"; import { SettingsManager } from "./core/settings-manager.js";
import { printTimings, time } from "./core/timings.js"; import { printTimings, resetTimings, time } from "./core/timings.js";
import { allTools } from "./core/tools/index.js"; import { allTools } from "./core/tools/index.js";
import { runMigrations, showDeprecationWarnings } from "./migrations.js"; import { runMigrations, showDeprecationWarnings } from "./migrations.js";
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js"; import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
@@ -622,6 +622,7 @@ async function handleConfigCommand(args: string[]): Promise<boolean> {
} }
export async function main(args: string[]) { export async function main(args: string[]) {
resetTimings();
const offlineMode = args.includes("--offline") || isTruthyEnvFlag(process.env.PI_OFFLINE); const offlineMode = args.includes("--offline") || isTruthyEnvFlag(process.env.PI_OFFLINE);
if (offlineMode) { if (offlineMode) {
process.env.PI_OFFLINE = "1"; process.env.PI_OFFLINE = "1";
@@ -638,6 +639,7 @@ export async function main(args: string[]) {
// First pass: parse args to get --extension paths // First pass: parse args to get --extension paths
const firstPass = parseArgs(args); const firstPass = parseArgs(args);
time("parseArgs.firstPass");
const shouldTakeOverStdout = firstPass.mode !== undefined || firstPass.print || !process.stdin.isTTY; const shouldTakeOverStdout = firstPass.mode !== undefined || firstPass.print || !process.stdin.isTTY;
if (shouldTakeOverStdout) { if (shouldTakeOverStdout) {
takeOverStdout(); takeOverStdout();
@@ -645,6 +647,7 @@ export async function main(args: string[]) {
// Run migrations (pass cwd for project-local migrations) // Run migrations (pass cwd for project-local migrations)
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd()); const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
time("runMigrations");
// Early load extensions to discover their CLI flags // Early load extensions to discover their CLI flags
const cwd = process.cwd(); const cwd = process.cwd();
@@ -669,6 +672,7 @@ export async function main(args: string[]) {
systemPrompt: firstPass.systemPrompt, systemPrompt: firstPass.systemPrompt,
appendSystemPrompt: firstPass.appendSystemPrompt, appendSystemPrompt: firstPass.appendSystemPrompt,
}); });
time("createResourceLoader");
await resourceLoader.reload(); await resourceLoader.reload();
time("resourceLoader.reload"); time("resourceLoader.reload");
@@ -698,6 +702,7 @@ export async function main(args: string[]) {
// Second pass: parse args with extension flags // Second pass: parse args with extension flags
const parsed = parseArgs(args, extensionFlags); const parsed = parseArgs(args, extensionFlags);
time("parseArgs.secondPass");
// Pass flag values to extensions via runtime // Pass flag values to extensions via runtime
for (const [name, value] of parsed.unknownFlags) { for (const [name, value] of parsed.unknownFlags) {
@@ -729,6 +734,7 @@ export async function main(args: string[]) {
parsed.print = true; parsed.print = true;
} }
} }
time("readPipedStdin");
if (parsed.export) { if (parsed.export) {
let result: string; let result: string;
@@ -745,6 +751,7 @@ export async function main(args: string[]) {
} }
migrateKeybindingsConfigFile(agentDir); migrateKeybindingsConfigFile(agentDir);
time("migrateKeybindingsConfigFile");
if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) { if (parsed.mode === "rpc" && parsed.fileArgs.length > 0) {
console.error(chalk.red("Error: @file arguments are not supported in RPC mode")); console.error(chalk.red("Error: @file arguments are not supported in RPC mode"));
@@ -758,6 +765,7 @@ export async function main(args: string[]) {
settingsManager.getImageAutoResize(), settingsManager.getImageAutoResize(),
stdinContent, stdinContent,
); );
time("prepareInitialMessage");
const isInteractive = !parsed.print && parsed.mode === undefined; const isInteractive = !parsed.print && parsed.mode === undefined;
const startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK); const startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);
if (startupBenchmark && !isInteractive) { if (startupBenchmark && !isInteractive) {
@@ -766,6 +774,7 @@ export async function main(args: string[]) {
} }
const mode = parsed.mode || "text"; const mode = parsed.mode || "text";
initTheme(settingsManager.getTheme(), isInteractive); initTheme(settingsManager.getTheme(), isInteractive);
time("initTheme");
// Show deprecation warnings in interactive mode // Show deprecation warnings in interactive mode
if (isInteractive && deprecationWarnings.length > 0) { if (isInteractive && deprecationWarnings.length > 0) {
@@ -777,9 +786,11 @@ export async function main(args: string[]) {
if (modelPatterns && modelPatterns.length > 0) { if (modelPatterns && modelPatterns.length > 0) {
scopedModels = await resolveModelScope(modelPatterns, modelRegistry); scopedModels = await resolveModelScope(modelPatterns, modelRegistry);
} }
time("resolveModelScope");
// Create session manager based on CLI flags // Create session manager based on CLI flags
let sessionManager = await createSessionManager(parsed, cwd, extensionsResult); let sessionManager = await createSessionManager(parsed, cwd, extensionsResult);
time("createSessionManager");
// Handle --resume: show session picker // Handle --resume: show session picker
if (parsed.resume) { if (parsed.resume) {
@@ -821,6 +832,7 @@ export async function main(args: string[]) {
} }
const { session, modelFallbackMessage } = await createAgentSession(sessionOptions); const { session, modelFallbackMessage } = await createAgentSession(sessionOptions);
time("createAgentSession");
if (!isInteractive && !session.model) { if (!isInteractive && !session.model) {
console.error(chalk.red("No models available.")); console.error(chalk.red("No models available."));
@@ -846,6 +858,7 @@ export async function main(args: string[]) {
} }
if (mode === "rpc") { if (mode === "rpc") {
printTimings();
await runRpcMode(session); await runRpcMode(session);
} else if (isInteractive) { } else if (isInteractive) {
if (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) { if (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {
@@ -868,6 +881,8 @@ export async function main(args: string[]) {
}); });
if (startupBenchmark) { if (startupBenchmark) {
await interactiveMode.init(); await interactiveMode.init();
time("interactiveMode.init");
printTimings();
interactiveMode.stop(); interactiveMode.stop();
stopThemeWatcher(); stopThemeWatcher();
if (process.stdout.writableLength > 0) { if (process.stdout.writableLength > 0) {
@@ -882,6 +897,7 @@ export async function main(args: string[]) {
printTimings(); printTimings();
await interactiveMode.run(); await interactiveMode.run();
} else { } else {
printTimings();
const exitCode = await runPrintMode(session, { const exitCode = await runPrintMode(session, {
mode, mode,
messages: parsed.messages, messages: parsed.messages,