Taking a systematic approach to performance improvement
Process · Chapter 10
The idea in brief
Section titled “The idea in brief”- The entire development team should own performance, not a few individuals — shared ownership yields better results.
- Follow a systematic, iterative loop rather than guessing where problems are. Measure, don’t assume.
The iterative loop
Section titled “The iterative loop”- Profile the application → collect precise measurements.
- Analyze the results → find bottlenecks.
- Implement changes → fix the highest-payoff bottleneck.
- Monitor results → confirm the fix, watch for shifted or new bottlenecks; repeat.
1. Profiling the application
Section titled “1. Profiling the application”Profiling = analysis producing measurements of a system’s execution. Don’t guess where the hotspots are — they’re often not where you expect. Capture: time per method, call counts, communication time, I/O volume, CPU/memory use.
Two ways profilers (profiling tools) collect data — an effective strategy often uses both:
- Instrumentation — code is injected into the system to collect data (e.g. at method entry/exit for timing and counts). Can be added manually or automatically (some profilers modify source, some work at runtime). Gives great detail, but the instrumentation code perturbs measurements; profilers subtract their own overhead, yet adding code can change CPU optimizations, so very short methods can yield inaccurate results.
- Statistical (sampling) profilers — let the app run without runtime modification, collecting data during OS interrupts (process-switch points). Less intrusive, near-normal speed; downside is the data is an approximation, not as numerically accurate as instrumentation.
2. Analyzing the results — find the bottlenecks
Section titled “2. Analyzing the results — find the bottlenecks”- Bottlenecks are parts of the system that limit performance — they can’t keep pace with the workload and slow everything down.
- Optimize the bottlenecks, not the non-bottlenecks — only touch non-bottlenecks once all bottlenecks are handled and time remains.
- Common bottlenecks and typical remedies:
- Network slow → send less data (compression, caching).
- Database slow → work with the DBA: add indexes, optimize queries, use stored procedures, possibly denormalize. See Database performance.
- CPU bound → faster/more processors, cache computed data, improve algorithms.
- Scaling options a bottleneck may force:
- Vertical scaling (up): add resources to existing servers (memory, processors, faster CPUs, more disk).
- Horizontal scaling (out): add servers to the pool to handle more traffic.
3. Implementing changes
Section titled “3. Implementing changes”- Only change things after profiling + analysis prove it’s worth it.
- Implement one set of changes at a time so results don’t blur and new regressions stay visible.
- Prioritize the most important bottleneck with the biggest expected payoff first.
4. Monitoring results
Section titled “4. Monitoring results”- After a change, a bottleneck is either unresolved, fixed, or transferred elsewhere — eliminating one can reveal another. If unresolved, consider undoing the change.
- Keep monitoring even when performance is satisfactory: new features and bug fixes, and changes in user count/traffic, can introduce fresh bottlenecks over time. Be ready for more iterations.
Related concepts
Section titled “Related concepts”- Defining performance terminology
- Server-side caching
- Microservice architecture — scaling out at the service level.
Citations
Section titled “Citations”- Software Architect’s Handbook (Packt, 2018), Ch.10 “Taking a systematic approach to performance improvement”, pp. 748-754.