learn.lianglianglee.com/专栏/深入浅出计算机组成原理/03 通过你的CPU主频,我们来谈谈“性能”究竟是什么?.md.html
2022-05-11 18:57:05 +08:00

1147 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>03 通过你的CPU主频我们来谈谈“性能”究竟是什么.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/深入浅出计算机组成原理/00 开篇词 为什么你需要学习计算机组成原理?.md.html">00 开篇词 为什么你需要学习计算机组成原理?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/01 冯·诺依曼体系结构:计算机组成的金字塔.md.html">01 冯·诺依曼体系结构:计算机组成的金字塔.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/02 给你一张知识地图,计算机组成原理应该这么学.md.html">02 给你一张知识地图,计算机组成原理应该这么学.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/深入浅出计算机组成原理/03 通过你的CPU主频我们来谈谈“性能”究竟是什么.md.html">03 通过你的CPU主频我们来谈谈“性能”究竟是什么.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/04 穿越功耗墙,我们该从哪些方面提升“性能”?.md.html">04 穿越功耗墙,我们该从哪些方面提升“性能”?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/05 计算机指令:让我们试试用纸带编程.md.html">05 计算机指令:让我们试试用纸带编程.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/06 指令跳转原来if...else就是goto.md.html">06 指令跳转原来if...else就是goto.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/07 函数调用为什么会发生stack overflow.md.html">07 函数调用为什么会发生stack overflow.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/08 ELF和静态链接为什么程序无法同时在Linux和Windows下运行.md.html">08 ELF和静态链接为什么程序无法同时在Linux和Windows下运行.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/09 程序装载“640K内存”真的不够用么.md.html">09 程序装载“640K内存”真的不够用么.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/10 动态链接:程序内部的“共享单车”.md.html">10 动态链接:程序内部的“共享单车”.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?.md.html">11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/12 理解电路:从电报机到门电路,我们如何做到“千里传信”?.md.html">12 理解电路:从电报机到门电路,我们如何做到“千里传信”?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/13 加法器:如何像搭乐高一样搭电路(上)?.md.html">13 加法器:如何像搭乐高一样搭电路(上)?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/14 乘法器:如何像搭乐高一样搭电路(下)?.md.html">14 乘法器:如何像搭乐高一样搭电路(下)?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/15 浮点数和定点数怎么用有限的Bit表示尽可能多的信息.md.html">15 浮点数和定点数怎么用有限的Bit表示尽可能多的信息.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/16 浮点数和定点数(下):深入理解浮点数到底有什么用?.md.html">16 浮点数和定点数(下):深入理解浮点数到底有什么用?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/17 建立数据通路(上):指令加运算=CPU.md.html">17 建立数据通路(上):指令加运算=CPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/18 建立数据通路(中):指令加运算=CPU.md.html">18 建立数据通路(中):指令加运算=CPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/19 建立数据通路(下):指令加运算=CPU.md.html">19 建立数据通路(下):指令加运算=CPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/20 面向流水线的指令设计一心多用的现代CPU.md.html">20 面向流水线的指令设计一心多用的现代CPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/21 面向流水线的指令设计奔腾4是怎么失败的.md.html">21 面向流水线的指令设计奔腾4是怎么失败的.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/22 冒险和预测hazard是“危”也是“机”.md.html">22 冒险和预测hazard是“危”也是“机”.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/23 冒险和预测(二):流水线里的接力赛.md.html">23 冒险和预测(二):流水线里的接力赛.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/24 冒险和预测CPU里的“线程池”.md.html">24 冒险和预测CPU里的“线程池”.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/25 冒险和预测(四):今天下雨了,明天还会下雨么?.md.html">25 冒险和预测(四):今天下雨了,明天还会下雨么?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/26 Superscalar和VLIW如何让CPU的吞吐率超过1.md.html">26 Superscalar和VLIW如何让CPU的吞吐率超过1.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/27 SIMD如何加速矩阵乘法.md.html">27 SIMD如何加速矩阵乘法.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/28 异常和中断:程序出错了怎么办?.md.html">28 异常和中断:程序出错了怎么办?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/29 CISC和RISC为什么手机芯片都是ARM.md.html">29 CISC和RISC为什么手机芯片都是ARM.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/30 GPU为什么玩游戏需要使用GPU.md.html">30 GPU为什么玩游戏需要使用GPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/31 GPU为什么深度学习需要使用GPU.md.html">31 GPU为什么深度学习需要使用GPU.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/32 FPGA、ASIC和TPU计算机体系结构的黄金时代.md.html">32 FPGA、ASIC和TPU计算机体系结构的黄金时代.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/33 解读TPU设计和拆解一块ASIC芯片.md.html">33 解读TPU设计和拆解一块ASIC芯片.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/34 理解虚拟机:你在云上拿到的计算机是什么样的?.md.html">34 理解虚拟机:你在云上拿到的计算机是什么样的?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/35 存储器层次结构全景:数据存储的大金字塔长什么样?.md.html">35 存储器层次结构全景:数据存储的大金字塔长什么样?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/36 局部性原理:数据库性能跟不上,加个缓存就好了?.md.html">36 局部性原理:数据库性能跟不上,加个缓存就好了?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/37 理解CPU Cache“4毫秒”究竟值多少钱.md.html">37 理解CPU Cache“4毫秒”究竟值多少钱.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/38 高速缓存(下):你确定你的数据更新了么?.md.html">38 高速缓存(下):你确定你的数据更新了么?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/39 MESI协议如何让多核CPU的高速缓存保持一致.md.html">39 MESI协议如何让多核CPU的高速缓存保持一致.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/40 理解内存(上):虚拟内存和内存保护是什么?.md.html">40 理解内存(上):虚拟内存和内存保护是什么?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/41 理解内存解析TLB和内存保护.md.html">41 理解内存解析TLB和内存保护.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/42 总线:计算机内部的高速公路.md.html">42 总线:计算机内部的高速公路.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/43 输入输出设备我们并不是只能用灯泡显示“0”和“1”.md.html">43 输入输出设备我们并不是只能用灯泡显示“0”和“1”.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/44 理解IO_WAITIO性能到底是怎么回事儿.md.html">44 理解IO_WAITIO性能到底是怎么回事儿.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/45 机械硬盘Google早期用过的“黑科技”.md.html">45 机械硬盘Google早期用过的“黑科技”.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/46 SSD硬盘如何完成性能优化的KPI.md.html">46 SSD硬盘如何完成性能优化的KPI.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/47 SSD硬盘如何完成性能优化的KPI.md.html">47 SSD硬盘如何完成性能优化的KPI.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/48 DMA为什么Kafka这么快.md.html">48 DMA为什么Kafka这么快.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/49 数据完整性(上):硬件坏了怎么办?.md.html">49 数据完整性(上):硬件坏了怎么办?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/50 数据完整性(下):如何还原犯罪现场?.md.html">50 数据完整性(下):如何还原犯罪现场?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/51 分布式计算:如果所有人的大脑都联网会怎样?.md.html">51 分布式计算:如果所有人的大脑都联网会怎样?.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/52 设计大型DMP系统MongoDB并不是什么灵丹妙药.md.html">52 设计大型DMP系统MongoDB并不是什么灵丹妙药.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/53 设计大型DMP系统SSD拯救了所有的DBA.md.html">53 设计大型DMP系统SSD拯救了所有的DBA.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/54 理解Disruptor带你体会CPU高速缓存的风驰电掣.md.html">54 理解Disruptor带你体会CPU高速缓存的风驰电掣.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/55 理解Disruptor不需要换挡和踩刹车的CPU有多快.md.html">55 理解Disruptor不需要换挡和踩刹车的CPU有多快.md.html</a>
</li>
<li>
<a href="/专栏/深入浅出计算机组成原理/结束语 知也无涯,愿你也享受发现的乐趣.md.html">结束语 知也无涯,愿你也享受发现的乐趣.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>03 通过你的CPU主频我们来谈谈“性能”究竟是什么</h1>
<p>“性能”这个词,不管是在日常生活还是写程序的时候,都经常被提到。比方说,买新电脑的时候,我们会说“原来的电脑性能跟不上了”;写程序的时候,我们会说,“这个程序性能需要优化一下”。那么,你有没有想过,我们常常挂在嘴边的“性能”到底指的是什么呢?我们能不能给性能下一个明确的定义,然后来进行准确的比较呢?</p>
<p>在计算机组成原理乃至体系结构中,“性能”都是最重要的一个主题。我在前面说过,学习和研究计算机组成原理,就是在理解计算机是怎么运作的,以及为什么要这么运作。“为什么”所要解决的事情,很多时候就是提升“性能”。</p>
<h2>什么是性能?时间的倒数</h2>
<p>计算机的性能,其实和我们干体力劳动很像,好比是我们要搬东西。对于计算机的性能,我们需要有个标准来衡量。这个标准中主要有两个指标。</p>
<p>第一个是<strong>响应时间</strong>Response time或者叫执行时间Execution time。想要提升响应时间这个性能指标你可以理解为让计算机“跑得更快”。</p>
<p><img src="assets/4c87a1851aeb6857a323064859da6396.png" alt="img" /></p>
<p>图中是我们实际系统里性能监测工具 NewRelic 中的响应时间,代表了每个外部的 Web 请求的执行时间</p>
<p>第二个是<strong>吞吐率</strong>Throughput或者带宽Bandwidth想要提升这个指标你可以理解为让计算机“搬得更多”。</p>
<p><img src="assets/27cab77c0eec95ec29792e6c3d093d27.png" alt="img" /></p>
<p>服务器使用的网络带宽,通常就是一个吞吐率性能指标</p>
<p>所以说,响应时间指的就是,我们执行一个程序,到底需要花多少时间。花的时间越少,自然性能就越好。</p>
<p>而吞吐率是指我们在一定的时间范围内,到底能处理多少事情。这里的“事情”,在计算机里就是处理的数据或者执行的程序指令。</p>
<p>和搬东西来做对比,如果我们的响应时间短,跑得快,我们可以来回多跑几趟多搬几趟。所以说,缩短程序的响应时间,一般来说都会提升吞吐率。</p>
<p>除了缩短响应时间,我们还有别的方法吗?当然有,比如说,我们还可以多找几个人一起来搬,这就类似现代的服务器都是 8 核、16 核的。人多力量大,同时处理数据,在单位时间内就可以处理更多数据,吞吐率自然也就上去了。</p>
<p>提升吞吐率的办法有很多。大部分时候,我们只要多加一些机器,多堆一些硬件就好了。但是响应时间的提升却没有那么容易,因为 CPU 的性能提升其实在 10 年前就处于“挤牙膏”的状态了,所以我们得慎重地来分析对待。下面我们具体来看。</p>
<p>我们一般把性能,定义成响应时间的倒数,也就是:</p>
<p>性能 = 1/ 响应时间</p>
<p>这样一来,响应时间越短,性能的数值就越大。同样一个程序,在 Intel 最新的 CPU Coffee Lake 上,只需要 30s 就能运行完成,而在 5 年前 CPU Sandy Bridge 上,需要 1min 才能完成。那么我们自然可以算出来Coffee Lake 的性能是 1/30Sandy Bridge 的性能是 1/60两个的性能比为 2。于是我们就可以说Coffee Lake 的性能是 Sandy Bridge 的 2 倍。</p>
<p>过去几年流行的手机跑分软件,就是把多个预设好的程序在手机上运行,然后根据运行需要的时间,算出一个分数来给出手机的性能评估。而在业界,各大 CPU 和服务器厂商组织了一个叫作<strong>SPEC</strong>Standard Performance Evaluation Corporation的第三方机构专门用来指定各种“跑分”的规则。</p>
<p><img src="assets/a50a6cb9d3df027aeda5ee8e53b75422.png" alt="img" /></p>
<p>一份 SPEC 报告通常包含了大量不同测试的评分</p>
<p>SPEC 提供的 CPU 基准测试程序,就好像 CPU 届的“高考”,通过数十个不同的计算程序,对于 CPU 的性能给出一个最终评分。这些程序丰富多彩,有编译器、解释器、视频压缩、人工智能国际象棋等等,涵盖了方方面面的应用场景。感兴趣的话,你可以点击<a href="https://www.spec.org/cpu2017/results/cpu2017.html">这个链接</a>看看。</p>
<h2>计算机的计时单位CPU 时钟</h2>
<p>虽然时间是一个很自然的用来衡量性能的指标,但是用时间来衡量时,有两个问题。</p>
<p><strong>第一个就是时间不“准”</strong>。如果用你自己随便写的一个程序,来统计程序运行的时间,每一次统计结果不会完全一样。有可能这一次花了 45ms下一次变成了 53ms。</p>
<p>为什么会不准呢?这里面有好几个原因。首先,我们统计时间是用类似于“掐秒表”一样,记录程序运行结束的时间减去程序开始运行的时间。这个时间也叫 Wall Clock Time 或者 Elapsed Time就是在运行程序期间挂在墙上的钟走掉的时间。</p>
<p>但是计算机可能同时运行着好多个程序CPU 实际上不停地在各个程序之间进行切换。在这些走掉的时间里面,很可能 CPU 切换去运行别的程序了。而且,有些程序在运行的时候,可能要从网络、硬盘去读取数据,要等网络和硬盘把数据读出来,给到内存和 CPU。所以说<strong>要想准确统计某个程序运行时间,进而去比较两个程序的实际性能,我们得把这些时间给刨除掉</strong></p>
<p>那这件事怎么实现呢Linux 下有一个叫 time 的命令,可以帮我们统计出来,同样的 Wall Clock Time 下,程序实际在 CPU 上到底花了多少时间。</p>
<p>我们简单运行一下 time 命令。它会返回三个值,第一个是<strong>real time</strong>,也就是我们说的 Wall Clock Time也就是运行程序整个过程中流逝掉的时间第二个是<strong>user time</strong>,也就是 CPU 在运行你的程序,在用户态运行指令的时间;第三个是<strong>sys time</strong>,是 CPU 在运行你的程序,在操作系统内核里运行指令的时间。而<strong>程序实际花费的 CPU 执行时间CPU Time就是 user time 加上 sys time</strong></p>
<pre><code>$ time seq 1000000 | wc -l
1000000
real 0m0.101s
user 0m0.031s
sys 0m0.016s
</code></pre>
<p>在我给的这个例子里,你可以看到,实际上程序用了 0.101s,但是 CPU time 只有 0.031+0.016 = 0.047s。运行程序的时间里,只有不到一半是实际花在这个程序上的。</p>
<p><img src="assets/0b340db019d7e389a2bde4c237ee4700.jpg" alt="img" /></p>
<p>程序实际占用的 CPU 时间一般比 Elapsed Time 要少不少</p>
<p><strong>其次,即使我们已经拿到了 CPU 时间,我们也不一定可以直接“比较”出两个程序的性能差异</strong>。即使在同一台计算机上CPU 可能满载运行也可能降频运行,降频运行的时候自然花的时间会多一些。</p>
<p>除了 CPU 之外,时间这个性能指标还会受到主板、内存这些其他相关硬件的影响。所以,我们需要对“时间”这个我们可以感知的指标进行拆解,把程序的 CPU 执行时间变成 CPU 时钟周期数CPU Cycles和 时钟周期时间Clock Cycle的乘积。</p>
<p>程序的 CPU 执行时间 =CPU 时钟周期数×时钟周期时间</p>
<p>我们先来理解一下什么是时钟周期时间。你在买电脑的时候,一定关注过 CPU 的主频。比如我手头的这台电脑就是 Intel Core-i7-7700HQ 2.8GHz,这里的 2.8GHz 就是电脑的主频Frequency/Clock Rate。这个 2.8GHz我们可以先粗浅地认为CPU 在 1 秒时间内,可以执行的简单指令的数量是 2.8G 条。</p>
<p>如果想要更准确一点描述,这个 2.8GHz 就代表,我们 CPU 的一个“钟表”能够识别出来的最小的时间间隔。就像我们挂在墙上的挂钟,都是“滴答滴答”一秒一秒地走,所以通过墙上的挂钟能够识别出来的最小时间单位就是秒。</p>
<p>而在 CPU 内部和我们平时戴的电子石英表类似有一个叫晶体振荡器Oscillator Crystal的东西简称为晶振。我们把晶振当成 CPU 内部的电子表来使用。晶振带来的每一次“滴答”,就是时钟周期时间。</p>
<p>在我这个 2.8GHz 的 CPU 上,这个时钟周期时间,就是 1/2.8G。我们的 CPU是按照这个“时钟”提示的时间来进行自己的操作。主频越高意味着这个表走得越快我们的 CPU 也就“被逼”着走得越快。</p>
<p>如果你自己组装过台式机的话,可能听说过“超频”这个概念,这说的其实就相当于把买回来的 CPU 内部的钟给调快了,于是 CPU 的计算跟着这个时钟的节奏也就自然变快了。当然这个快不是没有代价的CPU 跑得越快散热的压力也就越大。就和人一样超过生理极限CPU 就会崩溃了。</p>
<p>我们现在回到上面程序 CPU 执行时间的公式。</p>
<p>程序的 CPU 执行时间 =CPU 时钟周期数×时钟周期时间</p>
<p>最简单的提升性能方案,自然缩短时钟周期时间,也就是提升主频。换句话说,就是换一块好一点的 CPU。不过这个是我们这些软件工程师控制不了的事情所以我们就把目光挪到了乘法的另一个因子——CPU 时钟周期数上。如果能够减少程序需要的 CPU 时钟周期数量,一样能够提升程序性能。</p>
<p>对于 CPU 时钟周期数,我们可以再做一个分解,把它变成“指令数×<strong>每条指令的平均时钟周期数</strong>Cycles Per Instruction简称 CPI”。不同的指令需要的 Cycles 是不同的,加法和乘法都对应着一条 CPU 指令,但是乘法需要的 Cycles 就比加法要多,自然也就慢。在这样拆分了之后,我们的程序的 CPU 执行时间就可以变成这样三个部分的乘积。</p>
<p>程序的 CPU 执行时间 = 指令数×CPI×Clock Cycle Time</p>
<p>因此,如果我们想要解决性能问题,其实就是要优化这三者。</p>
<ol>
<li>时钟周期时间,就是计算机主频,这个取决于计算机硬件。我们所熟知的<a href="https://zh.wikipedia.org/wiki/摩尔定律">摩尔定律</a>就一直在不停地提高我们计算机的主频。比如说,我最早使用的 80386 主频只有 33MHz现在手头的笔记本电脑就有 2.8GHz,在主频层面,就提升了将近 100 倍。</li>
<li>每条指令的平均时钟周期数 CPI就是一条指令到底需要多少 CPU Cycle。在后面讲解 CPU 结构的时候,我们会看到,现代的 CPU 通过流水线技术Pipeline让一条指令需要的 CPU Cycle 尽可能地少。因此,对于 CPI 的优化,也是计算机组成和体系结构中的重要一环。</li>
<li>指令数,代表执行我们的程序到底需要多少条指令、用哪些指令。这个很多时候就把挑战交给了编译器。同样的代码,编译成计算机指令时候,就有各种不同的表示方式。</li>
</ol>
<p>我们可以把自己想象成一个 CPU坐在那里写程序。计算机主频就好像是你的打字速度打字越快你自然可以多写一点程序。CPI 相当于你在写程序的时候,熟悉各种快捷键,越是打同样的内容,需要敲击键盘的次数就越少。指令数相当于你的程序设计得够合理,同样的程序要写的代码行数就少。如果三者皆能实现,你自然可以很快地写出一个优秀的程序,你的“性能”从外面来看就是好的。</p>
<h2>总结延伸</h2>
<p>好了学完这一讲对“性能”这个名词你应该有了更清晰的认识。我主要对于“响应时间”这个性能指标进行抽丝剥茧拆解成了计算机时钟周期、CPI 以及指令数这三个独立的指标的乘积,并且为你指明了优化计算机性能的三条康庄大道。也就是,提升计算机主频,优化 CPU 设计使得在单个时钟周期内能够执行更多指令,以及通过编译器来减少需要的指令数。</p>
<p>在后面的几讲里面我会为你讲解具体怎么在电路硬件、CPU 设计,乃至指令设计层面,提升计算机的性能。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/深入浅出计算机组成原理/02 给你一张知识地图,计算机组成原理应该这么学.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/深入浅出计算机组成原理/04 穿越功耗墙,我们该从哪些方面提升“性能”?.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997a896d243cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>