Overview

这一章的主题是如何让程序运行的更快,这里的程序的算法已经确定,并且程序能够正确运行。

Generally Useful Optimizations

可以将重复计算的东西移到循环外面,避免重复的计算

Reduction in Strength

  • 用简单的操作降低花费大的操作
  • shift add代替乘除法

Share Common Subexpressions

相同的表达式可以降低重复使用

Optimization Blocker #1: Procedure Calls 过程调用

上面代码实际上很难看出问题,但是实际上这样的代码时间复杂度为O(n^2) 因为每个loop中我们都调用了strlen(s)函数!该函数是线性的函数。

提升效率的方法如下:

即将strnlen(s)函数移出循环

Memory Matters

下面再看一个糟糕的代码例子,我们要在内存和寄存器中来回移动数据

代码每次迭代都会更新b[i]的值,这样我们就把一个值从内存中拿出来,再放到另一个内存中去。

Memory Aliasing

当程序中的不同部分指向内存中的同一位置,称为别名。并且C编译器无法知道是否存在别名。

因此局部变量可以告诉编译器不要重复调用函数,不用重复在内存和寄存器中来回移动数据,只需要暂时存储在某个地方。

这样编译器会自动分配一个寄存器,并且把东西放在寄存器中

Removing Aliasing

如上面的代码,我们将a[i*n+j]的代码暂时保存在val中,然后循环外直接赋予b[i]。

这里,对内存的读写实际上会限制程序的性能,因此改写之后不会明显加快。

因此要习惯例子中引入局部变量的写法,这样可以告诉编译器不要一遍又一遍的调用相同的函数,不要一遍又一遍的读取和写入相同的内存位置,只需要将其保存在临时位置就好,然后编译器会自动分配一个寄存器并将结果放在寄存器中,一切都会很棒。

and后面讲了很多处理器级别的优化,听的有点懵。。

Benchmark Example: Data Type for Vectors

定义一个数据结构,这看起来像pascal实现的方式,在一种语言中实现数组的典型方式是,使用一个数据结构不仅保存数组中的值,还保存与之相关的其他信息,例如他的大小,所以这是一种很好的抽象方式,你编写的代码可以确保,如果你对数组的访问越界了,那么你会得到一个错误的信息。

下面看到的函数的功能是,从数组中取出索引值对应的元素,传递一个指针,然后该指针被赋值为数组中索引对应的元素。

此函数的返回值为0或10表示失败,1表示成功。将元素的数据类型定义为 data_t,这样可以修改data_t的定义,然后重新编译,

data_t可以定义为 int, long,float,和double,我们将会看到性能特征如何随着不同的数据类型而变化。

Benchmark Computation

使用的基准测试非常简单,对于这个数组,计算数组中所有元素的总和,上面使用了两个宏定义IDENT和OP,OP定义为加法,且IDENT定义为0。或者OP定义为乘法, 且IDENT定义为1。所以我们有八种不同的组合

Cycles Per Element (CPE)

cpe代表了处理一个元素所花的时间周期,用cpe这个指标的原因是通常当你编写代码遍历处理一个数组的时候,你并不关心对一个元素的处理需要多少秒或者多少微秒或者多少纳秒,你想知道它的整体的性能特征是什么。进行低级代码优化的时候也是这样,使用处理器内部时钟的时钟周期作为时间单位更有用,而不是以纳秒这样的单位。因为一个处理器是以2Ghz还是以2.3Ghz运行,程序员是无法控制的,但是程序员可以控制程序中不同的计算部分使用了多少个时钟周期

只改变编译器的优化选项,可以将每个元素降低到10个时钟周期。然后进行一些优化,减少程序中的冗余

前面看到,每次调用get_vec_element函数,该函数都会检查数组索引是否越界,一遍又一遍的检查数组越界是一种很愚蠢的行为

因此当遍历的时候,先得到它的长度来确定要访问的元素数量,放弃函数的边界检查,可以引入一个函数,返回数组的长度,数组长度以外的东西直接忽略,所以重新写一个循环,引入局部变量,先把数据累加到临时变量,然后再赋值给dest,这样程序就实际上变得更快了,优化如下。

Basic Optimizations

Effect of Basic Optimizations

它把整数的加法降低到了一个多时间周期,整数乘法降低到3个时钟周期,双精度乘法降低到了5个时钟周期。

Modern CPU Design

实际上现代的CPU设计是非常困难的。CPU提供庞大的硬件基础设施,使程序运行速度比一次执行一条指令快,采用了一种被称为超标量乱序执行的技术,这个想法粗略的讲,可以认为你的程序是一个顺序执行的指令序列,CPU尽可能读取多的指令序列,然后CPU把读入的指令拆开,发现有的指令之间不是相互依赖的,所以我可以开始执行程序后面的代码而不是当前的代码,因为他们彼此独立,这也被称为指令级并行性(instruction level parallelism),也就是即使你的程序是一个顺序的指令序列,但实际上,这些代码可以拆分成不同的部分,某些部分相互依赖,某些部分独立。

上图的上半部分显示了获取指令的方法。

Pipelined Functional Units

乱序执行比较复杂,但是功能单元比你想的可能更加复杂,功能单元使用了流水线技术(woc这就是我现在上computer architecture迷糊的地方)

流水线的基本思想是将计算分解为一系列不同的阶段。

一个简单的例子是你要计算 a*b+c的值,你先做乘法,然后做加法,但是乘法器做乘法比人要麻烦,乘法器会将乘法分解为一个接一个完成的步骤,可以认为每个阶段都有单独的专用硬件,然后可以做流水线操作。也就是,当一个操作从一个阶段移动到下一个阶段的时候,前一个阶段空出来了,你可以填入新的数据。

PPT上的例子,乘法器分为三个阶段,计算a*b和a*c,然后把两个积相乘,要注意的是a*b和a*c不以任何方式产生依赖,所以我们可以同时计算他们两个的乘积,但是我们没有两个乘法器,所以可以分段做。

由于流水线的操作,上面的操作只需要7个时钟周期,即使每个乘法操作都需要3个cycle。

Haswell CPU

指令有两个参数,延迟(latency)是一个指令从头到尾需要多长的时间,但由于有流水线操作,还有一个参数(cycles/issue)表示两个小步骤之间的距离。

注意除法是非常慢的,并且没有流水线技术,相对而言在大部分的机器上,除法都是一项比较昂贵的操作

所以有人在弹幕里提到:在开源库里,除数不变的批量除法运算都会换成乘除数的倒数

Combine4 = Serial Computation (OP = *)

如果我们把程序的计算顺序画成上图中的样子,程序进行一系列的乘法运算,并在开始下一个之前,需要上一个的计算结果,这样我们即便有一个流水线乘法器,程序本身限制了所有的乘法必须按照顺序执行。

所以让我们看看我们能否超越那个延迟界限(latency bound)

Loop Unrolling (2x1)

这里采用了一种技术,叫做循环展开,基本思想是:在循环中计算一个多值,而不是一个值。上图中展示了2*1的循环展开,也就是说每次循环处理数组的两个元素。

这样的处理我们会发现速度没有很快的提升,只有加法稍微快了一点点。因为这样的改动我们实际上还是需要顺序依赖。

Loop Unrolling with Reassociation (2x1a)

但是下图中 将括号的位置改变了,速度快了很多

Effect of Reassociation

Reassociated Computation

改动后的代码的关键路径变为了原来的一半,因此所用的时间减少了一半。

对于整形数据的加法和乘法进行这种转换没有问题,但是我们知道不能用于浮点数,不满足结合律,可能会出现舍入、溢出的情况。

现在有一套新的界限,这个界限是你程序能够达到了最好的性能,延迟界限是指在一系列操作必须严格顺序执行时,执行一条指令所要花费的全部时间,但是其实还有一个更基本的界限,称为吞吐量限制,这个限制是基于硬件的数量和性能,基于功能单元的基本计算能力。

CMU 15-213 Introduction to Computer Systems学习笔记(9) Program Optimization相关推荐

  1. Introduction to Computer Networking学习笔记(十五):Queue Model 包交换中的缓冲模型

    本章知识点比较零散,因此一篇文章进行总结,并且不具有连贯性,仅记录自己认为有价值的内容. 将较大的包拆分为小包进行传输,可以减小端对端延迟,原因如下图: 数据传输时,突发大量的数据包会增加延迟,简单周 ...

  2. CS269I:Incentives in Computer Science 学习笔记 Lecture 13:Introduction to Auctions(拍卖简介)

    Lecture 13 Introduction to Auctions(拍卖简介) 1 Preamble(前言) 为什么计算机科学家要关心拍卖?直到最近(甚至可能仍然),提到拍卖,我们脑海中联想到的图 ...

  3. CS269I:Incentives in Computer Science 学习笔记 Lecture 15 The VCG Mechanism(VCG机制)

    Lecture 15 The VCG Mechanism(VCG机制) 1 GSP vs VCG 作为本讲的开始,我们来证明上一讲中的一个重要结论: 回忆一下背景:有k个广告位,它们 的点击率排布为) ...

  4. CS269I:Incentives in Computer Science 学习笔记 Lecture 12 对称信息和声誉系统

    Lecture 12 Asymmetric Information and Reputation Systems(对称信息和声誉系统) 1 Preamble(前言) 之前的几讲,我们都在声誉系统的边缘 ...

  5. Coursera 机器学习 第9章(下) Recommender Systems 学习笔记

    9.5 Predicting Movie Ratings 9.5.1 Problem Formulation 推荐系统. 推荐系统的问题表述:电影推荐.根据用户对已看过电影的打分来推测用户对其未打分的 ...

  6. CS269I:Incentives in Computer Science 学习笔记 Lecture 17 评分规则和同辈预测(诚实预报和反馈激励)

    Lecture 17 Scoring Rules and Peer Prediction(Incentivizing Honest Forecasts and Feedback)(评分规则和同辈预测( ...

  7. POSEIDON: A New Hash Function for Zero-Knowledge Proof Systems 学习笔记

    1. 引言 Grassi等人2019年论文<POSEIDON: A New Hash Function for Zero-Knowledge Proof Systems>. 前序博客有: ...

  8. 概率导论(Introduction to Probability, 2E)学习笔记 Part Ⅰ

    笔记内容基于Introduction to Probablity, Second Edition 因笔者为初学者,故内容不会面面俱到 若有表述错误还望直接指出 --2022.1 样本空间与概率 本书的 ...

  9. Introduction to Materials Management 学习笔记--生产计划系统

    概述本章介绍了MPC(Manufacturing planning and control)系统.首先从总体上介绍一下,然后讲了生产计划的编制的一些细节(英文就是省事加个ing就能说明很多问题,本章在 ...

  10. Introduction to Materials Management 学习笔记

    搞了两三年AX,越来越困惑. 技术层面可以通过多读代码去解决大多数问题,毕竟AX里的那么多源代码是可以模仿的,加上AX本身是个很不错的开发平台,技术方面可能不需要太多时间就差不多可以应付了. 做AX最 ...

最新文章

  1. 安波副教授:分布式人工智能进展与趋势
  2. 电脑台式计算机描述不可用,win7系统计算机描述不可用的解决方法
  3. JAVA实例,判断是否是瑞年
  4. 5行Python就能爬取 3000+ 上市公司的信息?
  5. 如何快速把音乐转成MP3格式
  6. 【熊猫多模式站群开发日志】流程总览
  7. 渗透测试入门21之Metasploit渗透测试常用流程
  8. Android多线程之IntentService源码解析
  9. 重磅福利!程序员面试——算法工程师面试大全第五部分
  10. 阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_11_常用的函数式接口_Consumer接口练习...
  11. PHP爬虫常用技术:v8js(执行js代码)
  12. 【活动报名】1024,一起过节,一起品网易/美团/贝壳/PingCAP/爱奇艺云原生实践干货!
  13. html5 cuplayer,PlayerLite免费flv与mp4网页视频播放器
  14. 我的ubuntu论坛账号
  15. Addon SuperEdge 让原生 K8s 集群可管理边缘应用和节点
  16. leetcode/求平方根
  17. 深入理解7种垃圾收集器
  18. N46期第十二周作业
  19. 土地测量 造成高房价的原因有许多,比如土地出让价格。既然地价高,土地的面积必须仔细计算。 遗憾的是,有些地块的形状不规则,比如是如图【1.jpg】中所示的五边形。
  20. 关于“​​​​​​\u200B“非法字符(不可见字符)的 ‘坑’

热门文章

  1. 在线旅游网站发展趋势分析
  2. 自定义View在android2.3.3手机上正常运行 在android4.2.2手机上报空指针
  3. 设计模式 (二十一) 策略模式
  4. MyCat分片规则之枚举分片
  5. anaconda的使用
  6. 20172304 2017-2018-2 《程序设计与数据结构》第五周学习总结
  7. mysql 主从故障恢复
  8. Jni 返回jstring字符串
  9. 5.4 continue,break跳出循环
  10. 【用jersey构建REST服务】系列文章