constexpr计算的编译时性能

时间:2019-03-04 19:38:49

标签: c++ g++ c++14 constexpr compilation-time

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

如果我尝试通过将结果放入constexpr全局变量来强制在编译时求值,则会发生3种情况:

  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开发人员的博客)中提到了此类问题

1 个答案:

答案 0 :(得分:2)

g ++记住编译时间结构。此外,编译时结构可能会沿着要创建和检查的分支(而不是不需要的分支)创建和检查,除非您非常小心。

指数爆炸很可能发生,也许就是您所看到的。

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

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

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

此代码的编写者可能只打算创建一种类型,但是此代码要求创建两种类型。

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

对于每个呼叫,计算所需状态的大小。总计所需的总状态。产生10倍的开销。

您还可以通过完成两个以上的样本来分析问题的O表示。查看100、200、300、400、500尺寸图。尝试使用线性图,平凡图,完整图,具有恒定或百分比连通性的随机图。

编译时间增长的O标记可以帮助您缩小问题所在的范围。如果它是线性,多项式或指数式的,您将要研究各种问题。

线性和急剧的弯曲意味着您遇到了资源瓶颈。也许是记忆。开始绘制其他资源使用情况的图表,看看是否可以找到瓶颈。

如果不记录图形并放大“悬崖”,则指数看上去很像带有悬崖的线性。可能有一个狭窄的部分,其中指数部分留下了常数因子。

多项式变得有趣。多项式的顺序(对数图可以帮助您找到答案)可以告诉您哪种操作使您费力。就像知道您的常规算法是O(n ^ 3)一样,这意味着您正在寻找三重循环。 O(n ^ 3)的编译时间意味着您正在以某种方式实例化等效于三重循环。

相关问题