📘 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

  1. Use compiler optimizations for automatic performance improvement
  2. Profile before optimizing to identify real bottlenecks
  3. Optimize cache usage for memory access efficiency
  4. Choose optimal algorithms for better complexity
  5. 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