What are common criminals for TMP slowness

I have a project that uses quite a lot of meta-programming of C ++ templates. This reduces compilation time. I understand that I cannot have a cake and have it, but I would like to know some tips and advice on how to reduce compilation time. I have already tried explicit instances, and although this can help in some cases, many times, instances are unique to a particular compilation unit, in which case explicit instance creation does not help anything. And now we are only talking about Klang, which does a very good job. When I try this on g ++, compilation time just explodes. For one file, I gave up, waiting for it to compile after 45 minutes.

  • Are there any common criminals when it comes to metaprogramming patterns, which is often problematic? What methods should be avoided and what should I do instead?
  • Are there any areas where GCC is known to be worse than Clang, and is there a way around this?

I use mostly simple vanilla C ++ 11 technologies, I do not use Boost MPL or similar libraries.

+6
source share
2 answers

Here are some tips for metaprogramming with C ++ 11 onwards:

  • Prefer algorithms based on variational extension . Variadic templates are generally handled by the compiler compared to the chain of O (n) template instances that are typically needed for type lists and are associated with older C ++ 98/03. I really want to see C ++ 1z fold expressions as a way to implement fold family metafiles using the package extension.

  • Avoid inheritance chains . Algorithms based on recursive inheritance usually work poorly, since the compiler must track the metadata of the inheritance tree. Prefer the raw calls to the following ::type instead of inheriting directly from the next β€œcall” as a transcript to get this type member.

  • Assume an extension to the inheritance set for recursive inheritance . That is, if you are implementing a similar game, prefer

     template<typename... Ts> struct tuple : Ts... 

    to

     template<typename Head, typename... Tail> struct tuple : Head, tuple<Tail...> 

    since the compiler must name N subtypes on the latter, plus the inheritance overheads described above.

  • Prefer name-based algorithms . Name lookups are usually faster than a recursive pattern instance. So, consider doing something like decltype(declval<T>().f()) to calculate the type where the result is in the correct f overload.

+2
source

In our projects, we simply used thinking and testing. That is, first we think β€œwhat kind of complex templates are here,” and then we tried to isolate these templates or remove them or refactor to see if the compilation time has changed. Often the compilation time of the templates is accompanied by an increase in memory usage, I even once reported a gcc error ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54056 ).

There was another trick that helped a few times using the -Q command line switch (show the functions that gcc currently compiles). For instance. for the error related above, it was clear that gcc slowed down on these buggy templates.

0
source

Source: https://habr.com/ru/post/985551/


All Articles