上一讲,我们讲解了CPU里的黑科技,超标量技术和超长指令字技术。

超标量技术能够让取指令以及指令译码也并行进行;在编译的过程,超长指令字技术可以搞定指令前后的依赖关系,使得一次可以取一个指令包。

不过,CPU里的各种神奇的优化我们还远远没有说完。这一讲里,我们讲一讲最后两个提升CPU性能的架构设计。它们分别是,超线程技术以及可能没有那么熟悉的单指令多数据流技术。

超线程:Intel多卖给你的那一倍CPU

不知道你还记得吗,在第二十一讲,我们介绍了Intel是怎么在奔腾4处理器上遭遇的巨大失败。

那时候我们说过,奔腾4的失败的一个重要原因,就是它的CPU的流水线级数太深了。早期的奔腾4的流水线深度高达20级,而后期的代号为Prescott 的奔腾4的流水线级数更是高达31级。超长的流水线,使得我们之前讲的很多解决冒险、提升并发的方案都用不上。

因为这些解决冒险、提升并发的方案,本质上都是一种指令级并行的技术方案。换句话来说,CPU想要在同一个时间,去并行地执行两条指令,而这两条指令,原本在我们的代码里,是有先后顺序的。无论是我们在流水线里面讲到的流水线架构、分支预测以及乱序执行,还是我们在上一讲数的超标量和超长指令字,都是想要通过同一时间执行两条指令,来提升CPU的吞吐率。

然而在奔腾4这个CPU上,这些方法都可能因为流水线太深,而起不到效果。我们讲过,更深的流水线意味着同时在流水线里的指令就多,相互的依赖关系就多。于是,很多时候,我们不得不把流水线停顿下来,插入很多NOP操作,来解决这些依赖带来的冒险问题。

什么是超线程技术呢?Intel想,既然CPU同时运行那些在代码层面有先后依赖关系的指令,会遇到各种冒险问题,我们不如去找一些和这些指令完全独立,没有依赖关系的指令来运行好了。那么这些的指令从哪里来呢?自然同时运行在另外一个程序里了。

你所用的计算机,其实同一个时间可以运行很多个程序。比如,我们现在一边写文章,后台可以运行着一个py脚本程序。而这两个程序,是完全相互独立的。它们两个的指令完全并行运行,而不会产生依赖问题带来的“冒险”。

然而这个时候,你可能就会觉得奇怪了,这么做似乎不需要什么新技术呀。现在我们用的CPU都是多核的,本来就可以用多个不同的CPU核心,去运行多个任务。那么这个超线程技术有什么特别的用处呢?

无论是上面说的多个CPU核心运行不同的程序,还是在单个CPU核心里面切换运行不同线程的任务,在同一个时间点上,一个物理的CPU核心只会运行一个线程的指令,所以其实我们没有真正的做到指令的并行运行。

超线程可不是这样。超线程的CPU,其实是把一个物理层面CPU核心,“伪装”成两个逻辑层面的CPU核心。这个CPU,会在硬件层面增加很多电路,使得我们可以在一个CPU核心内部,维护两个不同线程的指令的状态信息。

比如,在一个物理CPU的核心内部,会有双份的PC寄存器、指令寄存器以及条件码寄存器。这样,这个CPU核心就可以维护两条并行的指令的状态。在外面看来,似乎有两个逻辑层面的CPU在同时运行,所以,超线程技术通常也被叫做同时多线程技术。

不过,在CPU的其他功能组件上,Intel可不会提供双份,无论是指令译码器还是ALU,一个CPU核心仍然只有一份。因为超线程并不是真的去同时执行两个指令,那就真的变成物理多核了。超线程的目的是,在一个线程A的指令,在流水线停顿的时候,让另外一个线程去执行指令。因为这个时候,CPU的译码器和ALU就空出来了。那么另外一个线程B就可以拿来干自己需要的事情。这个线程B可没有对于线程A里面指令的关联和依赖。

这样,CPU通过很小的代价,就能实现“同时”运行多个线程的效果,通常我们只要在CPU核心的添加10%左右的逻辑功能,增加可以忽略不计的晶体管数量,就能做到这一点。

不过,你也看到了,我们并没有增加真的功能单元。所以超线程只能在特定的应用场景下效果比较好。一般是在那些各个线程“等待”时间比较长的应用场景下。比如,我们需要应对很多请求的数据库应用,就很适合用超线程。各个指令都要等待访问内存数据,但是并不需要做太多计算。

于是,我们就可以利用好超线程。我们的CPU计算并没有跑满。但是往往当前的指令要停顿在流水线上,等待内存里面的数据返回。这个时候,让CPU里的各个功能单元,去处理另一个数据库链接的查询请求就是一个很好的应用案例。

SIMD:如何加速矩阵乘法?

在上面的CPU信息图里面,你会看到,中间有一组叫做Instruction,里面写了有MMX,SSE等等。这些信息就是这个CPU所支持的指令集。这里的MMX和SSE的指令集,也就引出了最后一个提升CPU性能的技术方案,SIMD,中文叫做单指令多数据流

我们先来体会一下SIMD的性能到底怎么样。下面是两段实例程序。

python
>>> import numpy as np
>>> import timeit
>>> a = list(range(1000))
>>> b = np.array(range(1000))
>>> timeit.timeit("[i + 1 for i in a]", setup="from __main__ import a", number=1000000)
32.82800309999993
>>> timeit.timeit("np.add(1, b)", setup="from __main__ import np, b", number=1000000)
0.9787889999997788
>>>

你可以看到,两个功能相同的代码性能有着巨大的差异,足足相差了30多倍,也难得怪所有用py讲解数据科学的教程里,往往在一开始就告诉你不要使用循环,而是要把所有的计算都向量化。

有些同学会猜测,是否是因为py是一门解释型语言,所以这个性能差异会那么大。第一段程序的循环的每一次操作都需要 Python 解释器来执行,而第二段的函数调用是一次调用编译好的原生代码,所以才会那么快。如果你这么想,不妨试试直接用 C 语言实现一下 1000 个元素的数组里面的每个数加 1。你会发现,即使是 C 语言编译出来的代码,还是远远低于 NumPy。原因就是,NumPy 直接用到了 SIMD 指令,能够并行进行向量的操作。

而前面使用循环来一步一步计算的算法呢,一般称之为SISD,也就是单指令单数据(Single Instruction Single Data)的处理方式。如果你手头的是一个多核 CPU 呢,那么它同时处理多个指令的方式可以叫作MIMD,也就是多指令多数据(Multiple Instruction Multiple Data)。

为什么 SIMD 指令能快那么多呢?这是因为,SIMD 在获取数据和执行指令的时候,都做到了并行。一方面,在从内存里面读取数据的时候,SIMD是一次性读取多个数据。

就以我们上面的程序为例,数组里面的每一项都是一个 integer,也就是需要 4 Bytes 的内存空间。Intel 在引入 SSE 指令集的时候,在 CPU 里面添上了 8 个 128 Bits 的寄存器。128 Bits 也就是 16 Bytes ,也就是说,一个寄存器一次性可以加载 4 个整数。比起循环分别读取 4 次对应的数据,时间就省下来了。

在数据读取到了之后,在指令的执行层面,SIMD也是可以并行进行的。4个整数各自加1,互相之前完全没有依赖,也就没有冒险问题需要处理。只要CPU里有足够多的功能单元,能够同时进行这些计算,这个加法就是4路同时并行的,自然省下了时间。

所以,对于那些在计算层面存在大量“数据并行”的计算中,使用SIMD是一种很划算的办法,在这个大量的“数据并行”,其实通常就是实践当中的向量运算或者矩阵运算。在实际的程序开发过程中,过去通常是在进行图片,视频,音频的处理。最近几年则通常是在进行各种机器学习算法的计算。

而基于SIMD的向量计算指令,也正是在 Intel 发布 Pentium 处理器的时候,被引入的指令集。当时的指令集叫作MMX,也就是 Matrix Math eXtensions 的缩写,中文名字就是矩阵数学扩展。而 Pentium 处理器,也是 CPU 第一次有能力进行多媒体处理。这也正是拜 SIMD 和 MMX 所赐。

从 Pentium 时代开始,我们能在电脑上听 MP3、看 VCD 了,而不用专门去买一块“声霸卡”或者“显霸卡”了。没错,在那之前,在电脑上看 VCD,是需要专门买能够解码 VCD 的硬件插到电脑上去的。而到了今天,通过 GPU 快速发展起来的深度学习技术,也一样受益于 SIMD 这样的指令级并行方案,在后面讲解GPU的时候,我们还会遇到它。

总结延申

这一讲,我们讲完了超线程和SIMD这两个CPU的“并行计算”方案。超线程,其实是一个“线程级并行”的解决方案,它通过让一个物理CPU核心,“装作”两个逻辑层面的CPU核心,使得CPU可以同时运行两个不同线程的指令。虽然这样的运行仍然有着种种的限制。很多场景下超线程并不一定能带来CPU的性能提升。但是Intel通过超线程,让使用者有了“占到便宜”的感觉。同样的4核心的CPU,在有些情况下能够发挥出8核心CPU的作用。而超线程在今天,已经成了IntelCPU的标配。

而SIMD技术,则是一种“指令级并行”的加速方案,或者我们可以说,它是一种“数据并行”的加速方案,在处理向量计算的情况下,同一个向量的不同维度之间的计算是相互独立的。而我们的CPU里的寄存器,又能放下多条数据。于是,我们可以一次性取出多条数据,交给CPU并行计算。

正是 SIMD 技术的出现,使得我们在 Pentium 时代的个人 PC,开始有了多媒体运算的能力。可以说,Intel的 MMX、SSE 指令集,和微软的 Windows 95这样的图形界面操作系统,推动了 PC 快速进入家庭的历史进程。

思考

超线程这样的技术,在什么样的场景下最高效?你在自己开发系统的过程中,是否遇到过超线程技术为程序带来性能提升的情况呢?

深入计算机组成原理(二十七)SIMD:如何加速矩阵乘法相关推荐

  1. 【27】SIMD:如何加速矩阵乘法?

    [计算机组成原理]学习笔记--总目录 [27]SIMD:如何加速矩阵乘法? 引言 一.超线程:Intel 多卖给你的那一倍 CPU 1.背景 2.超线程(Hyper-Threading)技术 二.SI ...

  2. AVX指令集加速矩阵乘法

    AVX简介 SIMD SIMD(Single Instruction Multiple Data,单指令多数据流),是一种实现空间上的并行性的技术.这种技术使用一个控制器控制多个处理单元,同时对一组数 ...

  3. 计算机组成原理(二)——计算机的基本组成

    计算机的基本组成 冯·诺依曼计算机结构图 冯·诺依曼计算机以运算器为中心. 冯·诺依曼计算机特点 1.计算机由运算器.控制器.存储器.输入设备和输出设备五大部件组成. 2.指令和数据以同等地位存放在存 ...

  4. 计算机组成原理二:系统总线——知识点和知识结构图

    1.总线:计算机系统各部位公共用来传输数据和信息的传输线为总线. 2.总线结构: 单总线结构:将计算机系统各部位挂在一组总线上,图略 双总线结构:将低速设备分离另外挂载在一条新的总线上 多总线结构: ...

  5. CUDA实例——加速矩阵乘法

    Ref: CUDA C programing guide https://docs.nvidia.com/cuda/cuda-runtime-api/index.html 一 什么是CUDA? CUD ...

  6. 【计组】入门篇 --《深入浅出计算机组成原理》(一)

    课程链接:深入浅出计算机组成原理_组成原理_计算机基础-极客时间 目录 一.为什么需要学习计算机组成原理 二.冯·诺依曼体系结构:计算机组成的金字塔 1.计算机的基本硬件组成 2.冯·诺依曼体系结构 ...

  7. 上海大学计算机组成原理实验13,上海大学计算机组成原理实验报告11.doc

    上海大学计算机组成原理实验报告11 上海大学计算机组成原理实验报告11 上海大学_计算机组成原理实验报告8 2011级 上海大学计算机学院 <计算机组成原理二实验>报告8 姓名:学号: 教 ...

  8. 计算机组成大学考试,计算机组成原理本科期末试题4套含答案(大学期末复习资料)(21页)-原创力文档...

    PAGE PAGE 6 总分 一 二 三 四 五 六 七 八 学 院班 级学 号姓 名-----○----- 学 院 班 级 学 号 姓 名 -----○-----密-----○-----封----- ...

  9. 计算机组成原理(一)

    目录 前言 一.为什么要学习计算机组成原理 二.如何学习计算机组成原理 三.计算机的硬件设备组成 CPU 内存 主板 显卡 四.冯·诺依曼体系结构 五.计算机性能 六.计算机功耗 前言 记得吴军博士说 ...

  10. CUDA加速计算矩阵乘法进阶玩法(共享内存)

    CUDA加速计算矩阵乘法&进阶玩法~共享内存 一.基础版矩阵乘法 二.为什么可以利用共享内存加速矩阵乘法 1.CUDA内存读写速度比较 2.申请共享内存 三.改进版矩阵乘法(利用共享内存) 一 ...

最新文章

  1. MySQL的安装和初次使用
  2. centos升级python_CentOS 升级Python3
  3. 怎么理解python的__init___理解Python中super()和__init__()方法
  4. 退役笔记一#MySQL = lambda sql : sql + #39; Source Code 4 Explain Plan #39;
  5. 文本读取写入易错问题
  6. java学习笔记1--开发环境平台总结
  7. matlab 日期加小时数_MATLAB时间与日期的基本操作
  8. boost::ignore_unused的用法实例
  9. java存放的位置_java数据类型的种类以及存放的位置
  10. JavaScript模块化开发(一)基础知识
  11. WinForm中窗体重画成圆角矩形
  12. 软件开发人月成本估算方法
  13. Win10系统解决图片打开方式没有照片查看器
  14. 北大学霸不当外交官,回国种地养猪终于熬出年销2000万
  15. 如何让那些模糊的照片变得高清?不会PS也能解决
  16. CAD突然没有对话框了?只能命令行输入内容??(FILEDIA=0?CMDECHO=0?)
  17. win10便签常驻桌面_Win10下环境有哪些好用的便签记事本?想和iPhone一块儿用 - 学显...
  18. ‘function‘ object has no attribute ‘splits‘(Torchtext加载数据集出现的问题)
  19. 服务器文件防泄密系统,数据防泄密软件解决图纸泄密问题
  20. 前后期绑定Excel/Word对象的应用

热门文章

  1. STL库和Boost库
  2. 【计算理论】计算理论总结 ( 上下文无关文法 ) ★★
  3. 基于STM32的电量采集系统
  4. 使用PHP+MYSQL搭建的一款直播电商源码和大家分享一下
  5. MYSQL卸载教程(5.7)
  6. 弘辽科技:拼多多店铺星级多久更新一次?如何提升?
  7. 统计学中p值计算公式_统计学中的p值怎么算,具体步骤
  8. Android 仿淘宝首页界面
  9. 网页导出pdf不完整_网页怎么打印成PDF文件?使用这款工具轻松实现
  10. GitHub上下载代码