读书报告范文

| 报告 |

【www.guakaob.com--报告】

  以下是中国招生考试网www.chinazhaokao.com为大家整理的文章,希望大家能够喜欢!更多资源请搜索文档频道与你分享!

  读书报告

  王博

  1.编写高效程序程序需要两类活动:第一.选择一组最好的算法和数据结构。第二.编写出编译器能够有效优化以转换成高效有执行代码的源代码。

  2.需要在实现和维护程序的简单性与它的运行速度之间做出权衡折中。

  3.就编译器而言,编译技术被分为“与机器有关”和“与机器无关”两类。“无关”:使用技术时可以不考虑将执行代码的计算机的特性。“有关”:技术依赖与许多机器的低级细节。

  4.转换会降低代码的模块性和可续性,因此,应该在获得最大性能是首要目标时,才使用这些技术。

  5.研究汇编代码是理解编译器以及产生的代码会如何进行的最有效的手段之一。

  6.编译器优化程序的能力受几个因素的限制,包括:要求他们绝不能改变正确的程序行为;它们对程序行为,对使用它们的环境了解有限;需要很快的完成编译任务。

  7.存储器别名使用:编译器必须假设不同的指针可能会指向存储器中同一个位置,造成了一个主要妨碍优化的因素,这也是可能严重限制编译器产生优化代码机会的程序的一个方面。

  8.对许多程序都很有用的度量标准是每元素的周期数(CPE)。

  9.处理器活动的顺序是由时钟控制的,始终提供了某个频率的规律信号,用兆赫兹(MHz)千兆赫兹(KHz)来表示。

  10.一个过程所需要的时间可以用一个常数加上一个被处理元素个数成正比的因子来描述。

  11.最小二乘方拟合:寻找一条形如y=mx+b的线,使得下面这个误差最小: 12.typedef int data_t;除了头以外我们还会分配一个len个data_t类型对象的数组来存放实际的向量元素、

  13.边界检查降低了程序出错的几率,但是正如我们看到的那样,它也明显影响了程序的性能。

  14.除了浮点数乘法以外,对于各种数据类型和不同运算的时间基本上都是同等的,浮点数乘法有很高的时钟周期数是由于我们基准程序数据中的异常,找出这样的异常是性能分析和优化的重要组成部分。

  15.我们只需计算一次向量的长度,然后在我们的测试条件中使用这个值。

  16.代码移动包括识别出要执行多次但是计算结果不会改变的计算,因而我们可以将计算移动到代码前面的,不会被多次求值的部分。

  17.编译器会假设函数会有副作用。

  18.没有字符会从非零变为零,或是反过来,因为这超出了编译器的能力,必须由程序员自己进行这样的变换。

  19.过程调用会带来相当大的开销,妨碍大多数形式的程序优化。

  20.向量的内容是作为数组来存储的,而不是作为诸如链表之类的某种其他数据结构来存储的。

  21.用Told/Tnew的比率表示性能改进,发生了改进它应该是大于1.0的数字,“3.5X”读作“3.5倍”。

  22.优化编译器不能判断函数会在什么情况下被调用,以及程序员的本意可能是什么,相反,在编译时编译器有责任保持它的功能,即使这意味着生成低效率的代码。

  23.P6微体系结构是高端处理器的典型,在工业界成为超标量,意思是它可以在每个时钟周期执行多个操作,而且是乱序的,意思就是指令执行的顺序不一定要与它们在汇编程序中的顺序一样,整个设计有两个主要部分:ICU(制定控制单元)和EU(执行单元)。前者负责从存储器中读出指令序列,并根据这些指令序列生成一组针对程序数据的基本操作;而后者执行这些操作。

  24.ICU从指令高速缓存中读取指令,指令高速缓存包括最近访问的指令,ICU会在当前正在执行的指令之前取指,它有足够的时间对指令解码,并将操作发送给EU。

  25.分支预测技术:处理器会预测是否选择分支,同时还预测分支的目标地址。

  26.投机执行技术:处理器会开始取出它预测的分支处的指令并对指令解码,甚至于在它确定分支预测是否正确之前就开始执行这些操作。若确定分支预测错误,它会将状态重新设置到分支点的状态,并开始取出和执行另一个方向上的指令。

  27.一旦指令的操作完成了,而所有导致这条命令的分支点也都被认为预测正确,那么这条指令就可以退役了,所有对程序寄存器的更新都可以被实际执行了,另一方面,如果导致该指令的某个分支点预测错误,这条指令会被清空,丢弃所有计算出来的值。

  28.任何对程序状态的更新都只会在指令退役时才会发生。

  29.最常见的控制操作数在执行单元间传送的机制成为寄存器重命名。

  30.有了寄存器重命名,即使只有在处理器确定了分支结果之后才能更新寄存器,才可以预测着更新操作的整个序列。

  31.执行时间:功能单元完成操作所需要的总周期数。 发射时间:连续的、独立操作之间的周期数。

  32.只有当要执行的操作是连续的,逻辑上独立的,才能被流水线化。大多数单元能够每个时钟周期开始一个新的操作,仅有的例外是浮点乘法器和两个除法器,浮点乘法器要求连续的操作之间至少要有两个周期,而两个除法器根本就没有流水线化。

  33.对很大的向量来说,循环执行的操作是性能的决定性因素。

  34.标记是位模式而不是符号名字。

  35.一个有限多个功能单元和完美的分支预测处理器的性能只受下列因素的限制:功能单元的执行时间和吞吐量,以及程序中的数据相关性。

  36.一个只有固定数目的功能单元的处理器性能只受数据相关性、功能单元的执行时间以及资源约束的限制。

  37.处理性能受三类约束限制:第一,程序中的数据相关性迫使一些操作延迟直到它们的操作数被计算出来。第二,资源约束限制了在任意给定时刻能够执行多少个操作。最后,分支预测逻辑的成功限制了处理器能够在指令流中超前工作以保持执行单元繁忙的程度。

  38.循环展开技术:在一次迭代中访问数组元素并做乘法,这样得到的程序需要更少的迭代,从而降低了循环的开销。

  39.循环展开本身只会帮助整数求和情况中代码的性能,循环展开可以降低CPE。

  40.净CPE为过程需要的总周期数除以元素的个数。

  41.优化级别设置总够高的编译器可以很容易的执行循环展开。

  42.与数组相比,不带展开的整数求和的指针版本的CPE实际上还变糟了一个周期。

  43.指针和数组代码的相对性能依赖于机器、编译器,甚至某个特殊的过程,编译器对数组代码应用非常高级的优化,而对指针代码只应用最小限度的优化。为了可读性的缘故,通常数组代码更可取一些。

  44.代码不能利用流水线化的能力,即使是使用循环展开也不行,直到前面的计算完成之前我们都不能计算单独变量的新值,因此处理器会暂停(stall),等待开始新的操作,直到当前操作完成。

  45.对于一个可结合和可交换的合并操作来说,我们可以通过将一组合并操作分割成两个或者更多的部分,并在最后合并结果来提高性能。

  46.对于整数求和,并行化并没有帮助,因为指数加法的执行时间只是一个时钟周期,不过对于整数和浮点乘法,我们将CPE减小了一倍。

  47.选待分割:优化编程器潜在的将combine4中所示的代码首先转换成combine5的一个二路循环展开变种,然后再通过引入并行性,使之转换成combine6的一个变种。

  48.二进制补码运算是可交换和可结合的,甚至于溢出时也是如此。

  49.浮点乘法和加法是不可结合的。

  50.按照严格顺序对元素求和不太可能会有比“分成两组独立求和,然后再将这两个和相加“根本上更好的准确性。

  51.循环并行性的好处是受描述计算的汇编代码的能力限制。

  52.在发生寄存器溢出之前,最大并行度为6.(整数数据类型)

  53.在现代处理器中,寄存器名字只简单地用来标识在功能单元之间传递的程序值。

  54.无论何时,当一个编译了的程序显示出在某个频繁使用的内循环中有寄存器溢出的迹象时,它都会倾向于重写代码,使之需要较少的临时值。通过减少局部变量的数量能够做到这一点。

  55.使用浮点数据时,我们希望将所有的局部变量都放在浮点寄存栈中。我们还需要保持栈顶可用于从存储器加载数据,这限制了并行度小于或等于7。

  56.对于整数求和和乘积以及浮点乘积,我们能够接近理论极限值。

  57.使用投机执行的处理器:会开始执行预测的分支目标处的指定为了避免修改任何实际的寄存器或存储器位置,直到确定了实际的结果。若预测是正确的,处理器便“提交”投机执行的指令的结果,把它们存储在寄存器或存储器中。如果预测是错误的,处理器必须丢弃掉所有执行的结果,有正确的位置重新开始取令的过程。这样做会引起很大的分支处罚,因为在产生有用的结果之前,必须重新填充指令流水线。

  58.在优化我们的合并过程中,处理器通常能够预测循环结尾的分支的方向。实际上,如果处理器总是预测会选择分支,那么除了最后一次的迭代以外,它都是对的。

  59.随机处理的一个原则是无论用什么策略来猜测值的序列,如果底层的处理是真正随机的,那么我们只可能有50%的时间是正确的。

  60.加载操作能利用流水线化,每个时钟周期开始新的加载操作,加载操作相对较长的执行时间对程序性能没有任何负面影响。

  61.与加载操作一样,在大多数情况下,存储操作能够在完全流水线化的模式中工作,每个周期开始一条新的存储。

  62.一系列存储操作一定是相互独立的,实际上,只有一条加载操作是受一条存储操作结果影响的,因为只有一条加载操作能从由存储操作写的那个存储器位置读回值。

  63.存储缓冲区(store fuffer)

  包含已经被发射到存储单元而又还没有完成存储操作的地址和数据,这里的完成包括更新数据高速缓存,有这样一个缓冲区,使一系列存储操作不必等待每个操作更新高速缓存就能够执行。当一条加载操作发生时,它必须检查存储缓冲区的条目,看有没有地址相匹配。如果有地址相匹配,它就取出相应的数据条目作为加载操作的结果。

  64.对于寄存器操作,在指令解码成操作时,处理器就可以确定哪些指令会影响另外哪些指令。另一方面,对于存储器(或内存)的操作,在加载和存储地址被计算出之前,处理器都不能预测到哪些指令会影响另外哪些指令,由于存储器操作占到了程序很大的一部分,存储器子系统被优化成以独立的存储器操作来提供更大的并行性。

  65.若存储和加载操作有不同的地址,可以不等待存储就进行加载;若存储和加载操作有相同地址,加载必须等待,直到它从存储获得结果了。

  66.优化程序性能的基本策略:

  1、高级设计:选择适当的算法和数据结构。

  2、基本编码原则:避免限制优化的因素。

  3、低级优化:尝试各种与数组代码相对的指针形式,通过展开循环降低循环开销,通过诸如迭代分割之类的技术找到使用流水线化的功能单元的方法。

  67.程序剖析:包括运行程序的这样一个版本,其中插入了工具代码,以确定程序的各个部分需要多长时间。

  68.Unix系统提供了一个剖析程序GPROF,这个程序产生两种形式的信息。首先,它确定程序中每个函数花费了多少CPU时间。其次,它计算每个函数被调用的次数,以调用函数来分类。

  69.GPROF有些属性值得注意:

  计时不是很准确、调用信息相当可靠、默认情况下不会显示对库函数的调用。

  70.时间(五类)

  Sort:按照频度对单词排序

  List:如果需要插入一个新的元素,为匹配单词扫描链表

  Lower:将字符串转换为小写字母

  Hash:计算哈希函数

  Rest:其他所有函数的和

  71.剖析能帮助我们对典型的情况进行优化,但是我们还应该确保对所有可能的情况进行优化,但是我们还应该确保对所有可能的情况,程序都有相当的性能。这主要包括避免得到糟糕的渐进功能(asymototic performance)的算法(例如插入算法)和坏的编程实践(例如Lower1)

  72.Amdhl定律:当我们加快系统一个部分的速度时,对系统整体性能的影响依赖于这个部分有多重要和速度提高了多少。

  主要观点——要想大幅度提高整个系统的速度,我们必须提高整个系统很大一部分的速度。

  主要问题:有些源代码看不懂,课后习题无法自己一人解答。

  下周计划:继续深入探究计算机的程序性能优化方面的知识;阅读书中所给的源代码,不知道的自己查明;争取独立完成书后练习,若不能独立完成也要在讨论之后理解其来龙去脉。

本文来源:http://www.guakaob.com/shiyongwendang/52218.html

    热门标签

    HOT