计算机组成原理
文章平均质量分 94
计算机组成原理
_Rye_
左手代码右手诗
一行代码一行诗
展开
-
55 | 理解Disruptor(下):不需要换挡和踩刹车的CPU,有多快?
好了,咱们专栏的正文内容到今天就要结束了。今天最后一讲,一起看了 Disruptor 代码的一个核心设计,也就是它的 RingBuffer 是怎么做到无锁的。Java 基础库里面的 BlockingQueue,都需要通过显示地加锁来保障生产者之间、消费者之间,乃至生产者和消费者之间,不会发生锁冲突的问题。但是,加锁会大大拖慢我们的性能。在获取锁过程中,CPU 没有去执行计算的相关指令,而要等待操作系统或者 JVM 来进行锁竞争的裁决。而那些没有拿到锁而被挂起等待的线程,则需要进行上下文切换。原创 2024-02-09 10:45:27 · 800 阅读 · 0 评论 -
54 | 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣
好了,不知道讲完这些,你有没有体会到 Disruptor 这个框架的神奇之处呢?CPU 从内存加载数据到 CPU Cache 里面的时候,不是一个变量一个变量加载的,而是加载固定长度的 Cache Line。如果是加载数组里面的数据,那么 CPU 就会加载到数组里面连续的多个数据。所以,数组的遍历很容易享受到 CPU Cache 那风驰电掣的速度带来的红利。对于类里面定义的单独的变量,就不容易享受到 CPU Cache 红利了。因为这些字段虽然在内存层面会分配到一起,但是实际应用的时候往往没有什么关联。原创 2024-02-09 10:37:13 · 880 阅读 · 0 评论 -
53 | 设计大型DMP系统(下):SSD拯救了所有的DBA
好了,关于 DMP 和存储器的内容,讲到这里就差不多了。希望今天的这一讲,能够让你从 Cassandra 的数据库实现的细节层面,彻底理解怎么运用好存储器的性能特性和原理。传统的关系型数据库,我们把一条条数据存放在一个地方,同时再把索引存放在另外一个地方。这样的存储方式,其实很方便我们进行单次的随机读和随机写,数据的存储也可以很紧凑。但是问题也在于此,大部分的 SQL 请求,都会带来大量的随机读写的请求。这使得传统的关系型数据库,其实并不适合用在真的高并发的场景下。原创 2024-02-09 10:18:22 · 783 阅读 · 0 评论 -
52 | 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药
好了,相信到这里,应该对怎么从最基本的原理出发,来选择技术栈有些感觉了。你应该更多地从底层的存储系统的特性和原理去考虑问题。一旦能够从这个角度去考虑问题,那么你对各类新的技术项目和产品的公关稿,自然会有一定的免疫力了,而不会轻易根据商业公司的宣传来做技术选型了。因为低延时、高并发、写少读多的 DMP 的 KV 数据库,最适合用 SSD 硬盘,并且采用专门的 KV 数据库是最合适的。我们可以选择之前文章里提过的 AeroSpike,也可以用开源的 Cassandra 来提供服务。原创 2024-02-09 10:04:07 · 884 阅读 · 0 评论 -
51 | 分布式计算:如果所有人的大脑都联网会怎样?
讲到这里,相信已经很清楚,为什么我们需要水平扩展了。对于怎么去设计整个硬件的部署,来保障高可用性,你应该也有了一个清晰的认识。这两点也是分布式计算在实践中非常重要的应用场景。不过,光有这两点还是不够的。一旦系统里面有了很多台服务器。特别是,为了保障可用性,对于同样功能的、有状态的数据库进行了水平的扩展,我们就会面临一个新的挑战,那就是分区一致性问题。不过,这个问题更多的是一个软件设计问题,我把它留在后面再进行讲解。我们下面来回顾一下这一讲的内容。我们讲了通过升级硬件规格来提升服务能力的垂直扩展。原创 2024-02-09 09:25:27 · 782 阅读 · 0 评论 -
50 | 数据完整性(下):如何还原犯罪现场?
好了,纠错码的内容到这里就讲完了。你可不要小看这个看起来简单的海明码。虽然它在上世纪 40 年代早早地就诞生了,不过直到今天的 ECC 内存里面,我们还在使用这个技术方案。而海明也因为海明码获得了图灵奖。通过在数据中添加多个冗余的校验码位,海明码不仅能够检测到数据中的错误,还能够在只有单个位的数据出错的时候,把错误的一位纠正过来。在理解和计算海明码的过程中,有一个很重要的点,就是不仅原来的数据位可能出错。我们新添加的校验位,一样可能会出现单比特翻转的错误。原创 2024-02-09 00:07:54 · 931 阅读 · 0 评论 -
49 | 数据完整性(上):硬件坏了怎么办?
好了,让我们一起来总结一下今天的内容。介绍了一个硬件错误带来的 Bug。由于没有采用 ECC 内存,导致我们的数据处理中,出现了大量的单比特数据翻转的错误。这些硬件带来的错误,其实我们没有办法在软件层面解决。如果对于硬件以及硬件本身的原理不够熟悉,恐怕这个问题的解决方案还是遥遥无期。如果你对计算机组成原理有所了解,并能够意识到,在硬件的存储层有着数据验证和纠错的需求,那你就能在有限的时间内定位到问题所在。进一步地,简单介绍了奇偶校验,也就是如何通过冗余的一位数据,发现在硬件层面出现的位错误。原创 2024-02-08 23:51:18 · 856 阅读 · 0 评论 -
48 | DMA:为什么Kafka这么快?
讲到这里,相信对 DMA 的原理、作用和效果都有所理解了。那么,我们一起来回顾总结一下。如果我们始终让 CPU 来进行各种数据传输工作,会特别浪费。一方面,我们的数据传输工作用不到多少 CPU 核心的“计算”功能。另一方面,CPU 的运转速度也比 I/O 操作要快很多。所以,我们希望能够给 CPU“减负”。于是,工程师们就在主板上放上了 DMAC 这样一个协处理器芯片。通过这个芯片,CPU 只需要告诉 DMAC,我们要传输什么数据,从哪里来,到哪里去,就可以放心离开了。原创 2024-02-08 23:05:43 · 916 阅读 · 0 评论 -
47 | SSD硬盘(下):如何完成性能优化的KPI?
好了,现在让我们一起来总结一下今天的内容。因为 SSD 硬盘的使用寿命,受限于块的擦除次数,所以我们需要通过一个磨损均衡的策略,来管理 SSD 硬盘的各个块的擦除次数。我们通过在逻辑块地址和物理块地址之间,引入 FTL 这个映射层,使得操作系统无需关心物理块的擦写次数,而是由 FTL 里的软件算法,来协调到底每一次写入应该磨损哪一块。除了磨损均衡之外,操作系统和 SSD 硬件的特性还有一个不匹配的地方。那就是,操作系统在删除数据的时候,并没有真的删除物理层面的数据,而只是修改了 inode 里面的数据。原创 2024-02-08 22:38:39 · 889 阅读 · 0 评论 -
46 | SSD硬盘(上):如何完成性能优化的KPI?
到这里,相信对 SSD 硬盘的写入和擦除的原理已经清楚了,也明白了 SSD 硬盘的使用寿命受限于可以擦除的次数。仔细想一想,你会发现 SSD 硬盘,特别适合读多写少的应用。在日常应用里面,我们的系统盘适合用 SSD。但是,如果我们用 SSD 做专门的下载盘,一直下载各种影音数据,然后刻盘备份就不太好了,特别是现在 QLC 颗粒的 SSD,它只有几千次可擦写的寿命啊。在数据中心里面,SSD 的应用场景也是适合读多写少的场景。我们拿 SSD 硬盘用来做数据库,存放电商网站的商品信息很合适。原创 2024-02-08 20:58:22 · 952 阅读 · 0 评论 -
45 | 机械硬盘:Google早期用过的“黑科技”
好了,相信通过这一讲,对传统的 HDD 硬盘应该有了深入的了解。我们来总结一下。机械硬盘的硬件,主要由盘面、磁头和悬臂三部分组成。我们的数据在盘面上的位置,可以通过磁道、扇区和柱面来定位。实际的一次对于硬盘的访问,需要把盘面旋转到某一个“几何扇区”,对准悬臂的位置。然后,悬臂通过寻道,把磁头放到我们实际要读取的扇区上。受制于机械硬盘的结构,我们对于随机数据的访问速度,就要包含旋转盘面的平均延时和移动悬臂的寻道时间。通过这两个时间,我们能计算出机械硬盘的 IOPS。原创 2024-02-08 20:30:45 · 914 阅读 · 0 评论 -
44 | 理解IO_WAIT:I/O性能到底是怎么回事儿?
这一讲里,我们从硬盘的两个核心指标,响应时间和数据传输率,来理解和研究 I/O 的性能问题。你也自己可以通过 as ssd 这样的性能评测软件,看一看自己的硬盘性能。在顺序读取的情况下,无论是 HDD 硬盘还是 SSD 硬盘,性能看起来都是很不错的。不过,等到进行随机读取测试的时候,硬盘的性能才能见了真章。因为在大部分的应用开发场景下,我们关心的并不是在顺序读写下的数据量,而是每秒钟能够进行输入输出的操作次数,也就是 IOPS 这个核心性能指标。原创 2024-02-08 20:17:31 · 1138 阅读 · 0 评论 -
43 | 输入输出设备:我们并不是只能用灯泡显示“0”和“1”
好了,讲到这里,不知道,现在你是不是可以把 CPU 的指令、总线和 I/O 设备之间的关系彻底串联起来了呢?来回顾一下。CPU 并不是发送一个特定的操作指令来操作不同的 I/O 设备。因为如果是那样的话,随着新的 I/O 设备的发明,我们就要去扩展 CPU 的指令集了。在计算机系统里面,CPU 和 I/O 设备之间的通信,是这么来解决的。首先,在 I/O 设备这一侧,我们把 I/O 设备拆分成,能和 CPU 通信的接口电路,以及实际的 I/O 设备本身。原创 2024-02-08 19:48:16 · 920 阅读 · 0 评论 -
42 | 总线:计算机内部的高速公路
好了,现在明白计算机里的总线、各种不同的总线到底是什么意思了吧?希望这一讲能够帮你厘清计算机总线的知识点。现在我们一起来总结梳理一下这节的内容。这一讲,讲解了计算机里各个不同的组件之间用来通信的渠道,也就是总线。总线的设计思路,核心是为了减少多个模块之间交互的复杂性和耦合度。实际上,总线这个设计思路在我们的软件开发过程中也经常会被用到。事件总线就是我们常见的一个设计模式,通常事件总线也会和订阅者发布者模式结合起来,成为大型系统的各个松耦合的模块之间交互的一种主要模式。原创 2024-02-08 00:17:23 · 988 阅读 · 0 评论 -
41 | 理解内存(下):解析TLB和内存保护
为了节约页表所需要的内存空间,我们采用了多级页表这样一个数据结构。但是,多级页表虽然节省空间了,却要花费更多的时间去多次访问内存。于是,我们在实际进行地址转换的 MMU 旁边放上了 TLB 这个用于地址转换的缓存。TLB 也像 CPU Cache 一样,分成指令和数据部分,也可以进行 L1、L2 这样的分层。然后,介绍了内存保护。无论是数据还是代码,我们都要存放在内存里面。原创 2024-02-08 00:14:16 · 1120 阅读 · 0 评论 -
40 | 理解内存(上):虚拟内存和内存保护是什么?
好了,这一讲的内容差不多了,我们来总结一下。我们从最简单的进行虚拟页号一一映射的简单页表说起,仔细讲解了现在实际应用的多级页表。多级页表就像是一颗树。因为一个进程的内存地址相对集中和连续,所以采用这种页表树的方式,可以大大节省页表所需要的空间。而因为每个进程都需要一个独立的页表,这个空间的节省是非常可观的。在优化页表的过程中,我们可以观察到,数组这样的紧凑的数据结构,以及树这样稀疏的数据结构,在时间复杂度和空间复杂度的差异。另外,纯粹理论软件的数据结构和硬件的设计也是高度相关的。原创 2024-02-08 00:12:48 · 871 阅读 · 0 评论 -
39 | MESI协议:如何让多核CPU的高速缓存保持一致?
关于 CPU Cache 的内容,我们介绍到这里就结束了。我们来总结一下。这一节,我们其实就讲了两块儿内容,一个是缓存一致性,另一个是 MESI 协议。想要实现缓存一致性,关键是要满足两点。第一个是写传播,也就是在一个 CPU 核心写入的内容,需要传播到其他 CPU 核心里。更重要的是第二点,保障事务的串行化,才能保障我们的数据是真正一致的,我们的程序在各个不同的核心上运行的结果也是一致的。这个特性不仅在 CPU 的缓存层面很重要,在数据库层面更加重要。之后,介绍了基于总线嗅探机制的 MESI 协议。原创 2024-02-08 00:11:55 · 1082 阅读 · 0 评论 -
38 | 高速缓存(下):你确定你的数据更新了么?
最后,我们一起来回顾一下这一讲的知识点。通过一个使用 Java 程序中使用 volatile 关键字程序,我们可以看到,在有缓存的情况下会遇到一致性问题。volatile 这个关键字可以保障我们对于数据的读写都会到达主内存。进一步地,我们可以看到,Java 内存模型和 CPU、CPU Cache 以及主内存的组织结构非常相似。在 CPU Cache 里,对于数据的写入,我们也有写直达和写回这两种解决方案。写直达把所有的数据都直接写入到主内存里面,简单直观,但是性能就会受限于内存的访问速度。原创 2024-02-07 23:22:06 · 818 阅读 · 0 评论 -
37 | 高速缓存(上):“4毫秒”究竟值多少钱?
很多时候,程序的性能瓶颈,来自使用 DRAM 芯片的内存访问速度。根据摩尔定律,自上世纪 80 年代以来,CPU 和内存的性能鸿沟越拉越大。于是,现代 CPU 的设计者们,直接在 CPU 中嵌入了使用更高性能的 SRAM 芯片的 Cache,来弥补这一性能差异。通过巧妙地将内存地址,拆分成“索引 + 组标记 + 偏移量”的方式,使得我们可以将很大的内存地址,映射到很小的 CPU Cache 地址里。原创 2024-02-07 23:08:53 · 979 阅读 · 0 评论 -
36 | 局部性原理:数据库性能跟不上,加个缓存就好了?
这一讲,我们讲解了计算机存储器层次结构中最重要的一个优化思路,就是局部性原理。在实际的计算机日常的开发和应用中,我们对于数据的访问总是会存在一定的局部性。有时候,这个局部性是时间局部性,就是我们最近访问过的数据还会被反复访问。有时候,这个局部性是空间局部性,就是我们最近访问过数据附近的数据很快会被访问到。而局部性的存在,使得我们可以在应用开发中使用缓存这个有利的武器。比如,通过将热点数据加载并保留在速度更快的存储设备里面,我们可以用更低的成本来支撑服务器。原创 2024-02-07 22:10:57 · 878 阅读 · 0 评论 -
35 | 存储器层次结构全景:数据存储的大金字塔长什么样?
这节的内容不知道你掌握了多少呢?为了帮助记忆,这里再复习一下本节的重点。我们常常把 CPU 比喻成高速运转的大脑,那么和大脑同步的寄存器(Register),就存放着我们当下正在思考和处理的数据。而 L1-L3 的 CPU Cache,好比存放在我们大脑中的短期到长期的记忆。我们需要小小花费一点时间,就能调取并进行处理。我们自己的书桌书架就好比计算机的内存,能放下更多的书也就是数据,但是找起来和看起来就要慢上不少。而图书馆更像硬盘这个外存,能够放下更多的数据,找起来也更费时间。原创 2024-02-07 21:58:26 · 1125 阅读 · 0 评论 -
34 | 理解虚拟机:你在云上拿到的计算机是什么样的?
这一讲,从最古老的分时系统讲起,介绍了虚拟机的相关技术。我们现在的云服务平台上,你能够租到的服务器其实都是虚拟机,而不是物理机。而正是虚拟机技术的出现,使得整个云服务生态得以出现。虚拟机是模拟一个计算机系统的技术,而其中最简单的办法叫模拟器。我们日常在 PC 上进行 Android 开发,其实就是在使用这样的模拟器技术。不过模拟器技术在性能上实在不行,所以我们才有了虚拟化这样的技术。在宿主机的操作系统上,运行一个虚拟机监视器,然后再在虚拟机监视器上运行客户机的操作系统,这就是现代的虚拟化技术。原创 2024-02-07 16:20:03 · 809 阅读 · 0 评论 -
33 | 解读TPU:设计和拆解一块ASIC芯片
这一讲,从第一代 TPU 的设计目标讲起,解读了 TPU 的设计。可以通过这篇文章,回顾我们过去 32 讲提到的各种知识点。第一代 TPU,是为了做各种深度学习的推断而设计出来的,并且希望能够尽早上线。这样,Google 才能节约现有数据中心里面的大量计算资源。从深度学习的推断角度来考虑,TPU 并不需要太灵活的可编程能力,只要能够迭代完成常见的深度学习推断过程中一层的计算过程就好了。所以,TPU 的硬件构造里面,把矩阵乘法、累加器和激活函数都做成了对应的专门的电路。原创 2024-02-07 15:18:44 · 1330 阅读 · 0 评论 -
32 | FPGA和ASIC:计算机体系结构的黄金时代
这一讲里,介绍了 FPGA 和 ASIC 这两种芯片。FPGA 本质上是一个可以通过编程,来控制硬件电路的芯片。我们通过用 LUT 这样的存储设备,来代替需要的硬连线的电路,有了可编程的逻辑门,然后把很多 LUT 和寄存器放在一起,变成一个更复杂的逻辑电路,也就是 CLB,然后通过控制可编程布线中的很多开关,最终设计出属于我们自己的芯片功能。FPGA,常常被我们用来进行芯片的设计和验证工作,也可以直接拿来当成专用的芯片,替换掉 CPU 或者 GPU,以节约成本。原创 2024-02-06 02:47:51 · 1008 阅读 · 0 评论 -
31 | GPU(下):为什么深度学习需要使用GPU?
这一讲里面,我们讲了,GPU 一开始是没有“可编程”能力的,程序员们只能够通过配置来设计需要用到的图形渲染效果。随着“可编程管线”的出现,程序员们可以在顶点处理和片段处理去实现自己的算法。为了进一步去提升 GPU 硬件里面的芯片利用率,微软在 XBox 360 里面,第一次引入了“统一着色器架构”,使得 GPU 变成了一个有“通用计算”能力的架构。接着,我们从一个 CPU 的硬件电路出发,去掉了对 GPU 没有什么用的分支预测和乱序执行电路,来进行瘦身。原创 2024-02-06 02:30:20 · 1289 阅读 · 0 评论 -
30 | GPU(上):为什么玩游戏需要使用GPU?
这一讲里,我带你了解了一个基于多边形建模的三维图形的渲染过程。这个渲染过程需要经过顶点处理、图元处理、栅格化、片段处理以及像素操作这 5 个步骤。这 5 个步骤把存储在内存里面的多边形数据变成了渲染在屏幕上的画面。因为里面的很多步骤,都需要渲染整个画面里面的每一个像素,所以其实计算量是很大的。我们的 CPU 这个时候,就有点跑不动了。于是,像 3dfx 和 NVidia 这样的厂商就推出了 3D 加速卡,用硬件来完成图元处理开始的渲染流程。原创 2024-02-06 02:00:23 · 1105 阅读 · 0 评论 -
29 | CISC和RISC:为什么手机芯片都是ARM?
这一讲,从 RISC 和 CISC 架构之前的差异说起,讲到 RISC 的指令是固定长度的,CISC 的指令是可变长度的。RISC 的指令集里的指令数少,而且单个指令只完成简单的功能,所以被称为“精简”。CISC 里的指令数多,为了节约内存,直接在硬件层面能够完成复杂的功能,所以被称为“复杂”。RISC 的通过减少 CPI 来提升性能,而 CISC 通过减少需要的指令数来提升性能。然后,我们进一步介绍了 Intel 的 x86 CPU 的“微指令”的设计思路。原创 2024-02-06 01:22:50 · 1224 阅读 · 0 评论 -
28 | 异常和中断:程序出错了怎么办?
这一讲讲了计算机里的“异常”处理流程。这里的异常可以分成中断、陷阱、故障、中止这样四种情况。这四种异常,分别对应着 I/O 设备的输入、程序主动触发的状态切换、异常情况下的程序出错以及出错之后无可挽回的退出程序。当 CPU 遭遇了异常的时候,计算机就需要有相应的应对措施。CPU 会通过“查表法”来解决这个问题。在硬件层面和操作系统层面,各自定义了所有 CPU 可能会遇到的异常代码,并且通过这个异常代码,在异常表里面查询相应的异常处理程序。原创 2024-02-05 22:52:18 · 1127 阅读 · 0 评论 -
27 | SIMD:如何加速矩阵乘法?
这一讲,我们讲完了超线程和 SIMD 这两个 CPU 的“并行计算”方案。超线程,其实是一个“线程级并行”的解决方案。它通过让一个物理 CPU 核心,“装作”两个逻辑层面的 CPU 核心,使得 CPU 可以同时运行两个不同线程的指令。虽然,这样的运行仍然有着种种的限制,很多场景下超线程并不一定能带来 CPU 的性能提升。但是 Intel 通过超线程,让使用者有了“占到便宜”的感觉。同样的 4 核心的 CPU,在有些情况下能够发挥出 8 核心 CPU 的作用。原创 2024-02-05 18:09:51 · 1148 阅读 · 0 评论 -
26 | Superscalar和VLIW:如何让CPU的吞吐率超过1?
这一讲里,一起向 CPU 的性能发起了一个新的挑战:让 CPU 的吞吐率,也就是 IPC 能够超过 1。先是介绍了超标量,也就是 Superscalar 这个方法。超标量可以让 CPU 不仅在指令执行阶段是并行的,在取指令和指令译码的时候,也是并行的。通过超标量技术,可以使得你所使用的 CPU 的 IPC 超过 1。在 Intel 的 x86 的 CPU 里,从 Pentium 时代,第一次开始引入超标量技术,整个 CPU 的性能上了一个台阶。对应的技术,一直沿用到了现在。原创 2024-02-05 17:39:08 · 1010 阅读 · 0 评论 -
25 | 冒险和预测(四):今天下雨了,明天还会下雨么?
好了,这一讲,讲解了什么是控制冒险,以及应对控制冒险的三个方式。第一种方案,类似我们的操作数前推,其实是在改造我们的 CPU 功能,通过增加对应的电路的方式,来缩短分支带来的延迟。另外两种解决方案,无论是“假装分支不发生”,还是“动态分支预测”,其实都是在进行“分支预测”。只是,“假装分支不发生”是一种简单的静态预测方案而已。在动态分支预测技术里,我给你介绍了一级分支预测,或者叫 1 比特饱和计数的方法。其实就是认为,预测结果和上一次的条件跳转是一致的。原创 2024-02-05 17:04:26 · 1234 阅读 · 0 评论 -
24 | 冒险和预测(三):CPU里的“线程池”
总结一下。这一讲里,介绍了乱序执行,这个解决流水线阻塞的技术方案。因为数据的依赖关系和指令先后执行的顺序问题,很多时候,流水线不得不“阻塞”在特定的指令上。即使后续别的指令,并不依赖正在执行的指令和阻塞的指令,也不能继续执行。而乱序执行,则是在指令执行的阶段通过一个类似线程池的保留站,让系统自己去动态调度先执行哪些指令。这个动态调度巧妙地解决了流水线阻塞的问题。指令执行的先后顺序,不再和它们在程序中的顺序有关。我们只要保证不破坏数据依赖就好了。原创 2024-02-05 16:32:16 · 895 阅读 · 0 评论 -
23 | 冒险和预测(二):流水线里的接力赛
这一讲,我给你介绍了一个更加高级,也更加复杂的解决数据冒险问题方案,就是操作数前推,或者叫操作数旁路。操作数前推,就是通过在硬件层面制造一条旁路,让一条指令的计算结果,可以直接传输给下一条指令,而不再需要“指令 1 写回寄存器,指令 2 再读取寄存器“这样多此一举的操作。这样直接传输带来的好处就是,后面的指令可以减少,甚至消除原本需要通过流水线停顿,才能解决的数据冒险问题。这个前推的解决方案,不仅可以单独使用,还可以和前面讲解过的流水线冒泡结合在一起使用。原创 2024-02-05 16:01:48 · 820 阅读 · 0 评论 -
22 | 冒险和预测(一):hazard是“危”也是“机”
讲到这里,相信你已经弄明白了什么是结构冒险,什么是数据冒险,以及数据冒险所要保障的三种依赖,也就是数据依赖、反依赖以及输出依赖。一方面,我们可以通过增加资源来解决结构冒险问题。我们现代的 CPU 的体系结构,其实也是在冯·诺依曼体系结构下,借鉴哈佛结构的一个混合结构的解决方案。我们的内存虽然没有按照功能拆分,但是在高速缓存层面进行了拆分,也就是拆分成指令缓存和数据缓存这样的方式,从硬件层面,使得同一个时钟下对于相同资源的竞争不再发生。原创 2024-02-05 15:19:47 · 1062 阅读 · 0 评论 -
21 | 面向流水线的指令设计(下):奔腾4是怎么失败的?
相信到这里,对 CPU 的流水线技术,有了一个更加深入的了解。你会发现,流水线技术和其他技术一样,都讲究一个“折衷”(Trade-Off)。一个合理的流水线深度,会提升我们 CPU 执行计算机指令的吞吐率。我们一般用 IPC(Instruction Per Cycle)来衡量 CPU 执行指令的效率。IPC 呢,其实就是我们之前在第 3 讲讲的 CPI(Cycle Per Instruction)的倒数。也就是说, IPC = 3 对应着 CPI = 0.33。原创 2024-02-05 14:42:40 · 817 阅读 · 0 评论 -
20 | 面向流水线的指令设计(上):一心多用的现代CPU
讲到这里,相信你已经能够理解,为什么我们的 CPU 需要流水线设计了,也能把每一个流水线阶段在干什么,和上一讲的整个 CPU 的数据通路的连接过程对上了。可以看到,为了能够不浪费 CPU 的性能,我们通过把指令的执行过程,切分成一个一个流水线级,来提升 CPU 的吞吐率。而我们本身的 CPU 的设计,又是由一个个独立的组合逻辑电路串接起来形成的,天然能够适合这样采用流水线“专业分工”的工作方式。因为每一级的 overhead,一味地增加流水线深度,并不能无限地提高性能。原创 2024-02-05 11:37:12 · 913 阅读 · 0 评论 -
19 | 建立数据通路(下):指令+运算=CPU
好了,今天我们讲完了,怎么通过连接不同功能的电路,实现出一个完整的 CPU。我们可以通过自动计数器的电路,来实现一个 PC 寄存器,不断生成下一条要执行的计算机指令的内存地址。然后通过译码器,从内存里面读出对应的指令,写入到 D 触发器实现的指令寄存器中。再通过另外一个译码器,把它解析成我们需要执行的指令和操作数的地址。这些电路,组成了我们计算机五大组成部分里面的控制器。原创 2024-02-05 11:02:31 · 877 阅读 · 0 评论 -
18 | 建立数据通路(中):指令+运算=CPU
到了这里,我们可以顺一顺思路了。通过引入了时序电路,我们终于可以把数据“存储”下来了。我们通过反馈电路,创建了时钟信号,然后再利用这个时钟信号和门电路组合,实现了“状态记忆”的功能。电路的输出信号不单单取决于当前的输入信号,还要取决于输出信号之前的状态。最常见的这个电路就是我们的 D 触发器,它也是我们实际在 CPU 内实现存储功能的寄存器的实现方式。原创 2024-02-05 10:29:53 · 794 阅读 · 0 评论 -
17 | 建立数据通路(上):指令+运算=CPU
好了,到这里,我们已经把 CPU 运转需要的数据通路和控制器介绍完了,也找出了需要完成这些功能,需要的 4 种基本电路。它们分别是,ALU 这样的组合逻辑电路、用来存储数据的锁存器和 D 触发器电路、用来实现 PC 寄存器的计数器电路,以及用来解码和寻址的译码器电路。虽然 CPU 已经是由几十亿个晶体管组成的及其复杂的电路,但是它仍然是由这样一个个基本功能的电路组成的。只要搞清楚这些电路的运作原理,你自然也就弄明白了 CPU 的工作原理。原创 2024-02-05 09:54:37 · 942 阅读 · 0 评论 -
16 | 浮点数和定点数(下):深入理解浮点数到底有什么用?
到这里,我们已经讲完了浮点数的表示、加法计算以及可能会遇到的精度损失问题。可以看到,虽然浮点数能够表示的数据范围变大了很多,但是在实际应用的时候,由于存在精度损失,会导致加法的结果和我们的预期不同,乃至于完全没有加上的情况。所以,一般情况下,在实践应用中,对于需要精确数值的,比如银行存款、电商交易,我们都会使用定点数或者整数类型。比方说,你一定在 MySQL 里用过 decimal(12,2),来表示订单金额。原创 2024-02-05 09:18:23 · 1053 阅读 · 0 评论
分享