人在道路的分岔口时要预测哪条路能够到达目的地,面对众多选择时,计算机也一样要抉择,毕竟计算机的运行方式是以人的思路来设计的,计算机中的抉择其实就是人在抉择。

cpu中的指令是在流水线上执行。分支预测,是指当处理器遇到一个分支指令时,是该把分支左边的指令放到流水线上还是把分支右边的指令放在流水线上呢?

如C语言程序中的if、switch、for等语言结构,编译器将它们编译成汇编代码后,在汇编一级来说,这些结构都是用跳转指令来实现的,所以,汇编语言中的无条件跳转指令很丰富,以至于称之为跳转指令“族”,多的足矣应对各种转移方式。

举个例子,如下面测试代码

1 void main () {
2 int i = 0;
3 while (i < 10) {
4 i++;
5 }
6 }

里面的while结构,就是执行了10次i++。我们来看一下while结构是如何翻译成汇编语言的。

gcc -S -o ~/test/while.S ~/test/while.c回车,这样gcc就将while.c编译成了汇编代码while.S。其中的参数-S是编译到汇编语言,不进行汇编和链接。

查看下~/test /while.S文件,cat -n ~/test/while.S回车

 1       .file   "while.c"2        .text3  .globl main4        .type   main, @function5   main:6      pushl   %ebp7       movl    %esp, %ebp8     subl    $16, %esp9      movl    $0, -4(%ebp)
10      jmp .L2
11  .L3:                                ;此处是while的循环体
12      addl    $1, -4(%ebp)
13  .L2:                                ;此处是while循环条件表达式
14      cmpl    $9, -4(%ebp)
15      jle .L3
16      leave
17      ret
18      .size   main, .-main
19      .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
20      .section    .note.GNU-stack,"",@progbits

这个生成的汇编语言并不是我们熟悉的intel语法,而是AT&T语法,如果此时您觉得太陌生也不要慌张,因为在后面的章节我们会专门说到此类语法,现在先抛出来和大家预预热。

本来打算只列出第9~15行的,但考虑到本身才20行,干脆就全贴出来了,简要说明下,前4行是用于声明代码段、导出main函数符号。第5行是main函数起始地址,高级语言中的函数名在汇编语言中只是个符号,而符号便是地址,这就是很多教科书上都说函数名是地址的原因。话说数组也同理,数组名在汇编语言中也是个标号地址,所以数组名也是地址。局部变量是在栈中分配空间的,所以第6~8行是在创建堆栈框架,也就是为局部变量i在栈中分配空间,-4(%ebp)便是指局部变量i。堆栈框架以后会说到。咱们主要是看第9~15行。

第9行是为变量i赋值为0。AT&T语法中,寄存器前要用%来指示,立即数前要用$来指示。-4(%ebp)表示内存地址“ebp寄存器的值减4”处内存内容。相当于intel汇编语法形式[ebp – 4]。AT&T语法中是源操作数在左,目的操作数在右,和intel语法相反。所以第9行是将0送入了变量i所在的栈空间。

第10行就是简单的无条件跳转,直接进入while循环结构的条件表达式判断,也就是第13行。

第14行就是while括号中的条件表达式,用变量i的值和立即数9做比较。

第15行的jle意思是,若第14行的比较结果是小于等于9,则跳到11行,继续执行第12行的加法。可见第11~12行则是循环体。

程序执行流是由第15行跳到第11行,这样组成了循环结构的回路。

程序执行while循环后就结束了,所以局部变量i所在的栈空间要被回收,第16行的指令leave是用于堆栈框架的回收工作。

第17行是main函数退出。由于main也是被调用的,所以gcc显示的帮咱们加了个ret以示退出,为什么main也是由别人调用的,这个在加载用户程序时咱们会说到的。

上面的第15行jle指令就是程序中的分支结构。我们花了“大力气”讲述了程序流的分支,这并不是浪费力气。类似这样的分支结构很多,它们只有两种结果,要么转移到这一边,要么转移到那一边。分支结构虽然让程序更加灵活多样,但这却成了cpu执行效率的诟病。这是怎么回事呢?

之前说流水线的时候,我和大家强调了两次“重叠”,即同一时间周期内完成的是当前指令的执行,下一条指令的译码,第三条指令的取指。其中最重要的是“执行”,指令只有执行了,才真正是泼出去的水,收不回来了。另外的译码和取指并不重要,首先它们并不是执行,其次它们也不属于当前指令,当前指令的“取指”和“译码”早就在前两个周期内完成了。

不知道您注意到了没有,拿表4-14的周期3来说,这一时钟周期内的“执行”是指的当前指令的执行阶段,“取指”和“译码”这两个工序分别隶属于未来要执行的下一条指令和下下一条指令。想到这里不禁要有个疑问,这两个未来的指令,cpu是如何确定的?如果程序一直是顺序执行的,未来无论多少条指令都可以轻易得到,都可以提前放到流水线上。可是,程序是有分支啊,到底该把哪个分支的指令放到流水线上呢?

流水线是有效提升cpu效率的方式,但流水线最大的问题是程序中的分支结构,如何把握好转移的方向,才是使流水线保持高效的关键,因为如果流水线上的指令放错了的话,必须要清空那些已经在流水线上的指令,一定不能执行错误的指令。随着流水线级数越多,要清空的指令也将越多,清空流水线的代价就越大,这严重影响cpu效率。

当遇到一个分岔口时,是往左走还是往右走呢?对于这种分支情况,就需要预测出哪一侧的指令将被执行,然后将预测出的那一分支上的指令放入流水线。从统计学的角度来看,某些事情一旦出现,下一次出现的机率还会很大。纵观历史,很多事情都是在重复的发生,很多伟人都拿这些历史样本来预测未来发生的事情。这个说的有点悬乎了,说点简单的,比如现在是葡萄收获的季节,今天刚吃了葡萄,很好吃,明天后天甚至未来的几周都会继续吃葡萄,哈哈,我大爱葡萄。

本内容摘自《操作系统真象还原》,作者不容易,请大家支持正版。

一步步编写操作系统 30 cpu的分支预测简介相关推荐

  1. 一步步编写操作系统 31 cpu的分支预测 下

    让我们说说预测的算法吧. 对于无条件跳转,没啥可犹豫的,直接跳过去就是了.所谓的预测是针对有条件跳转来说的,因为不知道条件成不成立.最简单的统计是根据上一次跳转的结果来预测本次,如果上一次跳转啦,这一 ...

  2. 一步步编写操作系统 29 cpu缓存简介

    缓存是20世纪最大的发明,其原理用一些存取速度较快的存储设备做为数据缓冲区,避免频繁访问速度较慢的低速存储设备,归根结底的原因是,低速存储设备是整个系统的瓶颈,缓存用来缓解"瓶颈设备&quo ...

  3. 一步步编写操作系统 25 cpu的保护模式

    在保护模式下,我们将见到很多在实模式下没有的新概念,很多都是cpu硬件原生提供,并且要求的东西,也就是说按照cpu的设计,必须有这些东西cpu才能运行.咱们只要了解它们是什么并且怎么用就行了,不用深入 ...

  4. 一步步编写操作系统 60 cpu的IO特权级2 什么是驱动程序

    用户程序可以在由操作系统加载时通过指定整个eflags设置,操作系统如何设置自己的IOPL呢,即使内核IOPL为0也得写进去eflags寄存器中才生效.可惜的是,没有直接读写eflags寄存器的指令, ...

  5. 一步步编写操作系统 59 cpu的IO特权级1

    在保护模式下,处理器中的"阶级"不仅体现在数据和代码的访问,还体现在指令中. 一方面将指令分级的原因是,有些指令的执行对计算机有着严重的影响,它们只有在0特权级下被执行,因此被称为 ...

  6. 一步步编写操作系统 28 cpu乱序执行

    乱序执行(乱序执行译作异步执行更贴切),是指在cpu中运行的指令并不按照代码中的顺序执行,而是按照一定的策略打乱顺序执行,也许后面的指令先执行,当然,得保证指令之间不具备相关性. 举个简单的例子,比如 ...

  7. 一步步编写操作系统 15 CPU与外设通信——IO接口,下

    既然都说到IO接口了,不知道各位有没有疑问,cpu是怎样访问到IO接口呢?肯定得有个链路吧?什么?有隐约听到有同学开玩笑说:cpu用无线访问其它设备.哈哈,不知道各位听说过没有,无线的终端是有线.无论 ...

  8. 一步步编写操作系统 14 CPU与外设通信——IO接口 上

    介绍显卡之前,必须得和大家交待清楚,那么多的外部设备,cpu是如何与他们交流. 大家都学过微机接口技术吧?没学过也没关系,反正我也只是笼统地说说^_^,保证大家一定能看得懂. 按理说,如果硬件种类较少 ...

  9. 一步步编写操作系统 10 cpu的实模式

    cpu的实模式 由于mbr在实模式下工作--什么?什么是实模式?这时候有同学打断了我.我心想,这下好办了--哈哈,没有啦,开个玩笑而已.我们这里所说的实模式其实就是8086 cpu的工作环境.工作方式 ...

最新文章

  1. SSL证书可以给多个域名使用吗?
  2. 在Centos 7下编译openwrt+njit-client
  3. SQLServer查询指定日期
  4. IDEA一直提示 错误: 找不到或无法加载主类
  5. 数据分析与挖掘 - R语言:贝叶斯分类算法(案例三)
  6. CRM软件设计评测点与采集测评点
  7. js中return、return false 、return true各自代表什么含义
  8. 【感悟】本书书名无法描述本书内容(二)
  9. 程序员是否应该创造面向 IDE 而非人类的编程语言?
  10. 视频教程-带你入门matlab小波分析-Matlab
  11. js之dialogArguments
  12. 卷积神经网络之前向传播算法
  13. 注意!吃蔬菜也有误区
  14. DDN周报|3月26日-4月1日
  15. 角谷定理python输出变化过程_角谷定理。
  16. PCSX2模拟《铁拳5》相关设置
  17. OSG入门即osgEarth建立一个地球的详细步骤
  18. 三十、元素的显示与隐藏
  19. Lua点号和冒号区别
  20. 简信CRM:电销系统是什么,企业为什么需要?

热门文章

  1. MySQL系统自带的数据库information schema
  2. InnerClass内部类
  3. 人物角色群体攻击判定(一)
  4. emctl start dbconsole OC4J_dbconsole*** not found
  5. Ubuntu apache 禁止目录浏览
  6. vs2005新建类,自定义模板信息(转载)
  7. xfire客户端对返回list很挑剔,所以需要使用泛型。
  8. leetcode之回溯backtracing专题3
  9. [Leetcode][第20题][JAVA][有效的括号][栈][HashMap]
  10. 枚举命名规范_UE4 C++基础教程 - 编码规范