/ utils / profilerBase.ts
profilerBase.ts
 1  /**
 2   * Shared infrastructure for profiler modules (startupProfiler, queryProfiler,
 3   * headlessProfiler). All three use the same perf_hooks timeline and the same
 4   * line format for detailed reports.
 5   */
 6  
 7  import type { performance as PerformanceType } from 'perf_hooks'
 8  import { formatFileSize } from './format.js'
 9  
10  // Lazy-load performance API only when profiling is enabled.
11  // Shared across all profilers — perf_hooks.performance is a process-wide singleton.
12  let performance: typeof PerformanceType | null = null
13  
14  export function getPerformance(): typeof PerformanceType {
15    if (!performance) {
16      // eslint-disable-next-line @typescript-eslint/no-require-imports
17      performance = require('perf_hooks').performance
18    }
19    return performance!
20  }
21  
22  export function formatMs(ms: number): string {
23    return ms.toFixed(3)
24  }
25  
26  /**
27   * Render a single timeline line in the shared profiler report format:
28   *   [+  total.ms] (+  delta.ms) name [extra] [| RSS: .., Heap: ..]
29   *
30   * totalPad/deltaPad control the padStart width so callers can align columns
31   * based on their expected magnitude (startup uses 8/7, query uses 10/9).
32   */
33  export function formatTimelineLine(
34    totalMs: number,
35    deltaMs: number,
36    name: string,
37    memory: NodeJS.MemoryUsage | undefined,
38    totalPad: number,
39    deltaPad: number,
40    extra = '',
41  ): string {
42    const memInfo = memory
43      ? ` | RSS: ${formatFileSize(memory.rss)}, Heap: ${formatFileSize(memory.heapUsed)}`
44      : ''
45    return `[+${formatMs(totalMs).padStart(totalPad)}ms] (+${formatMs(deltaMs).padStart(deltaPad)}ms) ${name}${extra}${memInfo}`
46  }