Agner Fog编写的优化手册
文章平均质量分 85
wuhui_gdnt
这个作者很懒,什么都没留下…
展开
-
优化C++软件(14)
在循环中的计算,其中每次迭代需要前面的结果,被称为循环携带依赖链。如果可以打破这样的依赖链,增益很大。当前CPU仅有一个浮点加法单元,但这个单元是流水线化的,如上所述,因此它可以在前面的加法完成周期,开始一个新的加法。非常长的依赖链对CPU的乱序资源施加压力,即使它们不带入循环的下一个迭代。具有乱序能力的微处理器可以重叠迭代,在前面迭代完成之前,开始一个迭代的计算。如果微处理器从时刻T到T+5进行对sum1的加法,它可以从时刻T+1到T+6进行另一个对sum2的加法,整个循环将仅需256时钟周期。翻译 2023-12-13 17:46:37 · 123 阅读 · 0 评论 -
优化C++软件(13)
例如,多个线程可以共享相同的队列、链表、数据库或其他数据结构,你可以考虑向每个线程给出它自己的数据结构,然后在所有线程完成耗时的数据处理时,最后合并多个数据结构,是否可能的。当前CPU仅有一个浮点加法单元,但这个单元是流水线化的,如上所述,因此它可以在前面的加法完成周期,开始一个新的加法。线程的使用在第47页讨论。坏处是,如果线程使用不同的内存区,缓存将被填满,而如果线程写到相同内存区,则有缓存竞争。将文件访问与网络访问放入独立的线程,在一个线程等待硬盘或网络响应时,另一个线程可以进行计算,也是有用的。翻译 2023-12-04 17:37:43 · 46 阅读 · 0 评论 -
优化C++软件(12)
行28的前8个元素共享同一个缓存行,但这8个元素将进入列28的8个不同的缓存行,因为缓存行遵循行,但不遵循列。如表9.3所示,仅在预期一个2级缓存不命中时,不使用缓存保存数据的方法是有优势的。表9.1中我的实验结果显示,当在2级缓存中出现竞争时,比不出现竞争,需要6倍的时间转置一个矩阵。这个函数按列模式写矩阵a,其中关键步长将导致所有的写在1级与2级缓存中载入新的缓存行。这个代码的问题是,如果对角线下元素matric[r][c]是按行访问的,那么对角线上的镜像元素matric[c][r]就是按列访问的。翻译 2023-11-29 14:13:41 · 41 阅读 · 0 评论 -
优化C++软件(11)
如果不能预测最终大小或预测结果太小,那么分配一个新的更大的内存块,把旧内存块的内容拷贝到新内存块是必要的。中用于访问容器元素的所谓迭代器,对许多程序员而言是笨拙的,如果你可以使用一个具有简单索引的线性列表,它们是不必要的。如果元素数在编译时刻已知,或者可以设置一个不是太大的上限,那么最优的方案是固定大小数组或不使用动态内存分配的容器。如果在保存第一个元素前,要保存的元素总数已知(或者可以做出一个合理的估计),那么最好使用允许你预先保留所需内存的容器,而不是分段分配或者在内存块变得太小时重新分配。翻译 2023-11-21 14:39:02 · 44 阅读 · 0 评论 -
优化C++软件(10)
例如,父类的成员函数在一个源文件,派生类在另一个源文件,可能是方便的。控制动态链接库函数的地址,没有容易的方法。从地址0x2710读或写一个变量,会使缓存将地址0x2700到0x273F的64或0x40字节载入0x1C组4条缓存行中的一条。将常用函数与很少使用的函数分开,将很少使用的分支,比如错误处理,放在函数末尾或一个独立的函数里。当然,使用联合不是一个安全的程序实践,因为如果a与b的使用重叠,你将不会得到编译器的警告。例如,如果程序有两个数组,a与b,以a[0],b[0],a[1],b[1],……原创 2023-11-16 16:59:07 · 59 阅读 · 0 评论 -
优化C++软件(9)
8.5.编译器优化选项所有C++编译器有各种你可以打开、关闭的优化选项。学习正在使用编译器可用的选项,并打开所有相关选项,是重要的。许多优化选项与调试不兼容。调试器可以一次执行一行代码,并显示所有变量的值。显然,在部分代码被重排、内联或优化掉时,这是不可能的。通常制作可执行程序的两个版本:带有完整调试支持,在程序开发期间使用的调试版本,以及打开所有相关优化选项的发布版本。大多数IDE(集成开发环境)有制作目标文件与可执行文件的调试版本与发布版本的设施。确保区分这两个版本,在可执行文件的优化版本里关.翻译 2020-08-07 11:03:23 · 493 阅读 · 0 评论 -
优化C++软件(8)
8.2.不同编译器的比较我在7个不同品牌的C++编译器上进行了一系列实验,看它们是否能够进行各种优化。结果汇总在表8.1中。这个表展示了在我的测试例子中,不同的编译器是否成功应用了各种优化方法以及代数约简。这个表可以给出哪些优化你可以预期一个特定的编译器会进行,哪些优化你必须手动进行的某些预示。必须强调,在不同的测试例子上,编译器行为会不同。你不能预期编译器的行为总是符合这个表。...翻译 2020-01-10 12:03:11 · 426 阅读 · 0 评论 -
优化C++软件(7)
8.1. 编译器里的优化8.1. 编译器如何优化现代编译器可以对代码进行许多优化以提升性能。程序员知道编译器能做什么,不能做什么是有好处的。下面章节描述某些程序员应该知道的编译器优化。函数内联编译器可以将被调用函数体替换函数调用。例子:// Example 8.1afloat square (float a) { return a * a;}float p...翻译 2020-01-03 11:25:24 · 325 阅读 · 0 评论 -
优化C++软件(6)
7.15. 函数参数在大多数情形里,函数参数通过值传递。这意味着参数的值被拷贝到一个局部变量。对简单类型,比如int,float,double,bool,enum以及指针与引用,这是高效的。数组总是以指针传递,除非它们被封装在一个类或结构体里。如果参数是复合类型,比如结构体或类,情形更复杂。如果满足以下条件,复合类型参数的传递更高效:对象很小能放入一个寄存器 对象没有拷贝构造函...翻译 2019-12-27 10:54:29 · 396 阅读 · 0 评论 -
优化C++软件(5)
7.6. 指针与引用指针与引用指针与引用同样高效,因为它们实际上做相同的事情。例如:// Example 7.12void FuncA (int * p) { *p = *p + 2;}void FuncB (int & r) { r = r + 2;}这两个函数做同样的事情,如果你看编译器产生的代码,你将注意到对这两个函数,代码实际上...翻译 2019-12-20 11:38:42 · 228 阅读 · 0 评论 -
优化C++软件(4)
7. 不同C++构造的效率对一段程序代码如何被翻译到机器码,以及微处理器如何处理这个代码,许多程序员知之甚少。例如,许多程序员不知道双精度计算与单精度计算一样快。有谁知道一个模板类比一个多态类要更高效?本章致力于解释不同C++语言元素的相对效率,以帮助程序员选择最高效的方案。在本系列手册的其他卷里,进一步解释理论背景。7.1.不同类型变量的储存变量与对象保存在内存的不同部分,依赖...翻译 2019-12-13 15:38:05 · 306 阅读 · 0 评论 -
优化C++软件(3)
4. 性能与可用性性能更好的软件产品是为用户节省时间。对许多计算机用户时间是宝贵的资源,在慢的、难用的、不兼容或易出错的软件上浪费了许多时间。所有这些问题是可用性问题,我相信应该在更宽广的可用性角度看待软件性能。可用性没有手册,但我相信这里引起软件程序员注意软件有效使用最常见的障碍是必要的。更多这个话题,参考WikiBooks上我的电子书《Usability for Nerds》。以下...翻译 2019-12-06 11:29:11 · 281 阅读 · 0 评论 -
优化C++软件(2)
3. 出最大的时间消耗者3.1. 一个时钟周期是多少?在本手册中,我使用CPU时钟周期,而不是秒或毫秒,作为时间测度。这是因为计算机的速度有非常大的差异。如果我写某个东西今天需要10 μs,在下一代计算机它可能仅需要5 μs,我的手册很快就过时了。但如果我写某个东西需要10时钟周期,那么即使CPU时钟周期加倍,它仍将需要10时钟周期。一个时钟周期的长度是时钟频率的倒数。例如,如果时钟频...翻译 2019-11-22 11:27:41 · 511 阅读 · 0 评论 -
优化C++软件——目录
1. 介绍 1.1. 优化的代价2. 选择最优的平台 2.1. 硬件平台的选择 2.2. 微处理器的选择 2.3. 操作系统的选择 2.4. 程序语言的选择 2.5. 编译器的选择 2.6. 函数库的选择 2.7. 用户接口框架的选择 2.8. 克服C++语言的缺点3. 找出最大的时间消耗者 3.1. 一个时钟周期是多少? 3...翻译 2019-11-15 11:40:07 · 377 阅读 · 0 评论 -
优化C++软件(1)
1. 介绍本手册面向希望使他们的软件更快的高级程序员与软件开发者。假定读者对C++编程语言掌握良好,并对编译器如何工作有基本的了解。选择C++语言作为基础的原因在下面第8页解释。本手册主要基于我对编译器及微处理器如何工作的研究。给出的建议基于Intel,AMD与VIA的x86微处理器家族,包括64位版本。x86处理器用在大多数使用Windows、Linux、BSD与Mac OS操作系统的通用平...翻译 2019-11-15 11:37:48 · 694 阅读 · 0 评论 -
优化汇编例程(18)
18. 测量性能18.1. 测试速度许多编译器有分析器,使测量一个程序中每个函数被调用多少次以及花了多长时间成为可能。找出程序里的热点十分有用。如果一个特定的热点占用了总执行时间的很大部分,那么这个热点应该是优化工作的对象。许多分析器不是非常准确,当然对代码一小部分的精细调整不够准确。测试一段代码速度最准确的方法是使用所谓的时间戳计数器。这是一个内部的64位时钟计数器,使用指令RDTS...翻译 2019-11-08 13:50:38 · 236 阅读 · 0 评论 -
优化汇编例程(17)
17. 特别话题17.1. XMM与浮点寄存器具有SSE指令集的处理器可以在XMM寄存器中进行单精度浮点计算。具有SSE2指令集的处理器还可以在XMM寄存器中进行双精度浮点计算。在XMM寄存器与旧式的浮点栈寄存器中,浮点计算几乎一样快。使用浮点栈寄存器ST(0) ~ ST(7)还是XMM寄存器的决定,取决于以下因素。使用ST()寄存器的好处:与没有SSE或SSE2的旧式处理器兼容。...翻译 2019-10-18 11:43:22 · 511 阅读 · 0 评论 -
优化汇编例程(5)
5. 在C++中使用固有函数正如已经提及的,有3个不同的方式制作汇编代码:在C++中使用固有函数与向量类,在C++中使用内联汇编,以及独立的汇编模块。固有函数在本章描述。其他两个方法在下面章节描述。固有函数与向量类是高度推荐的,因为它们比汇编语言语法更容易、也更安全。Microsoft,Intel,Gnu与Clang C++编译器都支持固有函数。大多数固有函数产生一条机器指。因此,一个...翻译 2019-05-31 12:19:25 · 352 阅读 · 0 评论 -
优化汇编例程(6)
6. 使用内联汇编内联汇编是把汇编代码放入一个C++文件的另一个方法。关键字asm或_asm或__asm或__asm__告诉编译器这个代码是汇编。对内联汇编,不同的编译器有不同的语法。不同的语法解释如下。使用内联汇编的好处有:它很容易与C++结合。 定义在C++代码中的变量与其他符号可以从汇编代码访问。 仅不能以C++编写的代码使用汇编编写。 所有汇编指令都可用。 生成的代码就...翻译 2019-06-06 11:50:57 · 524 阅读 · 0 评论 -
译 优化汇编例程(7)
7. 使用汇编器使用固有函数与内联汇编,你可以做的,受到某些限制。这些限制可以通过使用汇编器克服。原则是,编写一个或多个包含程序最关键函数的汇编文件,以C++编写不那么关键的部分。然后将不同的模块链接为一个可执行文件。使用汇编器的好处是:你可以做的,几乎没有限制。 对最终可执行代码的所有细节,你有完全的控制。 代码的方方面面都可以优化,包括函数prolog与epilog、参数传输方...翻译 2019-06-21 11:28:41 · 349 阅读 · 0 评论 -
优化汇编例程(4)
4. ABI标准ABI表示应用程序二进制接口(Application Binary Interface)。ABI是函数如何调用,参数与返回值如何传递,允许函数改变哪些寄存器的标准。在合并汇编与高级语言时,遵守适合的ABI标准是重要的。调用惯例等的细节涵盖在手册5《不同C++编译器与操作系统的调用惯例》中。这里,为了您的方便。汇总了最重要的规则。4.1. 寄存器的使用 ...翻译 2019-05-24 11:37:40 · 347 阅读 · 0 评论 -
优化汇编例程(3)
3.3. 取址模式16位模式中的取址16位代码使用分段内存模式。一个内存操作数可以有任意这些部分:段说明。这可以是任何段寄存器或与一个段寄存器关联的一个段或组名。(缺省的段是DS,除非BP被用作一个基址寄存器)。段可由一个段里定义的标签暗示。 一个定义可重定位偏移的标签。这个偏移相对于由链接器计算的段起始地址。 一个立即数偏移。这是一个常量。如果还有一个重定位偏移,这些值加起来。...翻译 2019-05-17 11:45:47 · 426 阅读 · 0 评论 -
优化汇编例程(2)
3. 汇编编程基础3.1. 可用的汇编器X86指令集有几个汇编器可用,但目前它们没有一个好到被一致推荐。汇编程序员处在x86汇编没有统一语法的不幸境地之中。不同的汇编器使用不同的语法变体。最常用的汇编器有如下。MASM这个Microsoft汇编器包括在Microsoft C++编译器中。有时可以通过下载Microsoft Windows驱动套装(WDK),或平台软件开发套装(SDK...翻译 2019-05-06 13:35:28 · 630 阅读 · 0 评论 -
优化汇编例程(14)
向量编程因为微处理器的最大时钟频率存在技术限制,增加处理器吞吐率的趋势是并行处理多个数据。单指令多数据(SIMD)编程的原理是在一个大的寄存器中封装一个向量或一组数据,在一次操作中一起处理。有数以百计的SIMD指令可用。在《IA-32 Intel Architecture Software Developer’s Manual》卷2A及2B,以及《AMD64 Architecture Progr...翻译 2019-09-20 15:24:01 · 2265 阅读 · 0 评论 -
汇编优化例程的目录(已完结)
1. 介绍1.1. 使用汇编代码的理由1.2. 不使用汇编代码的理由1.3. 本手册覆盖的操作系统2. 在你开始之前2.1. 在你开始编程之前所要做的决定2.2. 制定测试策略2.3. 常见的编程陷阱3. 汇编编程基础3.1. 可用的汇编器3.2. 寄存器集与基本指令3.3. 取址模式3.4. 指令代码格式...翻译 2019-04-26 11:53:55 · 761 阅读 · 0 评论 -
优化汇编例程(8)
8. 制作与多个编译器及平台兼容的函数库有若干兼容性问题需要注意,如果你希望制作与多个编译器、多个编程语言及多个操作系统兼容的函数库。要处理的最重要的兼容性问题有:名字重整 调用惯例 目标文件格式这些可移植问题最容易的解决方案是以一个高级语言,比如C++,制作代码,使用固有函数或内联汇编制作任何必须的低级构造。然后使用不同的编译器对不同的平台编译这个代码。。注意,不是所有的C++编译...翻译 2019-06-28 11:48:53 · 296 阅读 · 0 评论 -
优化汇编例程(9)
9. 为速度优化9.1. 识别代码中最关键部分优化软件不只是摆弄正确的汇编指令。许多现代的应用程序在载入模块、资源文件、数据库、接口框架等方面,比程序实际进行的计算,要花多得多的时间。优化计算时间不会有用,如果程序把99.9%的时间花在计算之外的事情上。在开始优化前,找出时间最多花在哪里是重要的。有时,解决方案会是从C#变为C++、使用不同的用户接口框架、把文件输入与输出组织得不一样、缓存...翻译 2019-07-05 11:15:37 · 380 阅读 · 0 评论 -
优化汇编例程(10)
10. 优化大小代码缓存可以保存8到32kb代码,如第77页,第11章解释。如果将代码关键部分保持在代码缓存里有问题,那么可以考虑减小代码的大小。减小代码大小还可以改进代码的解码。在Core2处理器上,不超过64字节代码的循环执行得特别快。如果速度不重要,甚至可能希望以降低速度为代价,减小代码大小。32位代码通常大于16位代码,因为在32位代码中地址与数据常量需要4字节,在16位代码需...翻译 2019-07-12 11:29:21 · 515 阅读 · 0 评论 -
优化汇编例程(11)
11. 优化内存访问从1级缓存读大约要3个时钟周期。从2级缓存读需要数十个时钟周期。从主存读需要数百时钟周期。如果跨了DRAM页边界,访问时间甚至更长,如果内存区已经被交换到硬盘,时间极长。这里,我不能给出确切的访问时间,因为它依赖硬件配置,且由于技术的快速发展,数值持续地变化。不过,从这三个值,显而易见,代码与数据的缓存对性能极端重要。如果代码有许多缓存不命中,每个缓存不命中的代价超过一...翻译 2019-07-19 11:07:54 · 341 阅读 · 0 评论 -
优化汇编例程(12)
12. 循环一个CPU密集程序的关键热点几乎总是一个循环。现代计算机的时钟频率非常高,即使最耗时的指令、缓存不命中及低效的异常,都可以不到1毫秒完成。由低效代码导致的时延仅在重复数百万次时,才是显著的。如此高的重复次数很可能仅在一系列嵌套循环的最内层出现。可以做的就是,在本章中讨论的,改进循环的性能。12.1. 使循环开销最小循环开销是跳回循环开始以及确定何时退出循环所需的指令。优化这...翻译 2019-08-16 11:44:24 · 396 阅读 · 0 评论 -
优化汇编例程(15)
多线程从单个CPU你能得到的处理能力是有限的。因此,许多现代计算机系统有多个CPU核。利用单个CPU的方式是,在多个线程间分解计算任务。通常,最优线程数等于CPU核个数。工作负荷应该理想地在线程间平均分配。在代码具有粗粒度的内秉并行性时,多线程化是有用的。多线程化不能用于细粒度并行,因为启动与停止线程以及线程同步有可观的开销代价。线程间通讯代价会相当高,尽管这些代价在较新的处理器上降低了。计...翻译 2019-09-20 15:17:46 · 436 阅读 · 0 评论 -
优化汇编例程(16)
16. 有问题的指令16.1. LEA指令(所有处理器)对许多应用,LEA指令是有用的,因为它可以在一条指令里执行一个偏移操作,两个加法,及一个移动。例子:; Example 16.1a, LEA instructionlea eax, [ebx+8*ecx-1000]比; Example 16.1bmov eax, ecxshl eax, 3add eax, ...翻译 2019-09-27 11:33:52 · 571 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(10)
4.3. 将复杂指令分解为更简单的指令你可以分解读/修改以及读/修改/写指令来改进成对性。例如:;Example 4.10a. P1/PMMX Imperfect pairing add[mem1], eax add[mem2], ebx 这个代码可以分解为一个序列,将时钟周期从5降到3:;Example 4.10b. P1/PMMX Imperfect pair翻译 2017-12-01 11:40:46 · 495 阅读 · 0 评论 -
优化汇编例程(1)
作者:Agner Fog。Technical University of DenmarkCopyright © 1996 – 2017。最后更新:2017-05-011. 介绍这是五本手册系列中的第二本:优化C++软件:对Windows,Linux及Mac平台的优化指引。 优化汇编例程:对x86平台的优化指引。 Intel, AMD及VIA CPU的微架构:对汇编程序员及编译器...翻译 2019-04-26 11:46:02 · 722 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(39,完)
21. 微架构的比较已经调查的最先进微架构代表了不同的微架构核心:AMD,Pentium 4(NetBurst),Pentium M与Intel Core 2核心。现在我将讨论这些微架构的优缺点。我不讨论内存带宽的差别,因为这部分依赖于内部硬件及缓存大小。这4个微架构类型都有不同缓存大小的不同版本。因此,微架构的比较主要与CPU密集应用相关,与内存密集应用不那么相关。21.1. AMD K...翻译 2019-03-29 11:29:49 · 1824 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(38)
20. AMD Bobcat与Jaguar流水线Bobcat与Jaguar是低时钟频率、关注低功耗的更小微架构。它通过在大多数时间降低时钟频率,相当进取地节约功耗。我在Bobcat上的测试中,全速仅在数百万行CPU密集代码后看到。在要求更高速度时,可以在BIOS设置中关闭这个节能特性(CoolNQuiet)。Bobcat有两个核,继承者Jaguar(原文为Bobcat)目前最多有4个核,未...翻译 2019-03-22 11:57:13 · 475 阅读 · 2 评论 -
Intel, AMD及VIA CPU的微架构(16)
5.12. 选择最优的指令使用更高效的指令替换较低效的指令有许多种可能性。最重要的前行汇总如下。INC与DEC这些指令有部分标记访问的问题,如第54页所示。总是以ADDEAX, 1等替换INCEAX。8位与16位整数用MOVZXEAX, BYTE PTR [MEM8]替换MOV AL, BYTE [MEM8]用MOVZXEBX, WORD PTR [MEM16]替换MOV BX, WOR...翻译 2018-04-20 11:43:19 · 336 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(15)
5.9. 写转发暂停(Storeforwarding stalls)访问一个内存操作数一部分的问题,比访问一个寄存器一部分的问题,要严重得多。对之前的处理器,这些问题都是相同的,参考第76页。例子:;Example 5.8a. Store forwarding stall movdword ptr [mem1], eax movdword ptr [mem1+4], 0 fild qw...翻译 2018-03-16 11:50:22 · 399 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(14)
5.6. 执行单元间传输数据一个操作的时延在大多数情形中变得更长,如果下一条依赖的指令没有在相同的执行单元里执行。例如(P4E):;Example 5.5. P4E transfer data between execution units ;clock ex.unit subunitpa...翻译 2018-03-02 11:38:57 · 485 阅读 · 0 评论 -
Intel, AMD及VIA CPU的微架构(12)
5.3. 指令解码不在追踪缓存的指令将直接从指令解码器去到执行流水线。在这个情形下,最大吞吐率由指令解码器确定。在大多数情形下,解码器为每条指令产生1-4个μop。对于要求多于4个μop的复杂指令,μop从微代码(microcode)ROM提交。手册4:“指令表”中列出了机器码μops的数目,以及每条指令产生的微代码μops。解码器最多可以每时钟周期处理一条指令。少数情形下解翻译 2018-01-26 11:51:05 · 451 阅读 · 0 评论