Front-end Engineering Lab

CPU Profiling

Identify performance bottlenecks with CPU profiling

CPU profiling reveals which functions consume the most processing time. Essential for optimizing JavaScript performance.

Chrome DevTools CPU Profiler

1. DevTools → Performance tab
2. Record profile
3. Interact with app
4. Stop recording
5. Analyze "Bottom-Up" and "Call Tree" tabs

JavaScript Profiling API

// Start profiling
console.profile('myProfile');

// Run expensive code
expensiveFunction();

// Stop profiling
console.profileEnd('myProfile');

// Results appear in DevTools Profiles tab

Finding Hot Functions

// Measure function execution time
export function measurePerformance<T extends (...args: any[]) => any>(
  fn: T,
  label: string
): T {
  return ((...args: Parameters<T>) => {
    const start = performance.now();
    const result = fn(...args);
    const duration = performance.now() - start;
    
    if (duration > 5) {
      console.log(`⚠️ ${label}: ${duration.toFixed(2)}ms`);
    }
    
    return result;
  }) as T;
}

// Usage
const processData = measurePerformance(
  (items: Item[]) => items.map(transform),
  'processData'
);

React DevTools Profiler

import { Profiler, ProfilerOnRenderCallback } from 'react';

const onRenderCallback: ProfilerOnRenderCallback = (
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) => {
  console.log(`${id} (${phase}) took ${actualDuration.toFixed(2)}ms`);
  
  // Log slow renders
  if (actualDuration > 16) {
    logMetric({
      component: id,
      phase,
      duration: actualDuration,
    });
  }
};

export function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <YourComponents />
    </Profiler>
  );
}

Performance Budgets

// Set performance budgets
const BUDGETS = {
  'data-processing': 50, // ms
  'component-render': 16,
  'api-call': 1000,
};

export function checkBudget(operation: string, duration: number) {
  const budget = BUDGETS[operation];
  
  if (budget && duration > budget) {
    console.warn(
      `Performance budget exceeded: ${operation} took ${duration.toFixed(2)}ms (budget: ${budget}ms)`
    );
    
    logMetric({
      type: 'budget_exceeded',
      operation,
      duration,
      budget,
      overage: duration - budget,
    });
  }
}

// Usage
const start = performance.now();
processData();
checkBudget('data-processing', performance.now() - start);

Optimizing Hot Paths

// ❌ Slow: Create new function every render
function Component({ items }: Props) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => handleClick(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
}

// ✅ Fast: Memoized handler
function Component({ items }: Props) {
  const handleClick = useCallback((id: string) => {
    // Handle click
  }, []);
  
  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => handleClick(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
}

Best Practices

  1. Profile in production mode - Dev mode is slower
  2. Use CPU throttling - Test on slow devices
  3. Focus on hot paths - Optimize frequently called code
  4. Measure first - Don't optimize blindly
  5. Set budgets - Define acceptable performance
  6. Memoize expensive computations - useMemo, useCallback
  7. Defer non-critical work - requestIdleCallback
  8. Monitor in production - Track real user performance

CPU profiling reveals bottlenecks—measure before optimizing!

On this page