|$ curl https://forge-ai.dev/api/markdown?path=docs/performance/profiling
$cat docs/performance-profiling.md
updated Recently·30 min read·published

Performance Profiling

PerformanceIntermediate🎯Free Tools
Introduction

Profiling identifies where your application spends time and memory. Without profiling, optimization is guesswork. With profiling, you can see exactly which functions are slow, which allocations cause GC pressure, and which code paths block the main thread.

Chrome DevTools Performance Panel
performance-api.ts
TypeScript
1// Performance API — programmatic profiling
2// Record a performance timeline
3performance.mark("start-heavy-work");
4heavyComputation();
5performance.mark("end-heavy-work");
6performance.measure("heavy-work", "start-heavy-work", "end-heavy-work");
7
8// Read the measurements
9const entries = performance.getEntriesByName("heavy-work");
10console.log(`Duration: ${entries[0].duration}ms`);
11
12// Long Task API — detect tasks blocking the main thread
13const observer = new PerformanceObserver((list) => {
14 for (const entry of list.getEntries()) {
15 if (entry.duration > 50) { // Tasks > 50ms are "long"
16 console.warn("Long task:", entry.duration, "ms", entry.attribution);
17 sendToAnalytics({
18 type: "long_task",
19 duration: entry.duration,
20 startTime: entry.startTime,
21 });
22 }
23 }
24});
25observer.observe({ entryTypes: ["longtask"] });
26
27// Web Vitals through Performance Observer
28const lcpObserver = new PerformanceObserver((list) => {
29 const entries = list.getEntries();
30 const lastEntry = entries[entries.length - 1];
31 console.log("LCP:", lastEntry.startTime, "element:", lastEntry.element);
32});
33lcpObserver.observe({ type: "largest-contentful-paint", buffered: true });
devtools-workflow.sh
Bash
1# Chrome DevTools workflow:
2# 1. Open DevTools → Performance tab
3# 2. Click Record → interact with your app → Stop
4# 3. Analyze the recording:
5
6# Key areas to look for:
7# - Long tasks (red triangles in the timeline)
8# - JavaScript execution (yellow bars)
9# - Layout (purple bars)
10# - Paint (green bars)
11# - Recalculate Style (red blocks)
12
13# Flame chart navigation:
14# - Click a bar to see details in the bottom panel
15# - WASD keys to zoom and pan
16# - Search for function names in the search bar
17# - "Summary" tab shows time by category
18# - "Bottom-Up" tab shows most expensive functions

info

Use Chrome DevTools Performance Monitor(Ctrl+Shift+P → "Show Performance Monitor") for real-time FPS, memory, and CPU usage while interacting with your app.
Node.js Profiling
node-profiling.sh
Bash
1# Built-in V8 profiler
2node --prof app.js
3# Generates isolate-*.log
4
5# Process the log
6node --prof-process isolate-*.log > processed.txt
7
8# Flame graph with clinic.js
9npm install -g clinic
10clinic doctor -- node app.js
11# Opens interactive flame chart in browser
12
13# Clinic flame graph
14clinic flame -- node app.js
15
16# CPU profile with Chrome DevTools
17node --inspect app.js
18# Open chrome://inspect in Chrome
19# Go to Profiler tab → Start recording
20
21# Memory profiling
22node --inspect --expose-gc app.js
23# In Chrome DevTools → Memory tab
24# Take heap snapshots to find memory leaks
React Profiling
react-profiling.tsx
TypeScript
1// React DevTools Profiler
2// 1. Install React Developer Tools browser extension
3// 2. Open DevTools → Profiler tab
4// 3. Click Record → interact → Stop
5
6// Programmatic profiling
7import { Profiler } from "react";
8
9function onRenderCallback(
10 id: string,
11 phase: "mount" | "update" | "nested-update",
12 actualDuration: number,
13 baseDuration: number,
14 startTime: number,
15 commitTime: number,
16) {
17 if (actualDuration > 16) { // Flag slow renders (>1 frame)
18 console.warn(`Slow render: ${id} took ${actualDuration}ms`);
19 }
20}
21
22function App() {
23 return (
24 <Profiler id="App" onRender={onRenderCallback}>
25 <Dashboard />
26 </Profiler>
27 );
28}
29
30// React DevTools advanced features:
31// - Flamegraph chart: see component render times
32// - Ranked chart: sort by render duration
33// - Why did this render?: shows what caused re-render
34// - Components → Profiler → "Record why each component rendered"

best practice

Use React.memo() and useMemo() only after profiling shows a component is re-rendering unnecessarily. Premature memoization adds complexity without measurable benefit.
Memory Profiling
memory-profiling.ts
TypeScript
1// Detect memory leaks with Performance API
2if (typeof performance.memory !== "undefined") {
3 setInterval(() => {
4 const { usedJSHeapSize, totalJSHeapSize } = performance.memory;
5 console.log(`Memory: ${(usedJSHeapSize / 1e6).toFixed(1)}MB / ${(totalJSHeapSize / 1e6).toFixed(1)}MB`);
6 }, 5000);
7}
8
9// Chrome DevTools Memory tab workflow:
10// 1. Take a heap snapshot
11// 2. Perform actions (navigate, interact)
12// 3. Take another heap snapshot
13// 4. Compare snapshots — objects that grew = potential leak
14
15// Common memory leak patterns:
16// - Forgotten event listeners
17// - Detached DOM nodes in closures
18// - Growing arrays/maps without cleanup
19// - Uncleared timers/intervals
20// - WebSocket connections not closed
21
22// Fix: cleanup in useEffect
23useEffect(() => {
24 const handler = () => {};
25 window.addEventListener("resize", handler);
26 return () => window.removeEventListener("resize", handler);
27}, []);
$Blueprint — Engineering Documentation·Section ID: PERF-PRF-01·Revision: 1.0