分析模板元程序编译时间

时间:2013-04-04 17:54:34

标签: c++ profiling instantiation template-meta-programming

我正在开发一个带有大量编译时计算的C ++项目。漫长的编译时间正在减慢我们的速度。我怎样才能找到模板元程序中最慢的部分,以便我可以优化它们? (当我们有慢的运行时计算时,我有很多分析器可供选择,例如valgrind的callgrind工具。所以我尝试构建一个调试GCC并分析它编译我们的代码,但我没有从中学到太多东西。)

我使用GCC和Clang,但欢迎任何建议。

我在Boost的网站上找到profile_templates,但它似乎记录很少,需要jam / bjam构建系统。如果您展示如何在非阻塞项目 1 上使用它,我将向您推荐。 https://svn.boost.org/svn/boost/sandbox/tools/profile_templates/似乎可以计算实例数,而计算时间则是理想的。

1 我们的项目使用CMake并且足够小,只需将模板分析用于模板分析就可以接受。

4 个答案:

答案 0 :(得分:15)

我知道这是一个老问题,但我想给出一个更新的答案。

有一组以clang为基础的项目针对这一特定问题。第一个组件是clang编译器上的一个工具,它生成编译期间发生的所有模板实例化的完整跟踪,包括时序值和可选的内存使用计数。该工具称为Templight,可在此处访问(目前需要针对修补的clang源树进行编译):

https://github.com/mikael-s-persson/templight

第二个组件是一个转换工具,允许您将templight轨迹转换为其他格式,例如易于解析的基于文本的格式(yaml,xml,文本等),以及可以更容易可视化的格式,例如graphviz / graphML,更重要的是一个callgrind输出,可以加载到KCacheGrind中,以可视化和检查模板实例化的元调用图及其编译时成本,例如一个模板实例化配置文件的截图创建boost::container::vector并使用std::sort对其进行排序的代码:

enter image description here

在这里查看:

https://github.com/mikael-s-persson/templight-tools

最后,还有另一个相关项目,它创建了一个交互式shell和调试器,以便能够以交互方式在模板实例化图形中上下移动:

https://github.com/sabel83/metashell

答案 1 :(得分:8)

自2008年以来,我一直在使用模板元编程的库。真正需要更好的工具或方法来理解消耗最多编译时间的内容。

我所知道的唯一技术是分而治之的方法,要么将代码分成不同的文件,注释模板定义的主体,要么将模板实例包装在#define宏中,并暂时重新定义这些宏以便什么都不做。然后,您可以使用和不使用各种实例来重新编译项目并缩小范围。

顺便说一下,只需将相同的代码分成更多更小的文件,就可以使编译速度更快。我不只是谈论并行编译的机会 - 即使是连续编译,我发现它仍然更快。我在编译我的库时以及编译Boost Spirit解析器时都在gcc中观察到了这种效果。我的理论是,gcc中的一些符号解析,重载决策,SFINAE或类型推断代码在游戏中类型定义或符号的数量方面具有O(n log n)或甚至O(n ^ 2)的复杂度。在执行单位。

最终你需要做的是仔细检查你的模板并分离真正依赖于类型信息的东西,并尽可能使用类型擦除和虚拟函数代码部分而不需要模板类型。你需要从头文件和cpp文件中获取东西如果那部分代码可以移动。在完美的世界中,编译器应该能够自己解决这个问题 - 您不必手动移动此代码来保护它 - 但这是我们今天使用的编译器的最新技术。

答案 2 :(得分:1)

经典书籍C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond附带20页的附录,介绍了编译时的成本。它有一张伴随CD,代码可以生成该附录中的图形。

另一篇论文是http://aszt.inf.elte.hu/~gsd/s/cikkek/profiling/profile.pdf,也许对您有用。

另一种但更耗费人力的方法是从编译器输出中计算每个类的number of instantiations

答案 3 :(得分:-2)

http://www.cs.uoregon.edu/research/tau/about.php可能是您对模板化实体感兴趣的东西,它显示了每个实例化所花费的时间的分解。其他数据包括调用每个函数的次数,每个函数调用的配置函数数量,以及每次调用的平均包含时间