我有一些标记为constexpr
的非平凡的C ++ 17函数。他们正在进行与图形相关的计算(深度优先遍历)和通用算法(例如,查找,排序,唯一......)。
如果我尝试通过将结果放在constexpr
全局变量中来强制在编译时进行评估,那么可能会发生以下三种情况:
如果我删除constexpr
限定符并要求运行时计算,编译和执行速度非常快(小于5秒)
我使用g ++ 8.2和-O3 -std = c ++ 17。
为什么需要这么长时间? g ++是否适用于constexpr
的编译时优化问题?在编译期间,我应该从constexpr
函数中获得什么样的性能?根据我的理解,编译器将自己变成constexpr
计算的解释器。但毫无疑问,考虑到数据量非常小,在Python中评估相同的程序会非常快。
编辑:提到这些问题here(GCC开发人员的博客)
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)编译时间意味着您以某种方式实例化三重循环的等价物。