与旧版本相比,CMake 3.16 在 Makefile 的生成阶段慢了几个数量级
CMake 3.16 orders of magnitude slower in the Generate phase for Makefiles compared to older versions
我正在咨询一家公司如何加速他们的构建,我立即向他们指出预编译头文件和统一构建 - 10 分钟的完整构建很容易下降到 2-3 分钟。幸好 CMake 3.16 最近发布了 it supports both of those,所以我告诉他们升级。
问题如下:一旦他们从 CMake 2.6 切换到 3.16,运行 CMake 所花费的时间从大约 20 秒跃升至 10 多分钟。大部分时间花在生成阶段。如果您给它足够的时间并且使用 unity 构建成功编译代码,它确实会成功完成,但是这个 CMake 时间是不可接受的。
这是他们的设置:
- CMake 2.6,具有全局 flags/defines/includes 的旧式 CMake - 非现代(基于目标)。没什么特别的 - 没有自定义命令或构建规则和复杂的依赖关系。
- 使用的编译器是 GCC 7,它们生成 Makefiles - OS 是 CentOS 7,内核:Linux 3.10.0-862.14.4.el7.x86_64
- 大约 2000 个
.cpp
文件分布在 100 个库和 600 个可执行文件中(其中大部分是带有单个 .cpp
的测试可执行文件)
- 大多数
.cpp
文件是 gathered/globbed 和 aux_source_directory
- 我们知道不明确列出 .cpp
文件是一种反模式,但这不是重点 - 我认为这是无关紧要的,因为这应该发生在配置步骤而不是生成期间,对吗?
这是我们观察到的:
- 我们对不同的 CMake 版本进行了二进制搜索,得出的结论是在 3.15 和 3.16 之间发生了巨大的减速——正是在添加预编译头文件和统一构建支持的时候,但我认为这些功能没有任何意义应对经济放缓 - 我想不出他们产生这种影响的原因 - 一定是其他一些重构或改变......
- 我们禁用了所有测试(这意味着几乎所有 600 个可执行文件都被删除了)- 将 CMake 目标的数量从 700 个减少到 100 个多一点 - 运行 CMake 花费的时间显着减少,但对于所有 700 个目标,仍然比 CMake 2.6 长几倍。
- 我们观察了使用
strace
发生的情况,其中大部分是 lstat
和 access
调用以及一些读取和写入 - 但这是无休止的 - 似乎每个操作有数百次其次以非常可重复的方式。此外,不断尝试寻找 libgflags.so
,但一直失败。不幸的是,我现在没有这样的日志。
- 我们做了一个 callgrind 配置文件,这是 运行ning 几分钟后的样子:https://i.imgur.com/Z9AObso.png (the callgrind output file can be found here) - 似乎大部分时间都花在了
ComputeLinkLibs()
并获取目标的全名和定义等等......有 700 个目标是不是太多了?这是一个指数问题吗?为什么这不是 CMake 3.15 的问题?
我在 Internet 上找不到任何其他人遇到同样问题的报告...知道接下来要尝试什么吗?也许使用 Perf 配置文件?尝试使用 Ninja 作为后端 (report of that being faster)?
很好的分析。这将对 CMake 的开发人员有所帮助。但我怀疑你会在这里找到很多帮助。请开一个issue.
如果你能提供一个最小的例子来展示你的问题,加分。您可能会通过生成大量文件来实现这一目标。
我正在咨询一家公司如何加速他们的构建,我立即向他们指出预编译头文件和统一构建 - 10 分钟的完整构建很容易下降到 2-3 分钟。幸好 CMake 3.16 最近发布了 it supports both of those,所以我告诉他们升级。
问题如下:一旦他们从 CMake 2.6 切换到 3.16,运行 CMake 所花费的时间从大约 20 秒跃升至 10 多分钟。大部分时间花在生成阶段。如果您给它足够的时间并且使用 unity 构建成功编译代码,它确实会成功完成,但是这个 CMake 时间是不可接受的。
这是他们的设置:
- CMake 2.6,具有全局 flags/defines/includes 的旧式 CMake - 非现代(基于目标)。没什么特别的 - 没有自定义命令或构建规则和复杂的依赖关系。
- 使用的编译器是 GCC 7,它们生成 Makefiles - OS 是 CentOS 7,内核:Linux 3.10.0-862.14.4.el7.x86_64
- 大约 2000 个
.cpp
文件分布在 100 个库和 600 个可执行文件中(其中大部分是带有单个.cpp
的测试可执行文件) - 大多数
.cpp
文件是 gathered/globbed 和aux_source_directory
- 我们知道不明确列出.cpp
文件是一种反模式,但这不是重点 - 我认为这是无关紧要的,因为这应该发生在配置步骤而不是生成期间,对吗?
这是我们观察到的:
- 我们对不同的 CMake 版本进行了二进制搜索,得出的结论是在 3.15 和 3.16 之间发生了巨大的减速——正是在添加预编译头文件和统一构建支持的时候,但我认为这些功能没有任何意义应对经济放缓 - 我想不出他们产生这种影响的原因 - 一定是其他一些重构或改变......
- 我们禁用了所有测试(这意味着几乎所有 600 个可执行文件都被删除了)- 将 CMake 目标的数量从 700 个减少到 100 个多一点 - 运行 CMake 花费的时间显着减少,但对于所有 700 个目标,仍然比 CMake 2.6 长几倍。
- 我们观察了使用
strace
发生的情况,其中大部分是lstat
和access
调用以及一些读取和写入 - 但这是无休止的 - 似乎每个操作有数百次其次以非常可重复的方式。此外,不断尝试寻找libgflags.so
,但一直失败。不幸的是,我现在没有这样的日志。 - 我们做了一个 callgrind 配置文件,这是 运行ning 几分钟后的样子:https://i.imgur.com/Z9AObso.png (the callgrind output file can be found here) - 似乎大部分时间都花在了
ComputeLinkLibs()
并获取目标的全名和定义等等......有 700 个目标是不是太多了?这是一个指数问题吗?为什么这不是 CMake 3.15 的问题?
我在 Internet 上找不到任何其他人遇到同样问题的报告...知道接下来要尝试什么吗?也许使用 Perf 配置文件?尝试使用 Ninja 作为后端 (report of that being faster)?
很好的分析。这将对 CMake 的开发人员有所帮助。但我怀疑你会在这里找到很多帮助。请开一个issue.
如果你能提供一个最小的例子来展示你的问题,加分。您可能会通过生成大量文件来实现这一目标。