This guide explains how to use the built-in performance profiling tools to identify and resolve bottlenecks in the application.
The observability module provides comprehensive profiling capabilities:
- CPU profiling (hot function identification)
- Memory profiling and heap snapshots
- Request waterfall timing analysis
- Performance baseline tracking and regression detection
- Memory leak detection
POST /profiling/cpu/start- Start CPU profilingPOST /profiling/cpu/stop- Stop and download CPU profileGET /profiling/cpu/status- Check if CPU profiling is running
POST /profiling/heap/snapshot- Capture heap snapshotGET /profiling/memory/health- Memory health check (leak detection)GET /profiling/profiles- List all saved profile filesGET /profiling/profiles/:filename- Download a specific profile file
GET /observability/baselines- Get performance baselines for all routesGET /observability/regressions- View detected performance regressionsPOST /observability/baselines/reset- Reset baselines after deploymentsGET /observability/active-requests- View currently processing requestsGET /observability/memory/current- Real-time memory usage statistics
-
Start profiling:
curl -X POST http://localhost:3000/profiling/cpu/start
-
Generate load on the application for 30-60 seconds to capture meaningful data
-
Stop profiling and download:
curl -X POST http://localhost:3000/profiling/cpu/stop --output cpu-profile.cpuprofile
-
Analyze in Chrome DevTools:
- Open Chrome and navigate to
chrome://inspect - Click "Open DevTools"
- Go to the "Performance" or "Memory" tab
- Load the
.cpuprofilefile - Look for:
- Functions with high self-time (hot functions)
- Unexpected call frequencies
- Blocking operations
- Open Chrome and navigate to
-
Capture a heap snapshot:
curl -X POST http://localhost:3000/profiling/heap/snapshot
-
Download the file from the profiles directory
-
Analyze in Chrome DevTools:
- Load the
.heapsnapshotfile in Chrome DevTools Memory tab - Use the "Retainers" view to find memory leaks
- Look for:
- Growing object counts over time
- Detached DOM trees (if applicable)
- Unexpectedly large objects
- Objects that aren't being garbage collected
- Load the
The application logs request timing data in JSON format:
{
"type": "request_timing",
"method": "GET",
"path": "/api/portfolio",
"timings": {
"middleware": 5, // Middleware execution time (ms)
"handler": 150, // Route handler execution time (ms)
"database": 120, // Database query time (ms)
"total": 155 // Total request duration (ms)
},
"waterfall": {
"middleware": [0, 5],
"handler": [5, 155],
"database": [20, 140]
}
}Waterfall timings are relative to request start time, showing exactly where time is spent.
The system automatically establishes baselines for route performance:
- Tracks P50, P95, and P99 latencies
- Alerts when a request is 50% slower than baseline P95
- Stores all detected regressions for analysis
- Reset baselines after deployments with
POST /observability/baselines/reset
The memory health check endpoint (GET /profiling/memory/health) monitors:
- Heap usage growth over time
- Memory growth thresholds
- Alerts on potential leaks
All metrics are exposed to Prometheus and can be visualized in Grafana:
- Request duration histograms
- Baseline latency gauges
- Regression counter
- Memory usage metrics
Import the existing Grafana dashboard (in docker/grafana/dashboards/) to get pre-built visualizations.
- Profile in staging first: Avoid running CPU/memory profiling in production unless necessary
- Keep profiling sessions short: CPU profiling adds minimal overhead but should still be limited
- Compare against baselines: Always compare new profiles against established baselines
- Take multiple heap snapshots: Memory leaks are best identified by comparing snapshots over time
- Look at database timings: Most application bottlenecks are database-related
- Check hot functions: CPU profiling often reveals inefficient algorithms or unexpected N+1 queries
- Ensure Node.js version >= 16 (the inspector API is stable in newer versions)
- The application must be run with
--inspectflag in development - In production, profiling is disabled by default (set
ENABLE_PROFILING=trueto enable)
- Check that the
profiles/directory exists and has proper permissions - Verify disk space is available
- Check application logs for errors during profile creation
- Reset baselines after any major deployment
- Adjust the
regressionThresholdinperformance-baseline.service.tsif needed - Ensure sufficient data has been collected to establish accurate baselines