24

我正在寻找可以帮助我深入了解 C++ 性能的资源(最好是一本书)。这里有一点背景:

我编写具有非常高的吞吐量要求和/或低延迟要求的服务器软件。我们用 C++ 编写;目前还没有真正的争论。我的大多数同事似乎对 C++ 性能有了更好的理解。他们有更好的心智模型,因此他们可以判断某段代码何时会在规模上表现不佳。我缺乏这种理解,所以我正在寻求改善我的心理模型。

我特别感兴趣:

  • 了解缓存效果,以及对象布局导致的缓存局部性如何影响我的代码性能。这是我团队的其他成员似乎提出的第一个问题。
  • 了解内存分配如何影响性能。我应该使用 TCMalloc(或其他 malloc)吗?我应该怎么知道?我应该如何调整各种分配和释放参数?
  • 我怎么知道对象复制的开销何时重要(例如,应该切换到指针)?
  • 只要我知道何时使用它们,我通常也对“优化”感兴趣。

我不太感兴趣的事情:

  • “高性能计算”这个术语似乎表示更多面向数学/模拟的应用程序。
  • 讨论 C++ 相对于其他语言的性能,因为我坚持使用 C++。

作为起点,有人知道这本书Efficient C++是否符合要求?

4

4 回答 4

30

让我把我的建议分成几个部分。

C++ 优化

作为起点,我强烈推荐 Agner Fog 的C++ 优化软件。本手册很好地概述了常见的 C++ 优化主题。

总体了解硬件

要对 C++ 性能有一个良好的心智模型,您还需要了解底层硬件。考虑这个陈述:

a[7] = 5;

在 C++ 语言方面,从性能的角度来看,这行代码很无聊:它只是一次内存写入。但是,在真实硬件上,内存写入的性能可能会相差几个数量级。要了解该级别发生了什么,您需要了解缓存、处理器管道、TLB、分支预测等概念。

作为对处理器缓存的快速介绍,我推荐我的文章处理器缓存效果库。关于缓存和计算机内存的更深入和更长(>100 页)的讨论是每个程序员应该了解的内存

为了全面了解现代计算机硬件,计算机体系结构:定量方法是通常推荐的书。我自己没有读过这本书,而是通过阅读博客和实验来学习的。然而,其他人显然发现这本书非常有用。

了解特定处理器

在您提高优化技能的过程中,您会发现识别不同处理器的细节很有用。作为众多示例之一,不同的 Intel 和 AMD 处理器对使用未对齐的 SSE 指令(例如 _mm_storeu_ps C++ 内在函数)具有非常不同的惩罚。

要了解不同处理器的细节,我推荐Intel、AMD 和 VIA CPU 的微架构:汇编程序员和编译器制造商的优化指南。事实上,我只是继续推荐 Agner Fog 的所有优化手册。此外,硬件供应商为其特定硬件提供文档。

学习使用工具

在优化代码时,拥有良好的 C++ 心智模型和硬件性能非常有用。但是,学习使用正确的工具至少同样有用。可以说,优化的最佳建议是“先测量!”。即使是一个简单的代码块,仅仅通过思考也很难理解它的性能。通过运行代码并以各种方式对其进行测量,您将获得大量信息。

这些是一些常见的有用测量:

  • 计时:只需运行代码并测量时间
  • 采样分析器
  • 仪器分析器
  • 处理器计数器

我不会对特定工具提出建议,因为可以说我超出了您最初问题的范围。而且,工具本身就是一个大话题:工具因不同的硬件平台、软件平台和成本而异(有些是免费的,有些是昂贵的)。

但是,您当然需要知道,要优化 C++ 代码,您需要了解和使用适当的工具。

于 2012-09-10T18:50:38.367 回答
11

Valgrind 应该是你的第一个工具。

Valgrind 有很多工具,但 cachegrind 是查看您的算法是否具有良好数据局部性的好方法。这将识别内存瓶颈。Callgrind 是另一个 valgrind 模块,可帮助您识别处理瓶颈。

参考:

缓存研磨:http : //valgrind.org/docs/manual/cg-manual.html

调用研磨:http : //valgrind.org/docs/manual/cl-manual.html

于 2012-09-10T17:24:38.217 回答
1

以前的回答给出了最重要的想法。

只有一个警告:做一些分析(valgrind),这就是你快速获胜的地方。在那之后,尝试进行缓存优化,查看 SSE ......将需要更多的努力,因为(至少在开始时)几乎没有改进。

此外,C++ 是一门庞大的语言,编译器确实很神奇。模板、内联等允许编译器进行在 C 等其他语言中无法实现的出色优化。因此,在考虑使用低级数据结构时要非常小心。它可能会导致性能损失(以及内存管理中的更多错误和更多麻烦)。

使用 STL 和 BOOST 可能有助于避免一些错误。

于 2012-09-10T19:26:03.017 回答
1

要了解该级别发生了什么,您需要了解缓存、处理器管道、TLB、分支预测等概念。

我想以非常随意的方式进一步讨论这些问题。

  1. 缓存 - 基本上,如果您可以尝试将您的工作集放入缓存中,您的应用程序可以看到巨大的速度提升。
  2. 分支 - 分支需要很长时间,因为它们在内存读取时需要一个块。例如,即使您最终进行了不必要的写入,x=1也可能会更快。if (needWrite) x=1;
  3. 分支预测 - 由于前面的原因,CPU 尝试使用模式匹配算法尝试“猜测”分支的结果。让这个琐碎的猜测可以让你提高速度。
  4. 至于处理器流水线、指令级并行、超标量、寄存器重命名等——我认为,这些大多必须由编译器进行优化。
于 2012-09-10T21:11:52.100 回答