📘 Learning Objectives
After completing this chapter, you will: - Master C++ performance optimization techniques - Understand compiler optimizations and flags - Learn about profiling and benchmarking - Master cache optimization and memory access patterns - Understand algorithmic optimization strategies
🎯 Key Concepts
1. Compiler Optimizations
- Optimization flags: GCC, Clang, MSVC optimization
- Inlining: Function inlining optimization
- Loop optimization: Loop unrolling and vectorization
- Dead code elimination: Unused code removal
- Constant folding: Compile-time constant evaluation
2. Profiling and Benchmarking
- Profiling tools: gprof, Valgrind, Intel VTune
- Benchmarking: Performance measurement
- Hotspot analysis: Performance bottleneck identification
- Memory profiling: Memory usage analysis
- CPU profiling: CPU usage analysis
3. Cache Optimization
- Cache hierarchy: L1, L2, L3 cache optimization
- Cache line optimization: Cache line alignment
- Memory access patterns: Sequential vs random access
- Data locality: Spatial and temporal locality
- Cache-friendly data structures: Cache-optimized containers
4. Algorithmic Optimization
- Algorithm complexity: Big O notation
- Data structure selection: Choosing optimal structures
- Algorithm selection: Choosing optimal algorithms
- Parallel algorithms: Multi-threaded optimization
- SIMD optimization: Vector instruction optimization
5. Performance Best Practices
- Avoid premature optimization: Optimization guidelines
- Measure before optimizing: Performance measurement
- Profile-guided optimization: PGO techniques
- Optimization trade-offs: Performance vs maintainability
- Continuous optimization: Ongoing performance improvement
🧩 Practice Exercises
Exercise 27.1: Compiler Optimization
Use compiler optimization flags and analyze results.
Exercise 27.2: Profiling
Profile code to identify performance bottlenecks.
Exercise 27.3: Cache Optimization
Optimize memory access patterns for cache efficiency.
Exercise 27.4: Algorithmic Optimization
Optimize algorithms for better performance.
💻 Code Examples
Performance Measurement
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
template<typename Func>
auto measure_time(Func&& func) {
auto start = std::chrono::high_resolution_clock::now();
func();
auto end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(end - start);
}
int main() {
const int size = 1000000;
std::vector<int> data(size);
// Fill with random data
std::iota(data.begin(), data.end(), 0);
std::random_shuffle(data.begin(), data.end());
// Measure sorting performance
auto sort_time = measure_time([&]() {
std::sort(data.begin(), data.end());
});
std::cout << "Sorting time: " << sort_time.count() << " microseconds" << std::endl;
return 0;
}
Cache Optimization
#include <iostream>
#include <vector>
#include <chrono>
// Cache-friendly: sequential access
void sequential_access(std::vector<int>& data) {
int sum = 0;
for (size_t i = 0; i < data.size(); ++i) {
sum += data[i];
}
}
// Cache-unfriendly: random access
void random_access(std::vector<int>& data, std::vector<size_t>& indices) {
int sum = 0;
for (size_t idx : indices) {
sum += data[idx];
}
}
int main() {
const size_t size = 1000000;
std::vector<int> data(size);
std::iota(data.begin(), data.end(), 0);
// Sequential access
auto start = std::chrono::high_resolution_clock::now();
sequential_access(data);
auto end = std::chrono::high_resolution_clock::now();
auto sequential_time = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
// Random access
std::vector<size_t> indices(size);
std::iota(indices.begin(), indices.end(), 0);
std::random_shuffle(indices.begin(), indices.end());
start = std::chrono::high_resolution_clock::now();
random_access(data, indices);
end = std::chrono::high_resolution_clock::now();
auto random_time = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Sequential access time: " << sequential_time.count() << " microseconds" << std::endl;
std::cout << "Random access time: " << random_time.count() << " microseconds" << std::endl;
return 0;
}
🎓 Key Takeaways
- Use compiler optimizations for automatic performance improvement
- Profile before optimizing to identify real bottlenecks
- Optimize cache usage for memory access efficiency
- Choose optimal algorithms for better complexity
- Measure performance to validate optimizations
🔗 Next Steps
After mastering performance optimization, proceed to Chapter 28 to learn about debugging and testing.
📚 Additional Resources
- C++ Reference: Performance
- C++ Core Guidelines: Performance
- Practice with profiling and optimization tools