Catching the Crime After the Fact
Traditional profiling is ad-hoc. You run it manually when you suspect a problem. The workflow looks like: alert fires → engineer wakes up → engineer sets up profiler → engineer tries to reproduce the issue. The problem? Performance anomalies are often transient. A CPU spike that lasted 90 seconds at 3:00 AM is long gone by the time you attach a profiler at 9:00 AM.
Continuous profiling solves this by running 24 hours a day, 7 days a week. It constantly records the state of your application — for example, taking a snapshot of the CPU call stack 100 times per second across every process on the machine. Each snapshot is a sample: "at this exact millisecond, this process was executing this function, which was called by this function, which was called by this function."
This gives you the ability to "rewind the tape":
- "Why did the server OOM-kill at 3:00 AM?" → Rewind the memory profile to 2:58 AM and see which function was allocating.
- "Why did p99 latency spike on Tuesday?" → Rewind the CPU profile to that window and see which code path was hot.
- "Did the new deployment make things faster or slower?" → Compare the profile from before and after the deploy.
The Storage Challenge
Continuous profiling generates a lot of data. A single machine sampled 100 times per second, with stacks 30 frames deep, produces millions of data points per minute. Modern profiling backends (Parca, Pyroscope/Phlare) solve this with aggressive compression using a data structure called a pprof format combined with columnar storage. Stack traces are deduplicated — if 10,000 samples all share the same bottom 20 frames, those frames are stored once, not 10,000 times.