图灵机主要由数据存储单元,控制单元,运算单元和一个可读写外部数据的读写头几部分构成。
图灵机工作需要有一条纸带,纸带上面布满格子,可以在格子上面记录字符,字符可分为数据字符和指令字符;纸带穿过图灵机并不断向前移动;图灵机上的读写头依次读取纸带格子上的字符,根据控制单元区分读取的字符属于数据还是指令,当读到数据字符时,将字符存储到存储单元中,当读到指令字符时,运算单元会将存储单元中的数据读取出来并进行相应运算,并将结果通过读写头写入纸带的下一个格子中。
图灵机的基本工作模式跟如今的计算机是一样的,数据和指令存在存储器中(纸带和存储单元),处理器读取后运算得出结果。计算机中使用cpu进行指令计算,存放数据的存储器我们常听的有磁盘、SSD、内存。但cpu并不直接从这些存储器中读取并执行指令,而是采用分级缓存策略。
为什么需要分级
我们比较熟悉的磁盘,数据在断电之后还能保存着,而且磁盘的存储空间较大,通常能有上T容量,但其数据读取速度极慢;内存的读取速度虽然比磁盘快了将近100倍,但跟cpu的执行速度相比,还是属于”龟速“。此外,内存是安装在主板上的,数据通过电路板传输到cpu上,数据传输的耗时相对于cpu执行速度来说也是不可忽视的。
存储器体积越小,其存储容量就会受到限制;读写速度越快,能耗和成本也会越高;其次,存储器距离cpu越远,数据传输也越慢。所以,目前而言,使用单一存储器无法让存储器中的数据跟的上cpu的处理速度。
计算机采用的方案是将存储器分级,将cpu使用频率越高的数据,存放在读写速度越快,距离cpu更近的存储器(缓存)中;将使用频率较低的数据存放在读写速度较慢,距离cpu较远,但存储容量较大,成本较低的存储器中。这样,cpu读取数据时,直接先从缓存中读取,缓存中不存在再从距离更远的存储器中读取。
分级缓存方案的可行性在于计算机存在局部性原理,试想下我们平时写的代码程序,运算用的最多的是for循环,然后对定义的几个变量进行计算读写。所以,cpu执行一个程序的时候,有几个数据区域的读写频率是比较高的。所以,可以将这些「热点」区域的数据缓存起来,下次读取的时候就会快很多。据统计,存储器缓存命中率能达到95%,也就是只有5%的数据会穿透到内存。
存储器分级策略
通常,存储器分成以下几个级别:
磁盘/SSD
SSD/磁盘是距离CPU最远,读取速度最慢的一类存储器,优点在于成本较低,断电后数据还在。其中SSD是我们常说的固态硬盘,结构与内存类似,读写速度比内存慢10-1000倍;磁盘读取速度更慢,比内存慢100W倍左右,随着SSD的普及,已经慢慢被取代了。
内存
内存是插在主板上,与CPU有一段距离,CPU通过主板总线读取内存中的数据,造价比磁盘稍贵,但读取速度比磁盘快,速度大概在200-300个CPU周期;容量方面,个人电脑的内存一般是8-16G,服务器上的内存可以达到几个T。
CPU周期:一条指令可分为取指令,执行指令等若干个阶段,每个阶段完成所需的时间成为CPU周期。
CPU cache(CPU 高速缓存)
CPU cache存在于CPU内部,CPU cache可分为L1(一级缓存)、L2(二级缓存)、L3(三级缓存),CPU的每个核都有各自的L1和L2缓存,同一个CPU的多个核共享一个L3缓存。
与CPU距离:L1 < L2 < L3
容量: L1(几十~几百KB)< L2(几百KB~几MB) < L3(几MB~几十MB)
读写速度: L1(2-4CPU周期) > L2(10-20CPU周期) > L3(20-60CPU周期)
(L1缓存划分了指令区和数据区,下文会解释)
需要注意的是,cpu缓存中每个缓存的最小单位是内存的一个内存块,而不是缓存一个变量;cpu缓存和内存的映射方式有很多种,类似于 cache 行号 = 内存页号 mod cache 总行数;这样,先根据内存地址计算出地址所在内存页号,再通过映射关系算出cache行号,如果存在缓存中,直接获取数据即可,如果不存在再到内存中获取。
寄存器
寄存器是CPU实际进行指令读写的地方,是距离CPU最近的存储器,读写速度也是最快,能在半个CPU周期完成读写;一个CPU中寄存器数量在几十到几百个之间,每个寄存器容量很小,只能存储一定字节(4-8个字节)的数据。
32 位 CPU 中大多数寄存器可以存储 4 个字节 64 位 CPU 中大多数寄存器可以存储 8 个字节
寄存器根据用途不同,可分为好几类,为了便于后面指令执行过程学习,我们先了解以下几类:
假设一个寄存器最大存储4字节数据,4字节=4*8=32位,值表示范围:0~(2^32) -1,换算单位为4G,也就是这个寄存器最大能查找0-4G范围的地址,但我们之前提到的内存容量可达几T,所以,直接通过一个寄存器无法表示全部范围的内存地址。 采用“基础地址+偏移地址=物理地址”的寻址模式,可极大扩大内存寻址能力。例如:32位的基础地址左移32位,再加上32位的偏移地址,可表示64位(16EiB)的内存地址。 需要注意的是,计算机的最终寻址范围是由下面介绍的地址总线决定的。
按上面的存储器分级,数据先从磁盘加载到内存中,然后被读取到CPU内部的高速缓存和寄存器中,CPU读取寄存器进行处理。其中,CPU和CPU cache之间的数据读写是在CPU内部中完成的,CPU对内存的读写则是通过主板上的总线完成的。
总线可以看成是多根导线的集合,通过控制导线电压的高低来传递数据,高电压是1,低电压是0。
根据传输信息的不同,总线分为地址总线,数据总线和控制总线
试想“向内存3位置读取数据”这一条读指令包含了几个信息:
3类总线分别负责对应信息的传输:CPU通过地址总线将要操作的内存地址信息传递给内存;通过控制总线发出内存读命令;内存将数据从数据总线传入CPU。
图片源自《汇编语言(第3版)》
地址总线
讲地址总线之前,我们先讲讲存储器地址的划分。存储器会被划分为若干个存储单元,存储单元从零开始编号,这些编号可以看做是存储单元在存储器中的地址。
每个存储单元由8个位(bit)组成,也就是可以存储一个字节的数据;假设一个存储器有128个存储单元,可以存储128个字节(Byte)。
CPU通过地址总线来指定存储单元,地址总线的线数,决定了对内存的寻址范围。比如,一个CPU有16根地址总线,最多可以寻找2的16次方个内存单元。
假设一个16位的CPU有20条地址总线,16位的CPU如何一次性给出20位的地址呢?
其实答案前面已经给出了,CPU内部会通过「基础地址」+「偏移地址」的方法合成一个20位的地址。
图片源自《汇编语言(第3版)》
数据总线
CPU与内存或其他器件通过数据总线进行数据传输,数据总线的宽度(总线条数)决定了CPU与外界的数据传输速度。8根数据总线一次可传输一个字节(8bit)的数据,16根数据总线一次可传输两个字节(16bit)。
控制总线
CPU对外部器件的控制是通过控制总线来进行的,多少根控制总线,意味着CPU对外部器件有多少种控制,所以控制总线的宽度决定了CPU对外部器件的控制能力。
了解了各种存储器和总线,我们再来看看程序是如何从磁盘加载到内存然后被CPU执行的。
我们编写的程序需要先经过编译器翻译成CPU认识的指令,这个过程称为指令的构造。程序启动时,会将程序的指令和数据分别存在两个内存段中。同时,PC指针(IP寄存器+CS寄存器)会指到指令段的起始地址(就是将起始地址赋值到PC指针上),表示CPU将从这个地址开始读取内存中的指令并执行。
指令解析
指令先被读取到指令寄存器中,CPU取出执行时,需要先对指令进行解析。
我们都知道,内存中存放的内容都是二进制类型(上面的指令我们写成16进制),cpu读取到要执行的指令后,会先对二进制的指令进行解析。以上面“0x8c400104”为例,拆分成二进制:
上面指令分成操作码、寄存器编号、内存地址三部分:
所以,这条指令是指将指定内存地址的内容加载到寄存器R1中。
总结一下,程序执行时:
所以,取址、译码、执行,这是一个指令的执行周期,所有指令都会严格按照这个顺序执行
指令预读
CPU执行指令的速度是非常快的,但内存的读写是非常慢的,所以,如果从内存中一条条读取指令再执行的话,指令执行周期会变得很慢。
前面我们学到,CPU内部还有三级缓存,所以,我们可以将内存中的多条指令一次性先读到读写速度较快的L1缓存中,这样,取址速度就能跟的上CPU的指令执行速度了。
同时,为了避免数据缓存覆盖指令缓存影响指令执行,我们可以将L1缓存划分为指令区和数据区。
思考下L2和L3需要划分指令区和数据区吗?其实是不需要的,因为L2和L3并不需要协助指令预读。
如何更快的执行指令
为了更快的执行指令,我们需要使用CPU的指令流水线技术。
在刚才的流程中,取指,解码的时候运算单元是空闲的,为了提高指令处理速度,需要让运算单元就可以一直处于运算中。我们可以使用CPU的指令流水线技术,在第一条指令完成取址进行译码时,第二条指令立刻进行取址,依次类推,这样,在上一条指令完成执行后,下一条指令也完成译码可以进行执行了。
图片源自网络
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有