【问题标题】:C++ Classes for High Performance Computing用于高性能计算的 C++ 类
【发布时间】:2020-09-01 17:01:03
【问题描述】:

根据this Quora forum

最简单的经验法则之一是记住硬件喜欢数组,并且针对数组迭代进行了高度优化。许多问题的简单优化就是停止使用花哨的数据结构,而只使用普通数组(或 C++ 中的 std::vectors)。这可能需要一些时间来适应。

C++ 类是那些“奇特的数据结构”之一,即一种可以被数组替换以在 C++ 程序中实现更高性能的数据类型吗?

【问题讨论】:

  • “C++ 类是那些“花哨的数据结构”之一吗? - std::vectorclass,它不是“花哨的”,而是明确提到要使用的东西,所以不是。你不能这样概括。 class(或struct - 相同的东西)可以是花哨的/复杂的或完全微不足道的。这一切都取决于里面有什么 / 它是如何实现的。只是作为class 本身没有任何意义。
  • 用更多信息编辑了我的答案。

标签: c++ hpc


【解决方案1】:

如果你的班级是这样的:

struct Person {
  double age;
  double income;
  size_t location;
};

那么你可能受益于重新安排

std::vector<double> ages;
std::vector<double> incomes;
std::vector<size_t> locations;

但这取决于您的访问模式。如果您经常一次访问一个人的多个元素,那么将这些元素阻止在一起是有意义的。

如果你的班级是这样的:

struct Population {
  std::vector<double> many_ages;
  std::vector<double> many_incomes;
  std::vector<size_t> many_locations;
};

那么您正在使用您的资源推荐的表单。单独使用这些数组中的任何一个都比使用第一个类更快,但同时使用所有三个数组中的元素可能会更慢使用第二个类。

最终,您的代码结构应尽可能简洁直观。速度的最大来源将是对算法的深刻理解和适当使用,而不是内存布局。我建议您忽略这一点,除非您已经具备强大的 HPC 技能并且需要从您的机器中获得最大性能。在几乎所有其他情况下,您的开发时间和理智远比节省几个时钟周期更有价值。

更广泛

  1. 与此相关的一篇有趣的论文是SLIDE: In Defense of Smart Algorithms over Hardware Acceleration for Large-Scale Deep Learning Systems。在将 ML 算法映射到 GPU 方面已经做了大量工作,对于 ML 应用程序来说,正确的内存布局确实会产生真正的影响,因为在训练上花费了大量时间,而且 GPU 专门针对连续阵列处理进行了优化。但是,该论文的作者认为,即使您对算法有很好的理解,也可以通过优化的内存布局击败专门的硬件,他们通过让 CPU 的训练速度比 GPU 快 3.5 倍来证明这一点。

  2. 更广泛地说,您的问题涉及cache misses 的概念。由于缓存未命中比 L1 引用 (link) 贵 200 倍,如果您的数据布局针对您的计算进行了优化,那么您可以真正节省时间。 然而,正如上面所暗示的,简单地重新排列数据会神奇地使一切变得更快,这种情况很少见。考虑矩阵乘法。这是一个完美的例子,因为数据按照您的资源要求排列在单个数组中。然而,对于一个简单的三循环 matmult GEMM 实现,仍然有 6 种方式来安排你的循环。其中一些方法比其他方法更有效,但它们都没有给你提供接近最佳性能的任何地方。通读this step-by-step explanation of matmult,以更好地了解获得良好性能所需的所有算法优化。

上面应该说明的是,即使在我们只有几个阵列完全按照您的资源建议布局的情况下,布局本身并不能为我们提供速度。好的算法可以。数据布局考虑(如果有的话)来自我们选择的算法和更高级别的硬件约束。

如果对于简单的数组和矩阵乘法等运算是这样,那么通过扩展,您也应该期望它对于“花式数据结构”也是如此。

【讨论】:

    【解决方案2】:

    C++ 类是那些“奇特的数据结构”之一吗?

    C++ 类是可用于创建数据类型的构造。可用于创建列表、队列等数据结构。

    即一种数据类型

    类是一种数据类型

    可以用数组替换

    类和数组不可互换。数组是数据结构。您正在将苹果与橙子进行比较。

    在 C++ 程序中实现更高的性能?

    这取决于你如何实现你的类

    【讨论】:

      【解决方案3】:

      C++ 类是那些“奇特的数据结构”之一吗?

      我认为他们特别指的是std::mapstd::dequestd::list 等容器,这些容器在许多不同的堆分配中保存数据,因此迭代容器的内容需要 CPU 来“四处跳” " 在某种程度上是在 RAM 地址空间中,而不是仅仅顺序读取 RAM。正是这种跳跃通常会限制性能,因为当未来的 RAM 访问位置不容易预测时,CPU 的板载内存缓存在避免由于 RAM 延迟而导致的执行停止方面不太有效。

      C++ 类本身可能会也可能不会鼓励非顺序 RAM 访问;它是否完全取决于类的实现方式(特别是它是否通过多个堆分配来保存其数据)。 std::vector 类(在论坛文本中提到)是 C++ 类的一个示例,它在您遍历其内容时不需要任何非顺序内存访问。

      【讨论】:

        【解决方案4】:

        C++ 类是那些“奇特的数据结构”之一,即一种可以被数组替换以在 C++ 程序中实现更高性能的数据类型吗?

        计算机时间和开发时间都很宝贵。

        除非您确定它占用了大部分 CPU 时间,否则不要优化代码。

        所以首先使用profiler(例如Gprof)并阅读您的C 或C++ 编译器的文档(例如GCC)。编译器能够进行花哨的优化。

        如果您真的关心 HPC,请学习 GPGPU 编程,例如OpenCLOpenACC

        如果您碰巧使用 Linux(HPC 世界中的一种常见操作系统),请阅读 Advanced Linux Programming,然后是 syscalls(2),然后是 time(7)

        【讨论】:

          猜你喜欢
          • 2012-01-12
          • 2015-12-03
          • 1970-01-01
          • 1970-01-01
          • 2011-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多