gpt4 book ai didi

c++ - 识别慢编译函数

转载 作者:可可西里 更新时间:2023-11-01 15:04:10 31 4
gpt4 key购买 nike

我有一些需要大量编译的 cpp 文件。它们包含一些基本的类/代码和一些模板,但没有任何理由证明编译时间在几十秒的量级上是合理的。

我确实使用了几个外部库(boost/opencv)

这就是 gcc 关于编译时间的说法。如何找到导致可怕编译时间的库/包含/函数调用?

Execution times (seconds)
phase setup : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 1445 kB ( 0%) ggc
phase parsing : 6.69 (46%) usr 1.61 (60%) sys 12.14 (47%) wall 488430 kB (66%) ggc
phase lang. deferred : 1.59 (11%) usr 0.36 (13%) sys 3.83 (15%) wall 92964 kB (13%) ggc
phase opt and generate : 6.25 (43%) usr 0.72 (27%) sys 10.09 (39%) wall 152799 kB (21%) ggc
|name lookup : 1.05 ( 7%) usr 0.28 (10%) sys 2.01 ( 8%) wall 52063 kB ( 7%) ggc
|overload resolution : 0.83 ( 6%) usr 0.18 ( 7%) sys 1.48 ( 6%) wall 42377 kB ( 6%) ggc
...

Profiling the C++ compilation process处理识别慢速文件,但我需要更细粒度的信息来找到罪魁祸首

(其他文件/项目以毫秒/秒为单位编译,所以这不是计算机资源的问题。我使用 gcc 4.9.1)

最佳答案

基本上有两件事会导致编译时间过长:包含太多和模板太多。

当您包含太多头文件并且这些头文件包含太多自己的头文件时,这仅意味着编译器有很多工作要做来加载所有这些文件,并且会在处理上花费过多的时间传递它必须对所有代码执行的操作,无论其是否实际使用,例如预处理、词法分析、AST 构建等。当代码分布在大量小标题上时,这可能尤其成问题,因为性能非常受 I/O 限制(大量时间浪费在从硬盘获取和读取文件上)。不幸的是,Boost 库倾向于以这种方式结构化。

以下是解决此问题的几种方法或工具:

  • 您可以使用“include-what-you-use”工具。这是一个基于 Clang 的分析工具,它基本上查看您在代码中实际使用的内容,以及这些内容来自哪些 header ,然后报告您可以通过删除某些不必要的包含而使用前向声明进行的任何潜在优化,或者用更细粒度的标题替换更广泛的“多合一”标题。
  • 大多数编译器都有转储预处理源的选项(在 GCC/Clang 上,它是 -E-E -P 选项,或者直接使用 GCC 的 C 预处理程序 cpp)。您可以取出源文件并注释掉不同的包含语句或包含语句组,然后转储预处理的源代码以查看这些不同 header 引入的代码总量(也可以使用行计数命令,例如 $ g++ -E -P my_source.cpp | wc -l) .这可以帮助您在要处理的大量代码行中确定哪些 header 是最严重的违规者。然后,您可以看到您可以采取哪些措施来避免它们或以某种方式缓解问题。
  • 您还可以使用预编译的头文件。这是大多数编译器支持的功能,您可以使用它指定要预编译的某些头文件(尤其是经常包含的“一体式”头文件),以避免为包含它们的每个源文件重新解析它们。
  • 如果您的操作系统支持它,您可以使用 ram-disk用于您的代码和外部库的 header 。这实质上占用了您的 RAM 内存的一部分,使其看起来像一个普通的硬盘/文件系统。这可以通过减少 I/O 延迟来显着减少编译时间,因为所有头文件和源文件都是从 RAM 内存而不是实际硬盘读取的。

  • 第二个问题是模板实例化的问题。在 GCC 的时间报告中,模板实例化阶段的某处应该报告时间值。如果这个数字很高,一旦代码中涉及到大量模板元编程,那么你就需要解决这个问题。一些模板密集型代码编译起来非常缓慢的原因有很多,包括深度递归的实例化模式、过于花哨的 Sfinae 技巧、滥用类型特征和概念检查以及过时的过度设计的通用代码。但是也有一些简单的技巧可以解决很多问题,比如使用未命名的命名空间(以避免浪费时间为实例化生成符号,这些符号实际上不需要在翻译单元之外可见)和专门的类型特征或概念检查模板(基本上“短路”进入它们的大部分花哨的元编程)。模板实例化的另一个潜在解决方案是使用“ extern templates”(来自 C++11)来控制应实例化特定模板实例化的位置(例如,在单独的 cpp 文件中)并避免在使用它的任何地方重新实例化它。

    以下是帮助您识别瓶颈的几种方法或工具:
  • 您可以使用“Templight ”分析工具(及其辅助“Templight-tools ”来处理痕迹)。这又是一个基于 Clang 的工具,可用作 Clang 编译器的直接替代品(该工具实际上是一个经过检测的成熟编译器),它将生成编译期间发生的所有模板实例的完整配置文件,包括在每个上花费的时间(以及可选的内存消耗估计,尽管这会影响计时值)。跟踪可以稍后转换为 Callgrind 格式并在 KCacheGrind 中可视化,只需阅读 templight-tools page 上的说明即可。 .这基本上可以像典型的运行时分析器一样使用,但用于在编译大量模板代码时分析时间和内存消耗。
  • 寻找最严重的违规者的一种更基本的方法是创建测试源文件,这些文件实例化您怀疑导致编译时间过长的特定模板。然后,您编译这些文件,计时,并尝试以您的方式(可能以“二进制搜索”方式)处理最严重的违规者。

  • 但即使有这些技巧,识别模板实例化瓶颈也比实际解决它们更容易。所以,祝你好运。

    关于c++ - 识别慢编译函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28919285/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com