c++ - 了解 C++ constexpr 性能

标签 c++ c++17 constexpr raytracing

我最近使用 constexpr 函数和 C++17 编写了一个编译时光线跟踪器。完整的源代码可以在 here 中看到。此问题的相关代码如下所示:

constexpr auto image = []() {
        StaticImage<image_width, image_height> image;

        Camera camera{Pointf{0.0f, 0.0f, 500.0f},
                      Vectorf{0.0f},
                      Vectorf{0.0f, 1.0f, 0.0f},
                      500.0f};

        std::array<Shapes, 1> shapes_list{Sphere{Pointf{0.0f}, 150.0f}};
        std::array<Materials, 1> materials_list{DefaultMaterial{}};
        ShapeContainer<decltype(shapes_list)> shapes{std::move(shapes_list)};
        MaterialContainer<decltype(materials_list)> materials{
            std::move(materials_list)};

        SphereScene scene;
        scene.set_camera(camera);

        Renderer::render(scene, image, shapes, materials);
        return image;
    }();
此处显示的每个类( StaticImageCameraShapesMaterialsShapeContainerMaterialContainerSphereScene )完全由 constexpr 函数组成。 Renderer::render 也是 constexpr,负责循环图像中的每个像素,将光线射入场景,并设置相应的颜色。
使用当前的设置和 512x512 的图像,在 Release模式下使用 MSVC 16.9.2,编译器需要大约 35 分钟来完成生成图像。在此过程中,其内存使用量上升到最终使用近 64GB RAM 的程度。
所以,我的问题是:为什么编译时间和内存使用率这么高?
我的理论是编译时间的部分原因是调用堆栈的复杂性(即大量模板、CRTP 和深度),所以我尝试通过删除几个模板来稍微简化调用堆栈(Vector 类是例如不再模板化)并设法将编译时间减少到 32 分钟,并将内存使用量减少到 61GB。更好,但仍然很高。问题是我不太明白为什么它这么慢。我确实理解评估所有 constexpr 函数是一个非常复杂的过程(因为编译器必须检查 UB、类型推导等),但我没想到它会这么慢。我也对高内存使用率感到困惑。图像数组本身使用的内存不超过 4MB ( 512 * 512 * 3 * sizeof(float) ) 那么额外的内存来自哪里?

最佳答案

编译时执行将比运行时执行效率低得多。编译器必须做更多的工作来执行相同的代码。编译时执行的重点是进行在运行时无法进行的计算。有时,编译时缓存更简单的计算。
编写一个仅在编译时存在的完整的、非平凡的应用程序并不是一件很快就能完成的事情。
至于细节,成本增加的主要原因是编译时执行必须检测所有未定义的行为。这意味着许多可能只是偏移指针的事情必须更加复杂。堆栈变量不能只是偏移堆栈指针;他们必须明确跟踪对象的生命周期。等等。
编译时执行基本上是解释型 C++。而且没有太多理由让它成为一个特别快的解释器。大多数编译时操作都处理基于类型和简单值的计算,而不是复杂的数据结构。所以这就是编译器的主要优化目标。
我记得最近为了改进 Clang 的 constexpr 发出了一些噪音。通过更好的解释来执行。但我不知道它有多少。

关于c++ - 了解 C++ constexpr 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66877395/

相关文章:

c++ - 为什么这个变量在 C++14 中的 g++ 中没有被推断为 initializer_list?

c++ - 如何创建类对象的 vector

c++:使用类类型作为参数

c++ - 在编译时读取文件(constexpr 或其他)

c++ - 可以创建任意类型的 constexpr 链表吗?

c++ - 如何初始化 constexpr 引用

c++ - clang 上的静态 constexpr undefined reference 错误

c++ - 为模板类重载运算符<<

c++ - win32 - .dll 中的对话框

c++ - 类模板偏特化 : compiler error