typescriptadvanced

Performance Measurement

Measure execution time with performance.now(), Performance API marks, measures, and PerformanceObserver.

typescript
import { performance, PerformanceObserver } from 'perf_hooks';

// Basic timing
const start = performance.now();
// ... some work
const end = performance.now();
console.log(`Duration: ${(end - start).toFixed(2)}ms`);

// Timer utility
function timer(label: string) {
  const start = performance.now();
  return {
    stop: () => {
      const ms = performance.now() - start;
      console.log(`${label}: ${ms.toFixed(2)}ms`);
      return ms;
    },
  };
}

// Performance marks and measures
performance.mark('app-start');

// Simulate work
function fibonacci(n: number): number {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

performance.mark('fib-start');
const result = fibonacci(35);
performance.mark('fib-end');
performance.measure('fibonacci', 'fib-start', 'fib-end');

console.log(`fib(35) = ${result}`);

// Get measurements
const measures = performance.getEntriesByType('measure');
for (const entry of measures) {
  console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
}

// PerformanceObserver (async observation)
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`[Observer] ${entry.name}: ${entry.duration.toFixed(2)}ms`);
  }
});
observer.observe({ entryTypes: ['measure', 'function'] });

// Wrap function for auto-measurement
function measured<T extends (...args: any[]) => any>(
  name: string,
  fn: T
): T {
  return ((...args: any[]) => {
    const t = timer(name);
    const result = fn(...args);
    if (result instanceof Promise) {
      return result.finally(() => t.stop());
    }
    t.stop();
    return result;
  }) as T;
}

// Benchmark utility
async function benchmark(
  name: string,
  fn: () => void | Promise<void>,
  iterations: number = 1000
): Promise<{ avg: number; min: number; max: number; p95: number }> {
  const times: number[] = [];

  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    await fn();
    times.push(performance.now() - start);
  }

  times.sort((a, b) => a - b);
  const avg = times.reduce((a, b) => a + b) / times.length;
  const p95 = times[Math.floor(times.length * 0.95)];

  const stats = {
    avg: Number(avg.toFixed(3)),
    min: Number(times[0].toFixed(3)),
    max: Number(times[times.length - 1].toFixed(3)),
    p95: Number(p95.toFixed(3)),
  };

  console.log(
    `\n[Benchmark] ${name} (${iterations} iterations):`,
    `avg=${stats.avg}ms, min=${stats.min}ms, max=${stats.max}ms, p95=${stats.p95}ms`
  );

  return stats;
}

// Usage
const measuredFib = measured('fibonacci', fibonacci);
measuredFib(30);

await benchmark('array-sort', () => {
  const arr = Array.from({ length: 1000 }, () => Math.random());
  arr.sort();
}, 500);

performance.mark('app-end');
performance.measure('total', 'app-start', 'app-end');

observer.disconnect();

Use Cases

  • Function execution profiling
  • Performance benchmarking
  • Production metrics collection

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.