The Hidden Performance Price of C++ Virtual Functions - Ivica Bogosavljevic - CppCon 2022

Discover how C++ virtual functions can impact your application's performance and learn how to optimize virtual function calls with type-based processing and other techniques.

Key takeaways
  • The cost of virtual function calls can be significant, especially for short and fast functions.
  • When the compiler inlines a function, it can perform additional compiler optimizations.
  • For small virtual functions, the overhead of a virtual function call is around 20%.
  • For large virtual functions, the overhead is more significant, around 50%.
  • A good way to optimize virtual function performance is to make small functions non-virtual.
  • Another approach is to use type-based processing, which can reduce overhead.
  • The CPU’s cache plays a significant role in performance. When the CPU needs to jump around memory, it can be slow.
  • Neighboring memory addresses are good for performance.
  • The optimal layout is when neighboring pointers point to neighboring objects.
  • Type-based processing can be used with polymorphic containers, such as the std::vector of base classes.
  • The std::vector of objects is faster than a std::vector of pointers.
  • The Liquid library is a good tool for measuring software performance.
  • The perf tool and Intel’s vtune profiler are also useful for measuring performance.
  • C++ virtual functions can have a significant impact on performance, especially in applications that require high performance.
  • Compiler optimization is important for performance.
  • Inlining functions can improve performance, but the compiler may not be able to inline virtual functions.
  • Jump destination guessing is a technique used by CPUs to optimize jumps.
  • The CPU’s prediction of jump destinations can be influenced by its previous experiences.
  • The branch predictor is a component of the CPU that predicts the outcome of jumps.
  • The branch predictor can be influenced by previous experiences.
  • The CPU has a limited amount of memory, and accessing memory can be slow.
  • Code that is executed recently is cached in the CPU’s cache.
  • Accessing objects on the heap can be slow.
  • The std::vector of objects is faster than a std::vector of pointers because objects are stored in contiguous memory.
  • Compiler optimization can improve performance by reducing the overhead of function calls.
  • The std::vector of objects is a good way to store objects of different types.
  • Polymorphic containers can be used with type-based processing.
  • The optimal layout is when neighboring pointers point to neighboring objects.
  • The std::vector of objects is faster than a std::vector of pointers because it stores objects in contiguous memory.
  • The cost of virtual function calls can be significant, especially for short and fast functions.