Why Traditional APM Misses the Hot Path
In my twenty-five years at JPMorgan Chase and Deutsche Bank, I have seen teams waste weeks chasing ghosts. We would look at Application Performance Monitoring (APM) dashboards, see a spike in latency, and assume the database was slow. We would then spend hours tuning SQL queries only to find the bottleneck was a CPU-bound loop in the application layer. APM tells you when something is slow. It does not tell you why at the instruction level.
Continuous profiling solves this. Unlike tracing, which samples a small fraction of requests (typically 1% to 10%), continuous profiling samples the CPU and memory of your application every second, 24/7. It captures the entire system state, not just a few representative requests. This allows you to see the aggregate behavior of thousands of concurrent goroutines or threads. In 2026, with the shift toward Agentic AI, where LLM inference and vector database lookups create complex, variable workloads, this granularity is no longer optional. It is the baseline for operational sanity.
When you deploy an AI agent, you are not just dealing with standard REST calls. You are dealing with token generation loops, context window management, and vector similarity searches. These are CPU-intensive and memory-heavy. If you cannot see the exact function causing the spike, you cannot optimize. You are flying blind.
Architecture: Agents vs. Sidecars
There are two ways to deploy Pyroscope in a Kubernetes environment. The first is the sidecar pattern, where a Pyroscope agent runs in the same pod as your application. The second is the node agent, which runs as a DaemonSet and profiles all containers on the node.
For most enterprise environments, I recommend the sidecar approach for application-specific profiling. It provides cleaner isolation and easier labeling. You deploy the agent as a container in your pod, mount the host's `/proc` and `/sys` filesystems, and point it at the application’s profiling endpoint.
Here is a basic deployment snippet for a Go application:
- Image: Use the official
pyroscope/pyroscope-agentimage. - Mounts: Mount
/procand/sysfrom the host to the container. - Environment: Set
ENABLE_PPROFtotruefor Go applications. - Labels: Add labels like
service.name,version, andenvironmentto the agent configuration.
For Java applications, the process is slightly different. You need to enable the Java Flight Recorder (JFR) agent. This adds a small overhead, typically less than 2% CPU usage. You must ensure the JVM is configured with -XX:+UnlockDiagnosticVMOptions if you are using older JDK versions, though modern JDK 17+ environments handle this more seamlessly.
Configuring the Pyroscope Server
The Pyroscope server is where the profile data is stored and visualized. You can run it as a standalone service or use a managed cloud offering. For on-premise Kubernetes clusters, I recommend deploying the server in a dedicated namespace with persistent storage.
Key configuration parameters include:
- Retention: Set
retention-periodto7dfor development and30dfor production. This balances storage costs with historical visibility. - Max Upload Size: Set
max-upload-sizeto100MBto prevent large payloads from crashing the server. - Query Timeout: Set
query-timeoutto30sto avoid long-running queries that block the UI.
One critical step is setting up authentication. In 2026, security is non-negotiable. Use OIDC with your existing identity provider. Do not run Pyroscope without authentication in any environment other than local development. I have seen too many incidents where unauthenticated profiling endpoints were used to exfiltrate code structure and logic.
Interpreting the Flame Graph
Once data is flowing, open the Pyroscope UI. The default view is a flame graph. The width of each bar represents the percentage of CPU time spent in that function. The height represents the call stack depth.
Look for the "widest" bars at the top of the stack. These are your hot paths. If you see a large block of time spent in runtime.gc, you have a memory pressure issue. If you see a large block in crypto/aes, you are spending too much time on encryption. If you see a large block in a custom function like calculateVectorSimilarity, you need to optimize that algorithm.
I recently worked on a case where a team was experiencing 40% higher CPU usage than expected. The APM tools showed no issues. The Pyroscope flame graph revealed that 35% of CPU time was spent in a specific logging function that was serializing JSON objects on every request. The fix was simple: switch to asynchronous logging. The CPU usage dropped by 30% within an hour.
Another powerful feature is the "Diff" view. You can compare two time periods or two versions of your application. This is invaluable for regression testing. Before deploying a new version, you can profile the old version and the new version, then diff them to see exactly which functions increased in execution time.
Integrating with CI/CD
Continuous profiling is not just for production. It should be part of your CI/CD pipeline. You can run profiling tests in your integration test environment and fail the build if CPU usage exceeds a certain threshold.
For example, you can set a threshold of 500ms average CPU time per request. If a new commit causes the average to rise to 600ms, the build fails. This shifts performance left, catching regressions before they reach production.
When deploying AI agents, this is even more critical. LLM inference is expensive. If a new prompt template causes the model to generate more tokens than expected, it will increase CPU and memory usage. Profiling in CI/CD helps you catch these issues early. I have written about this in detail in my post on why agentic AI fails in production. Profiling is one of the key tools you need to prevent that failure.
Additionally, you can use Pyroscope to monitor the performance of your AI agent guardrails. If you are using enterprise guardrails to filter outputs, you need to ensure they are not becoming a bottleneck. Profiling helps you identify if the guardrail logic is adding significant latency.
Common Pitfalls and Troubleshooting
Despite its power, Pyroscope has some common pitfalls. The first is label cardinality. If you use too many unique labels, the server will slow down. Keep your labels to a minimum. Use service.name, version, and environment. Avoid using labels like request.id or user.id, which have high cardinality.
The second pitfall is sampling bias. Continuous profiling samples every second, but it does not capture every instruction. If a function runs for less than 1 second, it may not appear in the profile. This is rare for hot paths, but it can be an issue for intermittent bugs. In those cases, you may need to increase the sampling rate or use a different tool.
The third pitfall is resource contention. If your application is already running at 100% CPU, the profiling agent will add overhead. In this case, you may need to reduce the sampling rate or profile a subset of instances. I recommend starting with a sampling rate of 100Hz (1 sample per 10ms) for most applications. If you are seeing high overhead, reduce it to 10Hz (1 sample per 100ms).
Frequently Asked Questions
Q: How much overhead does Pyroscope add to my application?
A: Typically, less than 2% CPU and 50MB of memory. The overhead is negligible for most applications. However, if you are running at high load, you may see a slight increase in latency. Always monitor your application metrics after deploying Pyroscope.
Q: Can I use Pyroscope with .NET applications?
A: Yes. Pyroscope supports .NET via the dotnet-otel exporter. You need to enable the profiler in your .NET application and configure it to send data to the Pyroscope server. The setup is similar to Java, but you use the .NET-specific agent.
Q: How do I correlate profiling data with Git commits?
A: Use the version label. Set the version label to the Git commit hash or the semantic version number. Then, in the Pyroscope UI, you can filter by version and see the profile for a specific commit. This allows you to trace performance changes back to specific code changes.
Q: Is Pyroscope suitable for profiling AI models?
A: Yes. You can profile the CPU and memory usage of the inference engine. However, for GPU profiling, you need to use a different tool, such as NVIDIA Nsight. Pyroscope does not capture GPU metrics. I have written about AI agent observability in more detail, including how to combine Pyroscope with GPU monitoring tools.