![](https://img-blog.csdnimg.cn/20190918140158853.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
3.3.2 《优化C++软件》
文章平均质量分 76
https://download.csdn.net/download/u012906122/89474619
vimer-hz
书是越读越薄的
展开
-
19 Literature
Intel:《IA-32 Intel Architecture Software Developer’s Manual》,第 1、2A、2B 和 3A 和 3B 卷。请参见 www.agner.org/optimize 和 comp.lang.asm.x86 新闻组的 FAQ 中的一些链接。包括在可从 www.intel.com 获取的 Intel C++ 编译器中。翻译 2023-11-23 22:14:53 · 34 阅读 · 0 评论 -
18 Optimization in embedded systems
在没有-fno-associative-math选项时,结果为0,在有-fassociative-math选项时,结果为1。例如: x*x可以优化为0. 如果x=INF,则结果将错误,因为INF-INF=NAN。-fno-math-errno: 不会为sqrt等函数设置errno的陷阱。这对于包含sqrt的分支的自动向量化是必要的。-fno-signed-zeros: 启用忽略零的符号的优化,例如x*0.0=0和x+0.0=x。翻译 2023-11-23 22:12:59 · 61 阅读 · 0 评论 -
17 Optimization in embedded systems
这通常属于系统编程领域,但在没有操作系统的应用程序中,这是应用程序员的工作。时钟频率可能低于标准个人计算机的百倍甚至千倍,RAM内存的数量甚至可能少于个人计算机的百万分之一。然而,如果避免使用大型图形框架、解释器、即时编译器、系统数据库以及其他在较大系统上常用的额外软件层和框架,就有可能在这些小型设备上运行相当快速的软件。如果想要计算一个具有两位小数的数字,例如,应该将其乘以100,以便表示为整数。程序员有责任确保数组足够大,可以处理包括终止零在内的字符串,并在必要时进行溢出检查(参见第105页)。翻译 2023-11-23 21:55:08 · 26 阅读 · 0 评论 -
16 Testing speed
一个时钟周期的长度是时钟频率的倒数,如第15页所解释的那样。如果在执行关键代码片段之前和之后读取时间戳计数器的值,那么您可以得到准确的时间消耗,即两个时钟计数之间的差异。通常的测试方法是创建一个小型的测试程序,使用适当的测试数据多次调用关键函数,并测量所需的时间。一个真实的性能测试应该包括不仅仅是一个单独的函数或热点,还应该包括包含关键函数和热点的最内层循环。偶尔,测量到的时钟计数远高于正常值。这种单元测试对于验证优化函数的功能是必要的,但不幸的是,单元测试并不能完全提供有关函数性能(速度)的全部信息。翻译 2023-11-23 21:53:38 · 26 阅读 · 0 评论 -
15 Metaprogramming
如果所有的输入都是已知的常量,一个好的优化编译器无论如何都会在编译时进行简单的计算,但是如果涉及到分支、循环、函数调用等更复杂的计算,很少有编译器能够在编译时进行。我认为除了简单的情况外,使用模板元编程是不明智的,因为复杂的代码本身就是一个风险因素,而验证、调试和维护此类代码的成本非常高昂,很少能够证明在性能上的收益是合理的。在C++的模板元编程中,循环被实现为递归模板。这是一种非常高效的方式来删除多余的代码,但是预处理器的功能有严重的限制,因为它在编译器之前起作用,并且只能理解最简单的表达式和运算符。翻译 2023-11-23 21:48:08 · 20 阅读 · 0 评论 -
14 Specific optimization topics
14.1 Use lookup tables如果一个常量表被缓存,那么从这个表中读取一个值是非常快的。通常从一级缓存中读取表只需要几个时钟周期。我们可以利用这个事实,如果一个函数的输入只有有限数量的情况,那么可以通过表查找来代替函数调用。以整数阶乘函数 (n!) 为例。它只允许输入区间 [0, 12] 中的整数。更大的输入会导致溢出,负数输入则产生无穷大。阶乘的典型实现如下:// Example 14.1aint factorial (int n) { // n!int i, f = 1;f翻译 2023-11-22 23:04:35 · 31 阅读 · 0 评论 -
13 Making critical code in multiple versions for different instruction sets
微处理器生产商不断向指令集添加新指令。这些新指令可以加快特定类型的代码执行速度。指令集中最重要的添加是第12章中提到的向量操作。如果代码针对特定的指令集进行编译,那么它将与支持该指令集或任何更高指令集的所有CPU兼容,但与早期的CPU不兼容。向后兼容的指令集序列如下所示:在手册4:“指令表”中提供了对指令集更详细的解释。根据第117页的说明,使用AVX或更高版本编译的代码与未使用AVX编译的代码存在一定的限制。使用最新的指令集的一个缺点是与旧微处理器的兼容性丧失。这个困境可以通过为不同的CPU制翻译 2023-11-22 21:09:04 · 39 阅读 · 0 评论 -
12 Using vector operations
使用长向量库的缺点是,如果你正在执行一个序列的计算,那么你必须在调用下一个步骤的函数之前将每个步骤的中间结果存储在一个临时数组中。short int的宽度为16位,而int的宽度为32位,因此,一个向量可以容纳8个short int类型的数字,而只能容纳4个int类型的数字。在AVX之前的指令集中,高效的向量操作要求数组的地址可被16整除。SSE2是向量类库支持的最低指令集,SSE4.1在select函数中具有优势,AVX2指令集具有更大的向量寄存器优势,而AVX512则具有更大的向量和更高效的分支操作。翻译 2023-11-21 22:34:42 · 137 阅读 · 0 评论 -
11 Out of order execution
最重要的是避免长的依赖链。它们可以检测到在示例11.3的循环的一个迭代中,寄存器temp的值与前一次迭代中的值无关。当前的CPU通常拥有一个或两个浮点加法单元,并且这些单元是流水线处理的,就像之前解释的那样,因此它可以在前一个加法完成之前启动新的加法操作。例如,在示例11.2b中,如果列表中的元素数目是奇数,那么我们需要在循环外部添加最后一个元素,或者在列表中添加一个额外的虚拟元素,并将该额外元素置零。一个迭代的计算中,除了循环计数器之外,不应该依赖于上一次迭代的结果(如果是整数,则计算速度很快)。翻译 2023-11-21 22:25:49 · 33 阅读 · 0 评论 -
10 Multithreading
在此,功能分解意味着不同的线程执行不同类型的工作。重要的是,用户界面不在同一个线程中作为非常耗时的任务,因为这将导致令人恼人的长而不规则的响应时间。例如,如果多个线程共享同一个队列、列表、数据库或其他数据结构,则可以考虑为每个线程提供自己的数据结构,然后在所有线程完成耗时的数据处理后将这些数据结构合并。缺点是如果线程使用不同的内存区域,缓存将被填满,并且如果线程对相同的内存区域进行写操作,就会发生缓存争用。在数据分解的情况下,最好没有更多具有相同优先级的线程,而是等于系统中可用的核心或逻辑处理器的数量。翻译 2023-11-21 22:22:27 · 28 阅读 · 0 评论 -
9 Optimizing memory access
9.1 Caching of code and data缓存是计算机中主内存的代理。这个代理比主内存小而且更接近CPU,因此访问速度更快。为了实现对最常用数据的最快访问,可能会有两个或三个级别的缓存。CPU的速度比RAM内存快得多。因此,高效的缓存对于系统性能非常重要。9.2 Cache organization如果您正在编写具有非顺序访问和需要避免缓存争用的大型数据结构的程序,了解缓存的组织方式是非常有用的。如果您满意更加经验性的准则,可以跳过本节。大多数缓存被组织为行和组。让我通过一个例子来解释。我翻译 2023-11-21 22:20:26 · 34 阅读 · 0 评论 -
8 Optimizations in the compiler
8.1 How compilers optimize现代编译器可以对代码进行许多修改以提高性能。了解编译器可以做什么和不能做什么对程序员很有用。下面的章节描述了一些编译器优化,这些优化对程序员来说是相关的。Function inlining编译器可以通过被调用函数的函数体来替代函数调用。例如:// Example 8.1afloat square (float a) {return a * a;}float parabola (float x) {return square(x) + 1.翻译 2023-11-20 23:10:41 · 39 阅读 · 0 评论 -
7 The efficiency of different C++ constructs
大多数程序员对程序代码如何转换为机器代码以及微处理器如何处理这些代码几乎没有了解。例如,许多程序员不知道双精度计算与单精度计算的速度是一样快的。谁会知道模板类比多态类更高效呢?本章旨在解释不同C++语言元素的相对效率,以帮助程序员选择最高效的替代方案。其他手册系列中的其他卷进一步解释了理论背景。7.1 Different kinds of variable storage根据在C++程序中的声明方式,变量和对象存储在内存的不同部分。这对数据缓存的效率有影响(参见第91页)。如果数据在内存中随机散布,数据翻译 2023-11-20 00:03:48 · 50 阅读 · 0 评论 -
6 Development process
在规划阶段进行对数据结构、数据流和算法的全面分析是很好的,以预测哪些资源最为关键。然而,在早期规划阶段可能存在许多未知因素,很难获得对问题的详细概述。在复杂的情况下,完全理解可能仅在开发过程的后期阶段才能实现。在这种情况下,你可以将软件开发视为一个学习过程,主要的反馈来自测试和编程问题。由于大多数开发方法都是增量或迭代的,因此重要的是为每个中间版本保存备份副本的策略。一些软件开发模型具有严格的形式化要求,在软件的逻辑架构中需要多层抽象。将软件分割成过多独立的抽象层是降低性能的常见原因。翻译 2023-11-19 23:37:26 · 37 阅读 · 0 评论 -
5 Choosing the optimal algorithm
"英特尔数学核心库"包含了许多常见的数学计算函数,包括线性代数和统计学,而"英特尔性能基元"库则包含了许多音频和视频处理、信号处理、数据压缩和加密的函数(www.intel.com)。哈希表可以大幅提高在非常大的数据库中的搜索时间,但对于那些列表非常小,二分查找甚至线性查找就足够快的情况下,使用哈希表是没有必要的。在某些情况下,你可能需要测试多个不同的算法,以找到在典型的测试数据集上表现最好的算法。你需要参考关于算法和数据结构的通用文献,以了解标准任务(如排序和搜索)的算法,或者更复杂数学任务的专门文献。翻译 2023-11-19 23:35:34 · 31 阅读 · 0 评论 -
4 Performance and usability
兼容性问题:所有的软件都应该在不同的平台、不同的屏幕分辨率、不同的系统色彩设置和不同的用户访问权限上进行测试。- 安全性:对具有网络访问权限的软件的漏洞攻击和其他滥用可能对许多用户造成极大的损失。- 认真对待用户反馈:用户的投诉应该被视为关于错误、兼容性问题、易用性问题和期望的新功能的宝贵信息来源。这是一份列举了一些让软件用户感到沮丧和浪费时间的典型问题,以及软件开发人员应该注意的重要的易用性问题的清单。- 后台服务:许多在后台运行的服务对用户来说是不必要的,也是资源的浪费。翻译 2023-11-19 23:32:00 · 23 阅读 · 0 评论 -
3 Finding the biggest time consumers
如果计算机上安装了许多这样的程序,启动时间可能需要几分钟,这完全浪费了用户的时间。此外,可以在程序的最重要或关键部分之前和之后读取时间,以测量每个部分所需的时间。除法需要更长的时间。如果程序中所有数据的总大小大于二级缓存,并且数据在内存中分散或以非连续的方式访问,那么内存访问很可能是程序中最耗时的部分。在时间测量期间,您可能需要将线程固定到特定的CPU核心上,以避免这种情况发生(在Windows中,使用SetThreadAffinityMask,在Linux中使用sched_setaffinity)。翻译 2023-11-19 23:29:06 · 30 阅读 · 0 评论 -
2 Choosing the optimal platform
最快的执行无疑是通过完全编译的代码实现的。针对此问题有几种可能的解决方法:(1) 在溢出发生之前检查溢出,(2) 使用无符号整数-它们保证会环绕回来,(3) 使用选项-ftrapv捕获整数溢出,但这样效率极低,(4) 使用选项-Wstrict-overflow=2获得此类优化的编译器警告,或者(5) 使用选项-fwrapv或-fno-strict-overflow使溢出行为具有明确定义。然而,通过良好优化的软件设计,即使在这些小型设备上,许多应用程序也可以实现良好的性能,正如第173页所讨论的那样。翻译 2023-11-19 23:22:10 · 32 阅读 · 0 评论 -
1 Introduction
在过去的几十年里,尽管微处理器性能呈指数级增长,但令人沮丧的长响应时间的软件产品仍然存在,这是一个悖论。这种编写风格的转变原因在于软件项目变得更加庞大和复杂,对软件开发成本的关注增加,以及计算机性能的提升。首先和首要的是,结构化软件开发的优先级高,而程序效率的优先级低,这体现在选择编程语言和接口框架上。在这种情况下,建议软件开发人员改进软件,而不是依赖于越来越快的微处理器:避免使用最浪费资源的软件工具和框架,并避免功能膨胀。此外,应小心注意相对较原始的编程风格可能存在的问题,并考虑使用经济高效的编程构造。翻译 2023-11-19 23:16:25 · 24 阅读 · 0 评论