H9

CPU 基础

点击正文段落选定收藏或划线位置;未选定时使用屏幕内第一段。

课内目录

学完本课,应当能够用取指、译码、执行、写回解释指令的基本路径;结合指令数、 和频率估算 CPU 执行时间;分清物理核心、硬件线程与云上 ;根据任务特征说明选型理由。这里建立的是可用于比较和估算的模型,具体机器的表现仍需要相同条件下的测量。

为什么关心 CPU:延迟与吞吐

假设某接口接收请求后,需要校验数据、计算结果并返回响应。用户最直接感受到的是从发出请求到收到结果所经过的时间,这叫响应时间,也常被称为请求延迟。运维人员还会关心服务每秒能够完成多少个请求,这叫吞吐量。延迟关注完成某个请求需要多久,吞吐量关注单位时间内完成多少工作,两者相关,但不能相互替代。

某服务只有一个工作线程,处理每个请求需要占用 CPU 10 ms。暂不计网络、存储和排队开销,它每秒最多完成约 100 个请求。如果增加独立工作线程,并且有足够的 CPU 执行资源,多个请求就可能同时推进,总吞吐量随之增加。然而,每个请求所需的计算并没有因此自动减少,单个请求仍可能需要接近 10 ms 的 CPU 时间。

当请求到达速度接近处理能力时,尚未执行的请求会在队列中等待。此时请求真正执行的时间可能变化不大,用户看到的响应时间却会明显增长。因此,报告性能时应当区分 CPU 执行、等待调度、等待输入输出和排队。只看到“接口很慢”,还不能认定需要更高主频;若主要时间花在等待数据库,CPU 升级带来的收益可能很小。

平均延迟也不能完整描述用户体验。把请求延迟从小到大排列,p99 表示约 99% 的请求延迟不超过的数值。少量请求等待过久,会让尾部延迟增大,即使平均值看上去仍然正常。面向交互的服务通常同时约束吞吐量和尾部延迟;批量处理则可能更重视在约定时间内完成全部工作。性能目标不同,适合的 CPU 配置也会不同。

延迟衡量单个请求的历时,吞吐量衡量单位时间完成量
延迟衡量单个请求的历时,吞吐量衡量单位时间完成量

图中的时间线提醒我们:请求的全部历时并不等于 CPU 忙碌的时间。评估算力之前,应先明确业务边界,例如只统计应用进程,还是统计从客户端到服务端的完整请求。比较不同方案时,还要使用相同的数据规模、到达负载和统计口径,否则吞吐增加可能只是因为请求变简单,延迟下降也可能只是因为测试流量变小。

指令如何走完:取指、译码、执行、写回

程序中的高级语言表达式需要经过编译或解释等处理,才能让处理器完成实际工作。CPU 面对的是其指令系统定义的机器指令。指令通常规定某种操作,以及操作数从哪里来、结果放到哪里去。操作数可能已经位于寄存器中,也可能需要从内存读取。寄存器是 CPU 内部保存少量当前工作数据的高速位置,与容纳大量程序和数据的内存有不同职责。

为了建立直觉,可以把某条普通算术指令理解为 4 个概念步骤。取指时,CPU 根据程序计数器所记录的位置取得指令;译码时,识别指令要求执行的操作和所需操作数;执行时,相关部件完成加法、比较或地址计算等工作;写回时,把产生的结果保存到指定位置。程序计数器随后指向后续应执行的指令,遇到跳转时,后续位置可能发生改变。

例如,假设寄存器中已经保存了数值 7 和 5,某条加法指令要求将它们相加并保存到另一个寄存器。取指得到的是这条指令的编码,译码确定加法与寄存器位置,执行产生 12,写回让后续指令能够使用结果。这里的 7、5 和 12 是数据,规定如何处理它们的编码是指令。把数据和指令区分开,有助于理解“程序很短”为什么不一定意味着运行很快。

普通算术指令从取指到写回的概念路径
普通算术指令从取指到写回的概念路径

动画使用寄存器加法演示数据位置变化。它按顺序突出各个步骤,是为了让读者看清每个步骤的职责,并不表示真实处理器总是完成一条指令后才开始下一条。现代 CPU 可以让多条指令的处理过程重叠;具体如何重叠、如何处理相关约束,留待后续课程讨论。本课不把动画中的每步对应为固定的一个时钟周期。

这个路径也有边界。读取内存的指令需要等待数据可用,存储指令要把数据送往存储层次,跳转指令影响后续取指位置,它们不必都经历完全相同的结果写回形式。某些指令完成得快,某些指令需要更多工作。讨论 CPU 性能时,不能仅统计源代码行数,也不能假定每条机器指令耗时相等。需要统计所研究任务实际执行了多少指令,以及这些指令整体推进得多快。

主频、周期与 IPC:把执行时间拆开

CPU 主频描述时钟的节奏,单位通常为 GHz。1 GHz 表示每秒约 10 亿个时钟周期;频率为 3 GHz 时,单个周期约为 0.333 ns。周期是描述处理器工作进展的时间尺度,但它并不是“完整指令”的同义词。知道每秒有多少周期,还需要知道每个周期平均完成多少有用工作,才能估算完成任务所需的时间。

IPC 是 Instructions Per Cycle 的缩写,表示平均每个时钟周期完成的指令数。设某段工作在统计范围内完成了 N 条指令、经过 C 个周期,则 IPC = N / C。IPC 可以小于 1,也可以大于 1。前者说明平均需要多个周期才完成一条指令,后者说明整体上每个周期平均可以完成多条指令;这与指令处理过程能够重叠有关,并不要求每条指令都在不足一个周期内独立完成。

对固定任务,基本关系可以写成:

CPU 执行时间 ≈ 指令数 /(平均 IPC × 平均频率)

分母的单位是“指令/周期 × 周期/秒”,即每秒完成的指令数。用总指令数除以它,得到秒。这里估算的是指定工作所需的 CPU 执行时间,通常不包含请求在队列中等待、等待磁盘或等待网络的全部历时。如果把性能定义为完成同样工作所需时间的倒数,那么性能约与 IPC × 频率 / 指令数成正比。不能把“时间越小越好”的公式直接称为“性能越大越好”的数值。

执行时间由指令数、平均 IPC 与平均频率共同决定
执行时间由指令数、平均 IPC 与平均频率共同决定

假设某段计算执行 12 亿条指令,平均 IPC 为 2,平均频率为 3 GHz。估算时间为 12 亿 /(2 × 30 亿),约 0.2 s。若只把频率提高到 4 GHz,并暂时保持指令数与 IPC 不变,时间约为 0.15 s。如果算法改进使指令数减半,即使频率不变,也可能得到更大的收益。这说明减少实际工作量与提高硬件执行能力,都能够影响结果。

这些因子并非永远独立。更换算法或编译方式可能同时改变指令数和 IPC;更换处理器可能改变运行频率与内存等待情况。IPC 是某个程序在某种环境下的测量结果,不是给 CPU 永久贴上的固定分数。比较不同指令系统时,指令所包含的工作也可能不同,不能只凭指令条数或 IPC 排名。对实际选型,更有意义的是同样业务输入下的完成时间、吞吐与资源成本。

多核与超线程:并行资源从哪里来

核心可以理解为 CPU 中能够执行指令流的计算单元。多核处理器包含多个这样的单元,操作系统可以把不同任务放到不同核心上运行。当多个任务在同一时刻分别使用不同执行资源推进时,称为并行。并发强调多个任务在某段时间内都得到推进;只有一个核心时,操作系统通过切换也能让多个任务并发进行,但它们未必在同一时刻执行指令。

程序中的线程是可被操作系统调度的执行流。硬件线程则是处理器向操作系统提供的执行上下文,两者不是同一个层次。操作系统可以管理远多于硬件线程数量的软件线程,并在可用资源上安排它们。软件线程多,并不意味着每个线程都能一直得到独占的核心;线程之间还可能等待彼此、等待数据,或竞争共享资源。

同时多线程技术通常称为 ,是其中常见的称呼。以每个核心支持 2 个硬件线程为例,一个核心向操作系统呈现 2 个可调度位置。每个硬件线程保留独立的程序计数器、寄存器状态等体系结构状态,从而承载不同的执行进度;但同一核心内的硬件线程会共享许多执行资源。它们不是把一个物理核心复制成 2 个完整核心。

不同物理核心通常各有自己的部分执行资源和私有缓存,同时也可能共享某级缓存、内存带宽、功耗预算等资源。具体共享范围取决于处理器设计,因此不能把“不同核心”理解为“互不影响”。同核心的硬件线程之间共享关系通常更紧密。如果某个线程等待数据,另一个线程有时可以利用空闲资源,提高总体利用率;如果 2 个线程同时争用已经饱和的执行资源,收益就可能很有限。

物理核心拥有执行资源,硬件线程在核心内部共享部分资源
物理核心拥有执行资源,硬件线程在核心内部共享部分资源

因此,8 核 16 线程规格通常表示 8 个物理核心提供了 16 个硬件执行上下文,并不等于 16 个完整物理核心。这个解释适用于所有核心都支持每核 2 个硬件线程的例子;遇到不同类型核心混合的设计,还需逐类计算线程数。规格中的线程数量也不是应用能够创建的软件线程上限。

增加核心要取得明显收益,还需要任务可以拆分。若某项工作有 20% 的时间必须串行完成,即使其余部分能理想地分给 4 个核心,总时间也约为原来的 0.2 + 0.8 / 4,即 0.4,约加速 2.5 倍。这里尚未计入任务分发、同步和数据搬运开销。串行部分越大,单纯增加核心越难继续缩短同一任务的完成时间;大量独立请求则可能更容易用多核提高总体吞吐。

滑块将核心数、IPC 和频率放入理想吞吐模型,让读者观察在假设成立时各个因子的作用。它不把超线程当作核心数的倍增项,也不预测具体处理器成绩。真实系统中,内存带宽、共享数据争用、串行代码与外部服务都可能先达到限制。观察曲线时,应始终同时阅读旁边的模型假设。

规格表怎么读:先确定字段含义

阅读规格表时,可以先确认核心组成,再看线程数和频率口径。某个假想处理器标注为 4 个性能核加 4 个能效核,其中性能核支持每核 2 个硬件线程,能效核支持每核 1 个硬件线程,那么总计是 8 个物理核心、12 个硬件线程。这里的计算展示了读取方法,不代表所有采用混合核心设计的产品都有相同配置。

性能核常记作 P 核,能效核常记作 E 核。它们体现不同的设计取向:前者通常更重视较强的单线程执行能力,后者通常更重视在面积和功耗约束下提供执行能力。能效核并非只负责后台任务,性能核也并非只负责前台任务。实际安排受到系统支持、软件特征和调度决策影响,本课只要求认识核心并不一定完全同质。

频率字段也要区分口径。基础频率是在厂商规定的条件与功耗约束下描述工作状态的参数,不能理解为每次采样都不会低于的绝对下限。睿频或动态加速频率描述处理器在温度、功耗、电流等条件允许时提高工作频率的能力。标注的最高频率可能只适用于部分核心的特定条件,不能据此假设所有核心在长时间满载时都维持同样频率。

规格字段需要连同核心组成和频率适用条件一起阅读
规格字段需要连同核心组成和频率适用条件一起阅读

例如,轻负载下的某个线程可能观察到较高频率,而全部核心持续运行时的平均频率较低。这种变化本身并不说明故障。估算长时间批处理能力,应参考可持续负载下的测量;评估短时交互任务,则应使用有代表性的请求和并发条件。比较时还要记录散热、电源设置和虚拟化条件,否则相同型号也可能表现不同。

缓存容量是另一个常见字段。缓存用来保存近期可能继续使用的数据或指令,帮助减少访问更远存储位置的等待。容量、层级、各核心是否共享以及访问行为都会影响收益;不能把所有缓存容量相加后,直接据此判断速度。H10 会进一步解释存储层次。在这里,只需把缓存看作影响实际 IPC 的因素之一,并知道“缓存更大”不等于任何工作负载都更快。

Linux 上的只读观察:lscpu 与 /sys

规格表说明产品宣称的能力,操作系统观察说明当前环境看到了什么。在 Linux 上,lscpu 会汇总处理器与拓扑信息。它可以帮助识别体系结构、逻辑 CPU 数量、每核线程数、每插槽核心数,以及系统是否处于虚拟化环境。不同发行版、工具版本和架构的字段可能不同,应按字段含义阅读,不能要求所有机器都打印同一份表格。

lscpu
lscpu -e=CPU,CORE,SOCKET,ONLINE
cat /sys/devices/system/cpu/online
cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

这些命令仅用于观察。最后几个路径属于 Linux 的 sysfs 接口,实际是否存在取决于内核、驱动与虚拟化环境。online 描述系统在线的逻辑 CPU 编号范围,例如 0-7 表示编号从 0 到 7 的 8 个逻辑 CPU。thread_siblings_list 描述与指定逻辑 CPU 属于同一核心的线程兄弟;在典型 SMT 拓扑下,列表中的多个编号对应共享该核心的硬件线程。

扩展表中的 CPU 是逻辑 CPU 编号,CORE 是核心标识,SOCKET 是插槽标识。核心编号可能在不同插槽内重复,判断物理核心时应结合插槽与核心标识。在每核线程数一致的普通裸机上,可以用插槽数、每插槽核心数和每核线程数交叉检查总量;对于混合核心、离线 CPU 或虚拟机,应进一步查看逐项信息,避免机械相乘。

例如,在普通裸机上,若 CPU 0 的 thread_siblings_list 为 0,4,就表示逻辑 CPU 0 与 4 属于同一个物理核心。把 2 个持续计算的工作线程分别绑定到这 2 个编号,仍会让它们争用同一核心的执行资源;编号不同并不保证获得 2 个核心的计算能力。如果某次绑核后吞吐没有预期增长,应先核对兄弟关系,再比较使用不同物理核心时的结果。也不能假定编号相邻就属于同一核心,编号分配需要以当前机器报告的拓扑为依据。

scaling_cur_freq 通常以 kHz 为单位报告频率相关信息,但它的数值含义与更新方式取决于驱动,不能视作任意时间窗口内的精确实际执行频率。没有这个路径也不等于 CPU 不支持变频。读取它的目的,是认识当前状态可能与规格中的最高频率不同,不要求据此修改系统配置,更不能用某次采样替代业务测量。

虚拟机展示的核心与插槽拓扑可能是虚拟拓扑,容器看到的在线 CPU 集合也可能大于允许使用的算力。容器的 CPU 配额与可运行 CPU 范围还会约束实际使用能力;例如看到 8 个编号,不保证能够持续占用 8 个核心。每次观察应记录运行位置、可见拓扑和资源限制,再与应用指标对应。处理器利用率能够提示忙碌程度,但不直接说明完成了多少业务工作,也不能单独作为处理器性能排名。

常见误区:主频、线程数与 vCPU

“线程数翻倍,性能就翻倍”混淆了软件线程、硬件线程和物理核心。增加软件线程可能利用原有的空闲资源,也可能只增加调度与同步成本。开启 SMT 增加的是可承载的硬件线程上下文,同核心执行能力仍受共享资源限制。线程增加后,某个请求的完成时间也可能上升,因此还应观察满足延迟约束时能够承受的负载。

云上 vCPU 是实例向用户提供的虚拟处理器资源单位。许多平台将一个 vCPU 对应到某个硬件线程,也有平台按物理核心或特定架构方式提供资源。实例页面中相同的 vCPU 数量,不能保证相同的物理核心数量、每核能力和持续计算能力。阅读规格时,应检查该实例系列对 vCPU 的定义、处理器代际、是否提供专用资源,以及是否采用突发额度等约束。

虚拟机中的某个 vCPU 还需要获得宿主机的执行时间。共享宿主环境下,其他虚拟机争用资源可能使它等待。Linux 中常用 steal time 提示这种被宿主环境占用的等待时间,但能否准确观察取决于平台。不能仅凭延迟上升就判定发生挤占,也不能因某项指标没有上报就断言不存在争用。需要把来宾系统指标、平台说明与业务测量结合起来。

还有一种误区是“CPU 利用率未到 100%,CPU 就没有瓶颈”。若一个关键线程已经占满某个核心,其余核心闲置,整机平均利用率仍可能较低。此时增加相同能力的核心不一定加快该线程。应结合各线程或各逻辑 CPU 的使用情况、请求等待位置与任务拆分方式,判断是单线程执行能力不足,还是并行资源总量不足。

把名称换算成可核对的量。同样标注 8 个 vCPU 的两台实例,一台绑定 8 个物理核心,另一台在争用池里共享执行槽;用同一段单线程计算循环测墙钟时间,前者可能稳定在约 1.0× 基准,后者在同宿主机忙时落到 1.4×~2.0×。若业务目标是 500 请求/秒且单请求需 2 ms CPU,名义上约需 1 个持续核心的执行量,但把“8 vCPU”直接写成“可扛 4000 请求/秒”会忽略 IPC、超线程与共享。规格表上的线程数或 vCPU 只是资源入口,验收必须以目标负载下的延迟与 CPU 时间为准。

案例:把规格差异换成业务结果

先比较 2 个同为 3 GHz 的处理器在某段单线程计算上的表现。为了只观察 IPC 差异,假设它们执行同样的 18 亿条指令,测得平均 IPC 分别为 1.5 和 2。前者估算需要 0.4 s,后者约 0.3 s。后者时间减少约 25%,完成同样任务的速率提高约 33%。这 2 个百分比的分母不同,应在报告中明确究竟比较时间还是速率。

这组数值不证明后者对所有应用都更快。若更换任务后频繁等待数据,平均 IPC 可能同时下降;若编译目标不同,指令数也可能改变。实际比较应先选取有代表性的业务输入,保证输出正确,再记录完成时间和资源配置。公式用于解释可能原因,测得的业务结果用于判断选型是否满足目标,两者相互支持。

再看 SMT 的例子。某台 8 核机器运行一个具有充足独立请求的服务,测试关闭 SMT 和开启 SMT 这 2 种配置。假设在相同到达负载 600 请求/秒下,前者的 p99 为 28 ms,后者为 35 ms,两者都满足 40 ms 的目标。提高负载后,再分别寻找仍能满足目标的最大持续完成量,得到关闭时约 800 请求/秒、开启时约 920 请求/秒。

在相同负载下比较尾延迟,在相同延迟目标下比较容量
在相同负载下比较尾延迟,在相同延迟目标下比较容量

这意味着在这组假设结果中,开启 SMT 使目标范围内的吞吐容量提高约 15%,同时在共同负载点观察到尾延迟上升。不能把它描述为“线程翻倍所以性能翻倍”,也不能用不同负载下的 p99 直接证明线程间竞争。要比较延迟,应固定请求到达负载;要比较可用容量,应固定延迟目标和错误率要求。这些口径必须先写清楚。

上述数值仅用于演示解释方法,不是通用测试结论。真实测试还应使请求组成、缓存预热、软件线程配置、数据规模和运行时长具有可比性,并重复观察波动。若某个应用的紧迫目标是更低尾延迟,关闭 SMT 后的配置可能更合适;若目标是达到延迟要求的同时处理更多独立请求,开启 SMT 可能更有价值。最终选择取决于自己的测量,而不是规格字段的数量大小。

放进方案里

容量不能直接按平均工作量配置。若在已经验证的负载范围内,希望正常运行时平均只使用约 50% 的有效执行能力,上述估算对应约 4 个核心当量;突发请求、请求成本波动和依赖服务变化仍需压测确认。这里的核心当量是以测量机器为参照的算力需求,不能直接改写成任意云平台的 4 vCPU。实例系列变化后,应重新验证单位资源的实际处理能力。

选择云实例时,应在方案里注明 vCPU 的平台定义、处理器类型、是否共享或受突发额度限制,并记录代表性负载下的吞吐与尾延迟。多核能够分摊独立请求,但串行计算仍取决于单线程能力;若关键路径被某个线程限制,就应优先评估算法改进、任务拆分或更强的单线程配置,不能只通过增加实例核心数承诺加速。

把这些判断写成非功能需求,即 NFR:给定数据规模和请求组成,在持续 500 请求/秒的到达负载下,p99 响应时间不超过 50 ms,并同时满足事先约定的错误率要求。再说明关键串行阶段的 CPU 时间预算、容量余量和验证环境。交付时用相同口径复测,并记录处理器、软件版本与资源限制。这样,规格表中的数字才成为能够追踪、验证和修订的容量依据。

从业务目标、CPU 时间估算到实例验证的方案路径
从业务目标、CPU 时间估算到实例验证的方案路径

小结:从 CPU 走向存储层次与线程

CPU 的基本任务可以通过取指、译码、执行、写回理解,主频刻画周期节奏,IPC 描述平均每周期完成多少指令。固定任务的 CPU 执行时间由指令数、平均 IPC 与平均频率共同决定。这个关系既能解释硬件差异,也提醒我们算法和软件实现会改变所需工作量;它描述 CPU 执行,并不直接等于完整请求延迟。

多核提供更多执行资源,SMT 让同一核心承载多个硬件线程,软件线程则由操作系统安排运行。规格中的核心数、线程数、频率与缓存都有明确的适用条件,云上 vCPU 还受到平台资源定义和分配方式影响。读懂这些字段的目的,是建立可测量的性能预期,并判断新增资源能否作用于真正的瓶颈。

后续 H10 将解释数据为什么有时能很快到达 CPU,有时却需要较长等待,从存储层次角度继续理解实际 IPC。S2 将进一步说明进程与线程如何组织执行工作,澄清软件执行流与硬件执行资源的联系。带着本课的延迟、吞吐与执行时间模型,就可以把这些机制放回同一个业务请求中理解。

下一课转向 H10 存储层次:把本章验收过的结论带进后续主题,写成可检查的方案约束。

同阶段相关课

AI 答疑

默认关闭。启用后,只发送本课标题、最近阅读的屏幕内正文摘录(最多 6000 字)与本次问题。

配置自己的服务