优化代码 - CPU 与内存 [关闭]

Posted

技术标签:

【中文标题】优化代码 - CPU 与内存 [关闭]【英文标题】:Optimizing Code - CPU vs Memory [closed] 【发布时间】:2014-02-26 07:51:33 【问题描述】:

我正在尝试优化程序核心中的一些算法,但我想知道硬件的哪一部分真正“减慢”了一切。

在编程方面,硬件中最重要的两个部分可能是 CPU 和 RAM(以及 CPU 的高速缓存???)。但在性能方面,它们如何一起发挥作用?

考虑一下这段代码:

std::vector<int> vec;
for(int count = 0; count < 100000; count++)

    vec.push_back(count);

在这种情况下,真正减慢算法速度的部分是内存写入 RAM 的速度(?)。 CPU 的速度几乎不会对这段代码的执行时间产生任何影响,因为不需要计算太多,对吧?

但是现在,考虑一下这段代码:

std::vector<int> vec;
for(int count = 0; count < 100000; count++)

    vec.push_back(count/10/10/10/10);

在这种情况下,在插入列表(在 RAM 上)之前,会执行几个算术运算(在 CPU 上)。在这种情况下是否会对性能产生很大影响? CPU必须先计算结果,然后才能将结果写入RAM,所以它肯定会更慢,对吧?

如果这是正确的,那么(据我所知)真正减慢程序速度的部分是可以写入 RAM 的速度,而不是 CPU 的速度,对吗?因为即使有更复杂的代码块,它也总是采用以下形式:

//calculate something and write it to the RAM
int something = calculateSomething();

总会有算术运算以及内存分配。但是在查看任务管理器时,我很少看到 CPU 100% 工作 - 得出的结论是肯定有另一个部分会减慢整个事情的速度。

直截了当: 在优化算法时我必须考虑的最重要的事情是什么?分配更少的内存并更频繁地重新计算值,这会增加 CPU 工作并减少内存分配 - 还是只计算一次值并将它们写入内存?什么会给我的算法带来更多性能? 当今现代硬件中哪些部分真正会减慢代码的速度?

提前致谢。

【问题讨论】:

1) c2.com/cgi/wiki?PrematureOptimization 2) en.wikipedia.org/wiki/Profiling_%28computer_programming%29 3) 修复热路径。 4) 有一只熊。 对于这样大小的向量,将花费大量时间为向量重新分配空间。如果您想优化,请预先分配空间。 @nonsensickle 熊不会吃我吗?! 通过阅读这篇由 C 库的作者之一编写的关于内存对性能影响的文章,您将学到很多东西:akkadia.org/drepper/cpumemory.pdf 答案是“视情况而定”。在您知道您的算法有效之后,最重要的事情是分析您的代码并确定它在哪里运行缓慢。然后判断是CPU bound、memory access bound、I/O bound等等,瓶颈的原因是什么。每种算法都会有所不同。 【参考方案1】:

在这种情况下,真正减慢算法速度的部分是内存写入 RAM 的速度(?)。

不,真正减慢算法速度的不是硬件,而是 C++ 向量的实现,它严重依赖于动态内存分配。它必须在该循环中一遍又一遍地重新调整向量的大小。此外,它会导致堆碎片。所有这些都将成为主要瓶颈。

如果您使用普通的“C 风格”数组,瓶颈可能是 CPU 或 RAM 访问时间。这取决于代码运行在什么硬件上。数据缓存可能不会有任何帮助,因为您不会在写入数据后立即使用它。

在这种情况下,在插入列表之前会执行几个算术运算(在 CPU 上)

不,编译器已经将您的代码翻译成count/10000。所以有一个CPU除法指令。它不会对 32 位或更大的 CPU 的性能产生很大影响。在 8 位 CPU 上,它会导致严重的性能下降,因为它不太可能以有效的方式对大量数执行除法。

如果这是正确的

从上面可以看出,大部分都不是。

但我在查看任务管理器时很少看到 CPU 100% 工作 - 得出的结论是肯定有另一个部分会减慢整个过程。

在 PC 上,有一个操作系统在后台运行。因此,除了在操作系统之上运行的应用程序之外,几乎总会有一些东西被执行。调度和物理 CPU 内核的数量也将决定 CPU 的使用百分比。当然,每种硬件都会发挥作用,不仅是 RAM,还有 HD 访问时间。

优化算法时我必须考虑的最重要的事情是什么?

最重要的是问自己以下问题:

真的需要优化这段代码吗?是否存在您已进行基准测试的真正瓶颈,或者您是否发现了现实世界中不存在的问题? 您真的知道预处理器和编译器的优化器是如何工作的吗? 您真的知道编译器如何将 C++ 代码转换为机器代码吗? 您是否对给定系统有深入的硬件知识,以至于您比为给定硬件制作编译器端口的人更了解硬件?您是否深入了解 CPU 的硬件优化功能,例如流水线、数据/指令缓存、分​​支预测?

在没有考虑特定硬件的情况下手动优化代码没有任何意义。

当今现代硬件中真正使代码速度减慢的部分是什么?

现代硬件通常速度快得离谱...对于 PC,任何硬盘访问都可能是硬件瓶颈。但实际上会减慢代码速度的大多数事情都是软件。程序中的数据混洗和嵌套循环。应用程序使用的 Bombastic 库和各种运行时垃圾。极其缓慢的桌面操作系统,同时运行着数百个其他程序。以此类推。

【讨论】:

"预处理器已经将你的代码翻译成 count/10000。" => 不是预处理器,而是 compiler :) @JensSchwarzer 嗯,很公平 :) 另外,count/10000 不一定是除法指令,但最终可能是定点倒数的乘法。【参考方案2】:

即使使用今天的硬件,也可以在一定程度上估计一些事情:算术运算的性能在某种程度上是可预测的,您可以将一组运算所需的时间计算为各个运算所需时间的总和。粗略地说,最多是两倍左右。不幸的是,对于大多数其他操作,这是不可能的。从内存中读取一个值可能需要 1 到 200 个时钟周期。条件跳转的数字是相似的,具体取决于分支预测和您跳转到的代码的缓存状态。而且由于这些操作通常会占用大部分性能,因此您很难仅通过查看代码来猜测瓶颈。 使用分析器并为一些意外做好准备。计算平方根可能比从内存中读取结果更快。 O(n^2) 算法可以比 O(n) 算法更快。在某些情况下,如果编译器能够证明结果保持不变,它甚至可能会将其中一种转换为另一种。

【讨论】:

明确答复,谢谢。您能指导我使用能够分析 CPU 和内存分配的 Windows 分析器吗?我发现的大部分内容只是能够对 CPU 进行采样。【参考方案3】:

无论您在想什么,后端可能不会发生类似的事情。 如今,编译器足够聪明,可以尽可能地优化您的程序。 因此,如果任何其他程序逻辑没有变化,您的想法 (count/10/10/10/10) 将使用 (count/10000) 进行优化。

我在您的代码中发现的另一件事是:如果您已经知道向量的大小,那么首先分配它可能会稍微提高您的性能。至于每次寻找新的存储数据的地方增加了不必要的计算。

另一种情况,虽然 CPU 速度远高于内存,但你不能只说问题出在内存而不是 CPU。分析您的代码一次,找出真正的瓶颈所在。

【讨论】:

以上是关于优化代码 - CPU 与内存 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Linux 内核 内存管理优化内存屏障 ① ( barrier 优化屏障 | 编译器优化 | CPU 执行优化 | 优化屏障源码 barrier 宏 )

Linux 内核 内存管理优化内存屏障 ① ( barrier 优化屏障 | 编译器优化 | CPU 执行优化 | 优化屏障源码 barrier 宏 )

写代码如何合理使用和优化我们的机器资源(CPU内存网络磁盘)

Android内存优化三:内存泄漏检测与监控

C#代码优化:斩断伸向堆内存的“黑手”

SRS性能(CPU)、内存优化工具用法