/** * Receiver for Godot's own remote-debugger profiler stream. * * `run_project({ profiling: true })` binds this listener first and passes * `--remote-debug tcp://127.0.0.1:` to the spawned engine, so the * measurements are the stock editor ones — no engine build, no addon, and * nothing injected into the project. Attached sessions cannot profile: the * debugger channel only exists if it was on the command line at launch. * * Godot pauses the game on a script error or `breakpoint` while a debugger is * connected, so every `debug_enter` is answered with `continue` — profiling * must never turn a runtime error into a frozen window. */ export type ProfilerErrorCode = 'bad_args' | 'profile_busy' | 'profile_not_started' | 'profile_timeout' | 'profile_disconnected' | 'profile_no_frames' | 'profile_bad_frame'; export declare class ProfilerError extends Error { readonly code: ProfilerErrorCode; constructor(code: ProfilerErrorCode, message: string); } export type ProfileSort = 'selfMs' | 'totalMs' | 'calls'; export declare const PROFILE_SORTS: readonly ProfileSort[]; export declare const PROFILE_MAX_SECONDS = 60; export declare const CAPTURE_LIMIT_MIN = 16; export declare const CAPTURE_LIMIT_MAX = 512; export declare const PROFILE_TOP_MAX = 100; export interface ProfilePeak { frame: number; calls: number; selfMs: number; totalMs: number; } export interface ProfileRow { signature: string; function: string; file: string; line: number; sourceResolved: boolean; calls: number; selfMs: number; totalMs: number; callsPerFrame: number; selfMsPerFrame: number; totalMsPerFrame: number; msPerCall: number; /** Inclusive share of an average frame, the editor's "Frame %" measure. */ percentOfFrame: number; peak: ProfilePeak | null; } /** Average and worst value of one per-frame measurement across the capture. */ export interface ProfileStat { avg: number; max: number; } /** The engine's own frame breakdown — the editor's "Frame Time" category. */ export interface FrameTimings { frameMs: number; processMs: number; physicsMs: number; physicsFrameMs: number; scriptMs: number; } export interface ProfileServer { name: string; msPerFrame: number; functions: Array<{ name: string; msPerFrame: number; }>; } export interface ProfileStartResult { active: boolean; maxSeconds: number; firstFrame: number | null; captureLimit: number; } export interface ProfileResult { seconds: number; frames: number; framesReceived: number; firstFrame: number | null; lastFrame: number | null; frameGaps: number; /** * Debugger packets dropped because the codec could not represent them. A * non-zero value means the capture may be missing frames it was sent. */ undecodablePackets: number; captureLimit: number; limitReached: boolean; sort: ProfileSort; functionsReceived: number; unresolvedFunctions: number; /** Per-frame engine breakdown, averaged over the capture and at its worst. */ frame: Record; /** Server-side timings (physics, audio, …), averaged per frame. */ servers: ProfileServer[]; rows: ProfileRow[]; worstFrame: ({ frame: number; } & FrameTimings & { rows: FrameRow[]; }) | null; } /** One function's numbers inside a single received frame. */ interface FrameRow { signature: string; function: string; file: string; line: number; sourceResolved: boolean; calls: number; selfMs: number; totalMs: number; } export declare class DebuggerProfiler { private readonly server; readonly port: number; private socket; /** Pending bytes, joined only once a whole frame has arrived (see `receive`). */ private rxChunks; private rxLength; private threadId; private processId; private state; private error; private closed; private lastMessage; private lastDecodeError; private undecodable; private signatures; private capture; private autoStopTimer; private waiters; private constructor(); /** Bind a loopback listener the spawned engine will dial back into. */ static create(): Promise; /** * A finished capture is readable even once the engine is gone — `stop` only * re-ranks data already folded, and the capture worth reading is often the * one taken right before a crash. */ get hasResult(): boolean; get connected(): boolean; /** * Enable the engine profiler and return once frames are arriving. The * capture stops itself after `seconds` so a forgotten `start_profiler` * cannot profile the rest of the session. */ start(seconds: number, captureLimit: number): Promise; /** * Stop an active capture (or re-read a finished one) and rank the functions. * The engine's own accumulated totals close the capture, so this waits for * the `profile_total` packet rather than summing the last frame. */ stop(top: number, sort: ProfileSort): Promise; /** * Wait out a known capture's close and rank it. Takes the capture rather than * re-reading `this.capture` so a caller that snapshotted one cannot be handed * a different capture's numbers. */ private finish; /** `start` + wait out the window + `stop`, for a one-shot capture. */ captureWindow(seconds: number, top: number, sort: ProfileSort, captureLimit?: number): Promise; close(): void; private accept; /** Read one pending byte without joining the chunk list. */ private byteAt; private receive; private handle; private summarize; /** Read behind a call so `start`'s own state assignment doesn't narrow it. */ private isCapturing; private send; private write; private autoStop; private armAutoStop; private clearAutoStop; /** * Close a capture out. Called on the engine's `profile_total`, and again if * that packet never arrives — a capture left in `stopping` would reject every * later `start` as busy while `stop` kept timing out, and the advice on that * error points straight back at `stop`. */ private finalize; private fail; private wait; private notify; private rejectWaiters; } export {}; //# sourceMappingURL=profiler.d.ts.map