






















@@ -0,0 +1,96 @@
1+import { performance } from "node:perf_hooks";
2+import {
3+areDiagnosticsEnabledForProcess,
4+emitDiagnosticEvent,
5+type DiagnosticPhaseDetails,
6+type DiagnosticPhaseSnapshot,
7+} from "../infra/diagnostic-events.js";
8+9+const RECENT_PHASE_CAPACITY = 40;
10+11+type ActiveDiagnosticPhase = {
12+name: string;
13+startedAt: number;
14+startedWallMs: number;
15+cpuStarted: NodeJS.CpuUsage;
16+details?: DiagnosticPhaseDetails;
17+};
18+19+let activePhaseStack: ActiveDiagnosticPhase[] = [];
20+let recentPhases: DiagnosticPhaseSnapshot[] = [];
21+22+function roundMetric(value: number, digits = 1): number {
23+if (!Number.isFinite(value)) {
24+return 0;
25+}
26+const factor = 10 ** digits;
27+return Math.round(value * factor) / factor;
28+}
29+30+function pushRecentPhase(snapshot: DiagnosticPhaseSnapshot): void {
31+recentPhases.push(snapshot);
32+if (recentPhases.length > RECENT_PHASE_CAPACITY) {
33+recentPhases = recentPhases.slice(-RECENT_PHASE_CAPACITY);
34+}
35+}
36+37+export function getCurrentDiagnosticPhase(): string | undefined {
38+return activePhaseStack.at(-1)?.name;
39+}
40+41+export function getRecentDiagnosticPhases(limit = 8): DiagnosticPhaseSnapshot[] {
42+return recentPhases.slice(-Math.max(0, limit)).map((phase) => ({ ...phase }));
43+}
44+45+export function recordDiagnosticPhase(snapshot: DiagnosticPhaseSnapshot): void {
46+pushRecentPhase(snapshot);
47+if (!areDiagnosticsEnabledForProcess()) {
48+return;
49+}
50+emitDiagnosticEvent({
51+type: "diagnostic.phase.completed",
52+ ...snapshot,
53+});
54+}
55+56+export async function withDiagnosticPhase<T>(
57+name: string,
58+run: () => Promise<T> | T,
59+details?: DiagnosticPhaseDetails,
60+): Promise<T> {
61+const active: ActiveDiagnosticPhase = {
62+ name,
63+startedAt: Date.now(),
64+startedWallMs: performance.now(),
65+cpuStarted: process.cpuUsage(),
66+ details,
67+};
68+activePhaseStack.push(active);
69+try {
70+return await run();
71+} finally {
72+const endedAt = Date.now();
73+const durationMs = roundMetric(performance.now() - active.startedWallMs, 1);
74+const cpu = process.cpuUsage(active.cpuStarted);
75+const cpuUserMs = roundMetric(cpu.user / 1_000, 1);
76+const cpuSystemMs = roundMetric(cpu.system / 1_000, 1);
77+const cpuTotalMs = roundMetric(cpuUserMs + cpuSystemMs, 1);
78+activePhaseStack = activePhaseStack.filter((entry) => entry !== active);
79+recordDiagnosticPhase({
80+ name,
81+startedAt: active.startedAt,
82+ endedAt,
83+ durationMs,
84+ cpuUserMs,
85+ cpuSystemMs,
86+ cpuTotalMs,
87+cpuCoreRatio: roundMetric(cpuTotalMs / Math.max(1, durationMs), 3),
88+details: active.details,
89+});
90+}
91+}
92+93+export function resetDiagnosticPhasesForTest(): void {
94+activePhaseStack = [];
95+recentPhases = [];
96+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。