constexpr计算的编译时性能

问题描述 投票:0回答:1

我有一些标记为constexpr的非平凡的C ++ 17函数。他们正在进行与图形相关的计算(深度优先遍历)和通用算法(例如,查找,排序,唯一......)。

如果我尝试通过将结果放在constexpr全局变量中来强制在编译时进行评估,那么可能会发生以下三种情况:

  1. 对于小尺寸计算(给出一个想法,让我们说大约100个节点的图形,节点或多或少整数)编译很好(需要~2s)
  2. 有大约500个节点,编译需要大约1分钟,需要30GB的内存(!)。
  3. 对于大约1000个节点,编译需要太多内存才能让它完成。

如果我删除constexpr限定符并要求运行时计算,编译和执行速度非常快(小于5秒)

我使用g ++ 8.2和-O3 -std = c ++ 17。

为什么需要这么长时间? g ++是否适用于constexpr的编译时优化问题?在编译期间,我应该从constexpr函数中获得什么样的性能?根据我的理解,编译器将自己变成constexpr计算的解释器。但毫无疑问,考虑到数据量非常小,在Python中评估相同的程序会非常快。

编辑:提到这些问题here(GCC开发人员的博客)

c++ g++ c++14 constexpr compilation-time
1个回答
2
投票

g ++ memoizes编译时结构。此外,编译时结构可以沿着你想要的分支创建和检查,而不是你不需要的分支,除非你小心。

指数爆炸很有可能,可能就是你所看到的。

有一些策略可以减少编译时间的复杂性。避免深度递归。注意累积的符号长度。确保只需要检查您要采取的分支。

我的意思是,检查一个非常简单的:

std::conditional_t< (A<B), make_type_A<Ts...>, make_type_B<Ts...> >

此代码的编写者可能只想生成一种类型,但此代码要求创建这两种类型。

这不太可能是您的问题,但运行constexpr代码时可能会出现类似的问题。

对于每个呼叫,计算出所需状态的大小。添加所需的总状态。投入10倍的开销。

您还可以通过提供超过2个样本的样本来分析问题的O符号。检查100,200,300,400,500尺寸图。尝试线性图,平凡图,完整图,具有恒定或百分比连通性的随机图。

编译时增长的O符号可能有助于缩小问题所在。如果它是线性的,多项式的或指数的,你将会看到不同类型的问题。

具有尖锐拐点的线性意味着您遇到了资源瓶颈。也许记忆。开始绘制其他资源使用情况,看看是否能找到瓶颈。

如果你没有记录图形并放大“悬崖”,指数看起来很像悬崖线性。可能存在一个狭窄部分,其中指数部分留下常数因子。

多项式变得有趣。多项式的顺序(对数图可以帮助找到)可以告诉你什么样的操作会让你失望。就像知道你的传统算法是O(n ^ 3)意味着你正在寻找一个三重循环。 O(n ^ 3)编译时间意味着您以某种方式实例化三重循环的等价物。

© www.soinside.com 2019 - 2024. All rights reserved.