【操作系统】CPU是如何执行程序的?_cpu怎么知道到哪里执行函数-程序员宅基地

技术标签: java  网络  操作系统  

一、程序执行的基本过程

程序实际上是⼀条⼀条指令,所以程序的运⾏过程就是把每⼀条指令⼀步⼀步的执⾏起来,负责执⾏指令的就是 CPU 了。

在这里插入图片描述

CPU 执行程序的过程如下 :

  • CPU 读取「程序计数器」的值,这个值是指令的内存地址,然后 CPU 的「控制单元」操作「地址总线」指定需要访问的内存地址,接着通知内存设备准备数据,数据准备好后通过「数据总线」将指令数据传给 CPU,CPU 收到内存传来的数据后,将这个指令数据存⼊到「指令寄存器」。
  • CPU 分析「指令寄存器」中的指令,确定指令的类型和参数,如果是计算类型的指令,就把指令交给「逻辑运算单元」运算;如果是存储类型的指令,则交由「控制单元」执⾏;
  • CPU 执⾏完指令后,「程序计数器」的值⾃增,表示指向下⼀条指令。这个⾃增的⼤小,由CPU 的位宽决定,⽐如 32 位的 CPU,指令是 4 个字节,需要 4 个内存地址存放,因此「程序计数器」的值会⾃增 4;

简单总结⼀下就是,⼀个程序执⾏的时候,CPU 会根据程序计数器⾥的内存地址,从内存⾥⾯把需要执⾏的指令读取到指令寄存器⾥⾯执⾏,然后根据指令⻓度⾃增,开始顺序读取下⼀条指令。

CPU 从程序计数器读取指令、到执⾏、再到下⼀条指令,这个过程会不断循环,直到程序执⾏结束,这个不断循环的过程被称为 CPU 的指令周期。

二、a = 1 + 2 执行具体过程

CPU 是不认识 a = 1 + 2 这个字符串的,这些字符串只是⽅便我们程序员认识,要想这段程序能跑起来,还需要把整个程序翻译成汇编语⾔的程序,这个过程称为编译成汇编代码。

针对汇编代码,我们还需要⽤汇编器翻译成机器码,这些机器码由 0 和 1 组成的机器语⾔,这⼀条条机器码,就是⼀条条的计算机指令,这个才是 CPU 能够真正认识的东⻄。

以32位CPU中 a=1+2 执行过程为例:

程序编译过程中,编译器通过分析代码,发现 1 和 2 是数据,于是程序运⾏时,内存会有个专⻔的区域来存放这些数据,这个区域就是「数据段」。如下图,数据 1 和 2 的区域位置:

  • 数据 1 被存放到 0x100 位置;
  • 数据 2 被存放到 0x104 位置;

在这里插入图片描述

编译器会把 a = 1 + 2 翻译成 4 条指令,存放到正⽂段中。如图,这 4 条指令被存放到了 0x200 ~ 0x20c的区域中:

  • 0x200 的内容是 load 指令将 0x100 地址中的数据 1 装⼊到寄存器 R0 ;
  • 0x204 的内容是 load 指令将 0x104 地址中的数据 2 装⼊到寄存器 R1 ;
  • 0x208 的内容是 add 指令将寄存器 R0 和 R1 的数据相加,并把结果存放到寄存器 R2 ;
  • 0x20c 的内容是 store 指令将寄存器 R2 中的数据存回数据段中的 0x108 地址中,这个地址也就
    是变量 a 内存中的地址;

编译完成后,执⾏程序的时候,程序计数器会被设置为 0x200 地址,然后依次执⾏这 4 条指令。

由于是在 32 位 CPU 执⾏的,因此⼀条指令是占 32 位⼤⼩,所以每条指令间隔4 个字节。

而数据的大小是根据程序中指定的变量类型,⽐如 int 类型的数据则占 4 个字节, char 类型的数据则占 1 个字节。

1、指令

上⾯的例⼦中,图中指令的内容是简易的汇编代码,⽬的是为了⽅便理解指令的具体内容,事实上指令的内容是⼀串⼆进制数字的机器码,每条指令都有对应的机器码,CPU 通过解析机器码来知道指令的内容。
不同的 CPU 有不同的指令集,也就是对应着不同的汇编语⾔和不同的机器码,接下来选⽤最简单的 MIPS指集,来看看机器码是如何⽣成的,这样也能明⽩⼆进制的机器码的具体含义。MIPS 的指令是⼀个 32 位的整数,⾼ 6 位代表着操作码,表示这条指令是⼀条什么样的指令,剩下的 26位不同指令类型所表示的内容也就不相同,主要有三种类型R、I 和 J。

在这里插入图片描述

这三种类型指令的含义:

  • R 指令,⽤在算术和逻辑操作,⾥⾯由读取和写⼊数据的寄存器地址。如果是逻辑位移操作,后⾯还有位移操作的「位移量」,⽽最后的「功能码」则是再前⾯的操作码不够的时候,扩展操作码来表示对应的具体指令的;
  • I 指令,⽤在数据传输、条件分⽀等。这个类型的指令,就没有了位移量和操作码,也没有了第三个寄存器,⽽是把这三部分直接合并成了⼀个地址值或⼀个常数;
  • J 指令,⽤在跳转,⾼ 6 位之外的 26 位都是⼀个跳转后的地址;

接下来,我们把前⾯例⼦的这条指令:「 add 指令将寄存器 R0 和 R1 的数据相加,并把结果放⼊到
R2 」,翻译成机器码。

在这里插入图片描述

加和运算 add 指令是属于 R 指令类型:

  • add 对应的 MIPS 指令⾥操作码是 000000 ,以及最末尾的功能码是 100000 ,这些数值都是固定的,查⼀下 MIPS 指令集的⼿册就能知道的;
  • rs 代表第⼀个寄存器 R0 的编号,即 00000 ;
  • rt 代表第⼆个寄存器 R1 的编号,即 00001 ;
  • rd 代表⽬标的临时寄存器 R2 的编号,即 00010 ;
  • 因为不是位移操作,所以位移量是 00000

把上⾯这些数字拼在⼀起就是⼀条 32 位的 MIPS 加法指令了,那么⽤ 16 进制表示的机器码则是
0x00011020 。

编译器在编译程序的时候,会构造指令,这个过程叫做指令的编码。

CPU 执⾏程序的时候,就会解析指令,这个过程叫作指令的解码。

现代⼤多数 CPU 都使⽤来流⽔线的⽅式来执⾏指令,所谓的流⽔线就是把⼀个任务拆分成多个⼩任务,于是⼀条指令通常分为 4 个阶段,称为 4 级流⽔线,如下图:

在这里插入图片描述

四个阶段的具体含义:

  • CPU 通过程序计数器读取对应内存地址的指令,这个部分称为 Fetch(取得指令);
  • CPU 对指令进⾏解码,这个部分称为 Decode(指令译码);
  • CPU 执⾏指令,这个部分称为 Execution(执⾏指令);
  • CPU 将计算结果存回寄存器或者将寄存器的值存⼊内存,这个部分称为 Store(数据回写);

上⾯这 4 个阶段,我们称为指令周期(Instrution Cycle),CPU 的⼯作就是⼀个周期接着⼀个周期,周⽽复始。事实上,不同的阶段其实是由计算机中的不同组件完成的:

在这里插入图片描述

  • 取指令的阶段,我们的指令是存放在存储器⾥的,实际上,通过程序计数器和指令寄存器取出指令的过程,是由控制器操作的;
  • 指令的译码过程,也是由控制器进⾏的;
  • 指令执⾏的过程,⽆论是进⾏算术操作、逻辑操作,还是进⾏数据传输、条件分⽀操作,都是由算术逻辑单元操作的,也就是由运算器处理的。但是如果是⼀个简单的⽆条件地址跳转,则是直接在控制器⾥⾯完成的,不需要⽤到运算器。

2、指令的类型

从功能⻆度划分,可以分为 5 ⼤类:

  • 数据传输类型的指令,⽐如 store/load 是寄存器与内存间数据传输的指令, mov 是将⼀个内存地址的数据移动到另⼀个内存地址的指令;
  • 运算类型的指令,⽐如加减乘除、位运算、⽐较⼤⼩等等,它们最多只能处理两个寄存器中的数据;
  • 跳转类型的指令,通过修改程序计数器的值来达到跳转执⾏指令的过程,⽐如编程中常⻅的 ifelse 、 swtich-case 、函数调⽤等。
  • 信号类型的指令,⽐如发⽣中断的指令 trap ;
  • 闲置类型的指令,⽐如指令 nop ,执⾏后 CPU 会空转⼀个周期;

3、指令的执行速度

CPU 的硬件参数都会有 GHz 这个参数,⽐如⼀个 1 GHz 的 CPU,指的是时钟频率是 1 G,代表着 1 秒会产⽣ 1G 次数的脉冲信号,每⼀次脉冲信号⾼低电平的转换就是⼀个周期,称为时钟周期。
对于 CPU 来说,在⼀个时钟周期内,CPU 仅能完成⼀个最基本的动作,时钟频率越⾼,时钟周期就越短,⼯作速度也就越快。
⼀个时钟周期⼀定能执⾏完⼀条指令吗?答案是不⼀定的,⼤多数指令不能在⼀个时钟周期完成,通常需要若⼲个时钟周期。不同的指令需要的时钟周期是不同的,加法和乘法都对应着⼀条 CPU 指令,但是乘法需要的时钟周期就要⽐加法多。

4、如何让程序跑的更快?

对于 CPU 时钟周期数我们可以进⼀步拆解成:「指令数 x 每条指令的平均时钟周期数(Cycles Per
Instruction,简称 CPI )」,于是程序的 CPU 执⾏时间的公式可变成如下:

在这里插入图片描述

因此,要想程序跑的更快,优化这三者即可:

  • 指令数,表示执⾏程序所需要多少条指令,以及哪些指令。这个层⾯是基本靠编译器来优化,毕竟同样的代码,在不同的编译器,编译出来的计算机指令会有各种不同的表示⽅式。
  • 每条指令的平均时钟周期数 CPI,表示⼀条指令需要多少个时钟周期数,现代⼤多数 CPU 通过流⽔线技术(Pipline),让⼀条指令需要的 CPU 时钟周期数尽可能的少;
  • 时钟周期时间,表示计算机主频,取决于计算机硬件。有的 CPU ⽀持超频技术,打开了超频意味着把 CPU 内部的时钟给调快了,于是 CPU ⼯作速度就变快了,但是也是有代价的,CPU 跑的越快,散热的压⼒就会越⼤,CPU 会很容易奔溃。

整理自小林coding所著的《图解网络》,仅做学习用,侵删

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/flyersboy/article/details/117405972

智能推荐

python编码问题之encode、decode、codecs模块_python中encode在什么模块-程序员宅基地

文章浏览阅读2.1k次。原文链接先说说编解码问题编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 Eg:str1.decode('gb2312') #将gb2312编码的字符串转换成unicode编码str2.encode('gb2312') #将unicode编码..._python中encode在什么模块

Java数据流-程序员宅基地

文章浏览阅读949次,点赞21次,收藏15次。本文介绍了Java中的数据输入流(DataInputStream)和数据输出流(DataOutputStream)的使用方法。

ie浏览器无法兼容的问题汇总_ie 浏览器 newdate-程序员宅基地

文章浏览阅读111次。ie无法兼容_ie 浏览器 newdate

想用K8s,还得先会Docker吗?其实完全没必要-程序员宅基地

文章浏览阅读239次。这篇文章把 Docker 和 K8s 的关系给大家做了一个解答,希望还在迟疑自己现有的知识储备能不能直接学 K8s 的,赶紧行动起来,K8s 是典型的入门有点难,后面越用越香。

ADI中文手册获取方法_adi 如何查看数据手册-程序员宅基地

文章浏览阅读561次。ADI中文手册获取方法_adi 如何查看数据手册

React 分页-程序员宅基地

文章浏览阅读1k次,点赞4次,收藏3次。React 获取接口数据实现分页效果以拼多多接口为例实现思路加载前 加载动画加载后 判断有内容的时候 无内容的时候用到的知识点1、动画效果(用在加载前,加载之后就隐藏或关闭,用开关效果即可)2、axios请求3、map渲染页面4、分页插件(antd)代码实现import React, { Component } from 'react';//引入axiosimport axios from 'axios';//引入antd插件import { Pagination }_react 分页

随便推点

关于使用CryPtopp库进行RSA签名与验签的一些说明_cryptopp 签名-程序员宅基地

文章浏览阅读449次,点赞9次,收藏7次。这个变量与验签过程中的SignatureVerificationFilter::PUT_MESSAGE这个宏是对应的,SignatureVerificationFilter::PUT_MESSAGE,如果在签名过程中putMessage设置为true,则在验签过程中需要添加SignatureVerificationFilter::PUT_MESSAGE。项目中使用到了CryPtopp库进行RSA签名与验签,但是在使用过程中反复提示无效的数字签名。否则就会出现文章开头出现的数字签名无效。_cryptopp 签名

新闻稿的写作格式_新闻稿时间应该放在什么位置-程序员宅基地

文章浏览阅读848次。新闻稿是新闻从业者经常使用的一种文体,它的格式与内容都有着一定的规范。本文将从新闻稿的格式和范文两个方面进行介绍,以帮助读者更好地了解新闻稿的写作_新闻稿时间应该放在什么位置

Java中的转换器设计模式_java转换器模式-程序员宅基地

文章浏览阅读1.7k次。Java中的转换器设计模式 在这篇文章中,我们将讨论 Java / J2EE项目中最常用的 Converter Design Pattern。由于Java8 功能不仅提供了相应类型之间的通用双向转换方式,而且还提供了转换相同类型对象集合的常用方法,从而将样板代码减少到绝对最小值。我们使用Java8 功能编写了..._java转换器模式

应用k8s入门-程序员宅基地

文章浏览阅读150次。1,kubectl run创建pods[root@master ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1[root@master ~]# kubectl get podsNAME READY STATUS REST...

PAT菜鸡进化史_乙级_1003_1003 pat乙级 最优-程序员宅基地

文章浏览阅读128次。PAT菜鸡进化史_乙级_1003“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。得到“答案正确”的条件是: 1. 字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符; 2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或..._1003 pat乙级 最优

CH340与Android串口通信_340串口小板 安卓给安卓发指令-程序员宅基地

文章浏览阅读5.6k次。CH340与Android串口通信为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio移植的具体步骤CH340串口通信驱动函数通信过程中重难点还存在的问题为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio为了在这个工程基础上进行改动,验证串口的数据和配置串口的参数,我首先在Eclipse上配置了安卓开发环境,注意在配置环境是..._340串口小板 安卓给安卓发指令