几百字节也对, 64kb也对.
64kb对应的是你用的单片机的地址位数. 你用的单片机是16位地址, 16位能寻到的地址一共只有2^16=64 * 2^10 bit=64kb.
计算机是32位/64位寻址, 至于理论上能寻多大题主请自行计算一下.
另, Cache一般也是分级的; L1 Cache是寄存器的两倍到四倍左右; 一般L2比L1大四倍, L3比L2大至少八倍.
比如i7-64位寻址; L1 Cache 32KB (注意是Kilo-Byte, 也就是32*8 K-bit); L2 Cache是128KB; L3Cache是2MB per Core (每个核心2MB)
不同型号的CPU寄存器的个数差别很大,理论上说越新的CPU寄存器会越多。你看的《深入理解计算机系统》书可能比较老,实际情况比那个要多。
至于你说的64KB,应该是指寻址空间。
然后一条条详细回答你的问题。
先说寄存器个数,现在Intel的最新一代CPU里大概有上百个寄存器,扣除重复使用的相同空间的寄存器,寄存器的大小大概是2KB多,具体的寄存器如下图:
图片来自:
x86Intel手册里没给详细的图,所以不确定broadwell里是否有新加的寄存器。
这一坨寄存器里,最大的就是AVX/AVX2寄存器,但这个是用来做特殊计算的。通用寄存器则非常少,64位下通用寄存器也就是R0~R15,其余的寄存器大部分也用不上。
你说的64KB应该是寻址范围,在16位环境里寻址范围是这个数,但现在都是64位时代了,你这个数有点老。
cache的大小跟寄存器个数没太大关系。
L1 cache大小是有上限的,超过一定的值会导致性能下降,所以一般CPU就看L2/L3 cache就够了,新一代的i7 CPU cache的图如下:
除了数据/指令cache之外,还有TLB等等,也都是cache,只不过你平时感觉不到它的存在。
最后再强调一下cache大小和寄存器个数无关。
首先,题主可能是误解了寻址空间、寄存器两个概念。而且B和b也不一样。
其次,这些问题比较难回答。只有很内行的人才知道准确答案。而且,即便今天有具体答案,过两年可能又有变化。
我早期和大部分人一样,认为虽然CPU在进化,但原理应该是不变的:
但当我了解到现代CPU设计的时候,发现我的想法还停留在1980年。
1995年前后推出的CPU,已经开始出现一些黑科技——最典型的是“乱序执行”。简单来说,就是程序员写的机器代码,在CPU中不按顺序执行,可以先执行后面的,再执行前面的,或者同时执行。
那不会产生BUG吗?当然会。
但乱序执行之后,还会有一个检测器,如果检测到有冲突的写操作,就会调整或者重新执行。
这颠覆了我对CPU的认知。
这意味着,CPU从“自动连续执行指令的机器”,变成了“能得到正确结果”的机器。
也就是说,Intel等芯片厂商,只对结果正确性负责,而不按照教科书上所写的原理去设计。教科书上的每一个环节,都可能在下一代CPU设计时被颠覆。
不仅有乱序执行,还有流水线、新的指令集、兼容性、各种多核架构、虚拟机指令等等等等。每一项进步都和说好的不一样【捂脸】
一些理论原则——比如32位系统可以访问约4GB内存,连这一点都不是一定的。intel只需要微调设计,就可以让32位系统做40位内存寻址,访问几百GB的内存(需要操作系统配合)。这一修改并不违背物理原则,但又和书上讲的不太一样。
所以看书学习时,很容易误解书上所说的意思。
一方面,寄存器、高速缓存、寻址范围、内存空间这些概念很容易搞混。
另一方面,书上写的一部分是当时的事实,一部分是物理原则。如果不加分辨,很难分清二者的区别。
比如,题主的第二个问题是不存在的——cache大小是寄存器多少倍?这个并没有限制,在三级缓存的情况下可以做到非常大,只需要考虑经济成本。
其他答案和题目评论已经提到了寄存器、内存访问区别,以及实际CPU寄存器大小,cache大小的一些问题。这篇答案会首先介绍架构相关寄存器(architectural register)和物理寄存器(physical register)的关系,然后介绍一下影响物理寄存器数目的因素,最后简单介绍一下如何在现代CPU中测量物理寄存器的数目。
首先这里寄存器应该指的是CPU架构相关的寄存器,而非广义或者说VLSI上的寄存器(flip-flop, register),广义上的寄存器基本上可以认为是和有多少晶体管类似的问题。
CPU架构相关的寄存器要区分两个概念。一个是architectural register,就是指令集(ISA)提供给软件可见的寄存器。比如x86中的ax, bx, cx, dx, sp, bp等等。现在的x86_64一共有16个64bit通用寄存器(传统的8个寄存器ax,bx等和新增的通用寄存器r8-r15),32个浮点/vector寄存器(浮点寄存器和simd寄存器是共享的,avx2是256bit寄存器,avx512是512bit寄存器),此外还有一些特殊寄存器(比如control, debug等)。这里主要用到的是通用和浮点/vector寄存器,对于高级语言来讲,由编译器来管理寄存器的分配(经典的图着色算法或者线性扫描算法来进行变量到寄存器的映射,没有上过正经的编译器课程,只是在architecture课上有一些简单的了解)。如果寄存器数目不够的话,可以将变量分配到栈上,以内存(memory)方式访问。对于x86这种CISC指令集来说可以在指令中直接访问内存,而对于像ARM这种RISC指令集还需要额外的load/store指令来访问内存,增加了指令的数目(x86在硬件层面还是会将指令翻译成micro-ops,实际也会转化成类似load/store的指令,这里只是在编译后的机器码层面CISC要比RISC简洁一些)。
在ISA中区分寄存器和内存主要是因为不同存储器的特性(访问延迟,带宽,port的数目,容量,功耗等),寄存器访问可能只需要1个cycle,L1 cache可能需要3-5cycle,LLC miss可能需要几百个cycle。少量的寄存器(或者可以理解为固定内存地址)可以简化指令的实现,同时可以让软件有机会优化(软件的局部性可以让经常访问的变量分配到寄存器上,而不需要通过延迟不确定的内存访问)。
另外一个概念是physical register file,也就是实际CPU中对应的寄存器。现代的超标量乱序执行CPU(intel以Pentium为首)内部会进行寄存器重命名(register renaming)。这是将指令周期降低为小于1的关键之一。涉及寄存器重命名和乱序执行的内容非常多,具体可以参考John Hennessy和David Patterson的Computer Architecture - A Quantitative Approach这本教科书。简单一点介绍,寄存器重命名会把ISA提供的architectural register映射到实际的物理寄存器上,对应的ALU,reorder buffer只需要物理寄存器的指针(tag)而不需要实际寄存器的内容,这样可以减少在乱序执行中数据在不同模块之间的搬移。很多架构图中可以看到RAT(register alias table),就是将architectural register映射到physical register的部件。同时寄存器重命名可以解决architectural register数目比较少的而出现的依赖问题(x86时代只有8个通用寄存器,对比ARM有32个通用寄存器)。这个是编译器无法优化的,因为编译器只有ISA提供的有限寄存器名字空间。举个简单例子(这里用伪代码而非标准x86汇编代码)。
ADD R0 <- R1, R2
IMUL R0 <- R0, R1
SUB R1 <- R2, R3
IMUL R0 <- R1, R2
第一二条指令存在WAW(write after write),RAW(read after write)依赖,第二三条指令存在WAR(write after read)依赖,第三四条指令存在RAW依赖。寄存器重命名可以解决除了RAW之外的依赖,从而尽可能的发掘指令层面的并行性(instruction level parallelism)。下面的指令1,3可以经过寄存器重命名之后可以分配到两个ALU中同时执行。(下面代码仅作为示例,具体算法可以参见tomasulo algorithm[1])
ADD R10 <- R11, R12
IMUL R13 <- R10, R11
SUB R14 <- R12, R13
IMUL R15 <- R14, R12
标量乱序执行的核心就是不断的检查未来的指令,并从中发掘可以并行执行的指令,从而最终提升IPC。这个可以乱序执行的指令窗口叫做instruction window,这是衡量现代CPU性能的一个重要指标(举个不太恰当的例子,以前参加智能车比赛,摄像头看得越远理论上可以跑的越快)。其中有两个关键因素影响着不断增加的instruction window size,一个是分支预测(branch prediction),准确的分支预测(目前的指标可以做到小于10MPKI,MPKI是没1000条指令中预测错误数目)可以保证绝大多数情况下instruction window中的指令都是在正确的程序路径上。否则总是错误的预测执行(speculative execution)反而会降低IPC。另外一个关键就是寄存器重命名和reorder buffer的大小。reorder buffer是实现乱序执行同时保持程序正确性和精确异常的关键,每条指令在译码之后会分配一个reorder buffer的entry,reorder buffer后面会按照指令顺序commit保证程序正确性。通常指令窗口大小(instruction window size)就是reorder buffer entry size,intel的几个关键节点的微架构的instruction window大小如下,Nehalem(45nm)128, Haswell(22nm)192,Sunny Cove(10nm)352。苹果的M1目前达到了~600(一部分原因是ARM不需要micro-ops译码,从而可以实现更高的instruction译码带宽8-wide)。
讲了这么多和recorder buffer相关的东西,原因是instruction window其实还和physical register file的数目密切相关。试想,如果physical register数目不够,那么reorder buffer无法充分利用会阻塞新的指令,如果physical register数目过多,又会导致physical register无法用满而浪费资源和功耗,由于不是每条指令都包含目的寄存器(比如branch instruction, call, ret等),通常physical register的数目要小于reorder buffer entry size。physical register又可以分为两部分,一部分是作为预测执行的寄存器(通过front end register alias table映射),另一部分为retirement RAT做映射保存当前执行的architectural状态(为现场保护用)。这里具体的物理寄存器(physical register)数目需要详细的架构设计仿真来决定,但是由上面的介绍可以看出,其和instruction window size一定是强相关的。
这里instruction window只是影响单个核心的物理寄存器数目(hyperthread技术只是静态划分physical register file和reorder buffer,不产生两套物理寄存器和reorder buffer),现代CPU通常由多个核心组成,也就是说实际CPU中物理寄存器数目还要和核心数目有关。苹果的M1(8核心)的大致物理寄存器大小约为8*600(8+16)/1024=112.5KB。(这里计算简单认为物理寄存器数目和reorder buffer entry数目相同,simd(neon 128bit)物理寄存器和通用寄存器数目相同)。单个核心大约14KB。
这里主要根据一篇博客文章[2]的内容简单介绍一下如何测量物理寄存器的数目。大概的思路就是通过CPU的乱序执行机制,试想可以设计随机内存访问,保证每次load都会LLC miss,由于DRAM的访问延时可能要几百个cycle,在数据从DRAM回到CPU流水线的过程中,load对应的reorder buffer不会commit,我们可以利用这段时间将reorder buffer填满,比如填满ADD指令,由于ADD指令的目的寄存器会占据一个physical register,前面讲过,reorder buffer entry size理论上是会大于physical register file entry size的,那么,当两个随机load指令中间填充的ADD指令占满physical register file后,每条load指令的延时大概就是LLC miss延时。反之,如果两个随机load指令中间的ADD没有占满physical register,这就意味着reorder buffer中会存在两个或以上的load指令,由于load指令可以并发,每条load指令的延时会大大降低。
如果我们能设计这样一个program并测量平均load指令延时,x轴为两条load指令之间填充的ADD指令数目,y轴为平均load指令延时。那么这条曲线陡升的位置对应的ADD指令数目就是大概的physical register数目。
这个因CPU厂家、型号不同不尽相同,得具体问题具体分析。
就像你买车,不同厂家的车发动机型号气缸数不尽相同,即使是同厂家同型号车也有不同的配置导致气缸数不一样。所以你想确定到底有多少,你先选定一片CPU然后去他们公司官网上去找datasheet,里面会有详尽的硬件配置信息... ...
公司名称: 亚游-亚游娱乐-注册登录站
手 机: 13800000000
电 话: 400-123-4567
邮 箱: admin@youweb.com
地 址: 广东省广州市天河区88号