问一些对虚拟化的认知: ESXi 的虚拟化把一个不支持多线程的程序的负载均匀分布在多个处理器上

2022-07-05 00:08:40 +08:00
 phpfpm

感觉好牛逼啊

找了一个比较简单无脑的程序测一下单核性能:

echo scale=5000; 4*a(1) | bc -l -q

用的是 windows 版的二进制的 bc 的 bin(GNU),这个性能不是很好,但是横评比较方便。

结果大概是这样:

	        时间	 主频
            
i5 2500k	23.48	3.3

e5 2630	        29.5	2.3

i5 6200U	26.76	2.4

e3 1231v3	21.02	3.4

基本上,耗时的秒数( s) x 主频(GHz) = 80G

所以能拿到的一些基本认知:

  1. ESXi 的虚拟化,如果节点运行的是没有给多 CPU 优化的程序,可以通过虚拟化的层面调度到多个 CPU
  2. 单个线性程序仍然不能并行,运行的时间和单核主频负相关
  3. 衡量虚拟化物理机的 cpu 容量用主频 x 物理核数是合理的
  4. 超线程似乎在虚拟化这边用处不大,虚拟化相当于是一个横跨多核的超线程(?)
  5. 当然,要跑得快,主频还是得要高

想问下这些理解对不对呢?谢谢

1391 次点击
所在节点    问与答
19 条回复
msg7086
2022-07-05 00:30:51 +08:00
调度到多个核心不需要虚拟化,操作系统的线程调度就可以做到。

核心之间的调度需要考虑到 CPU 内缓存命中的问题和单核 Turbo 性能的问题。
比如说跨 NUMA 调度,跨 CCX 调度等等。
Turbo 的话,根据 CPU governor 的不同,频率切换速度也不同。比如单核 5G 然后其他核 4G ,调度到别的核心后,需要把 5G 的核心降速,4G 的核心提速。来回切换的速度会影响运行效率。所以有些单核应用,锁核心以后运行速度会大幅提高。
phpfpm
2022-07-05 00:33:40 +08:00
@msg7086 但是如果一个单线程的程序,没有任何多核优化的,也能调度到多个 cpu 么?
msg7086
2022-07-05 00:56:57 +08:00
@phpfpm 现在的操作系统内核本来就是按时间片分配资源,不会绑定到核心的。
单线程程序在运行的时候,同一时间只会问操作系统要一份时间片。操作系统随机分配某个核心的一段时间给程序执行。优化过的线程调度器可能会更偏向于把同一个核心分给同一个线程,但并不是硬性要求。
有些调度器可能会故意分散压力来降低 CPU 温度;有些则会故意集中压力来提高运行性能。
不管是哪种情况,一个线程都不需要运行在同一个核心上。
LeeReamond
2022-07-05 01:10:24 +08:00
不是很理解 lz 描述的没有给"多 cpu 优化"的可以通过虚拟化解决,以及单线程还是单线程
phpfpm
2022-07-05 01:15:33 +08:00
@msg7086
@LeeReamond

我懂了。。。
之前一直以为一个单线程的程序一定始终绑定固定的内核。
GeruzoniAnsasu
2022-07-05 01:29:47 +08:00
几乎没有对的……

单线程程序你可以理解为无论有多少个 CPU 都只能利用其中一个,用哪个 CPU 不是程序决定的,是 OS 决定的。在过去 OS 就是 OS 内核本身;虚拟化时代,所有的现代 OS 都有 hypervisor+内核两部分,在虚拟机中运行时 OS 能检测硬件环境以决定使用自己的 hypervisor 还是虚拟化环境里的。exsi 只有 hypervisor ,没有 OS 内核,而例如 windows 则既有内核(传统的 windows 内核)也有 hypervisor ( hyper-v ,当你启用 hyper-v 组件的时候 windows 会把自己也交给 hyper-v 调度)

超线程是硬件层面的线程机制,打个比方切换线程时要保存上下文,上下文里包括算数寄存器、内存指针(栈寄存器)、程序指针( PC )之类的值,软件实现的机制是 OS kernel 打断用户程序的执行然后把这些寄存器的值找块内存放起来,而硬件实现则可以直接换一组寄存器给线程使用。CPU 体系结构里有个概念叫 register file ,x86 cpu 算数寄存器大概 10 几个,但是算数寄存器的 registry file 有上百个大,也就是说 CPU 内部能保存十几个同一寄存器值的副本随时切换。当你软件切换线程上下文还在等内存写入的时候硬件只需要换一下寄存器映射几乎瞬间就完成了,这就是超线程加速的基本原理。

然后再说说主频问题,商用 CPU 和个人终端产品 CPU 在功耗、性能调度上会有很大区别,并不能简单地认为主频越高越快。主频越高能带来更短的指令周期,但内存延迟、睿频、流水线长度、功耗控制……即使不考虑多核性能,都仍有非常多变量因素产生影响。 只能说控制单一变量只有主频变化的时候程序执行时间与主频负相关,但这是正确的废话
phpfpm
2022-07-05 09:30:31 +08:00
@GeruzoniAnsasu 是,其他我也都理解也都认同
但是你和
@msg7086
@LeeReamond

两位的发言在一个地方的认知还是不太一样:


打个比方,我写一个程序,跑 1e9 次空 loop (假设不被优化掉)

这种简单的程序是一定会固定在一个逻辑内核跑,还是会调度到多个内核上面?
你说的利用其中一个,是某一个特定的,还是说一个那么多的资源?
sujin190
2022-07-05 09:41:18 +08:00
@phpfpm #7 最大问题,“会被调度到多个核心”和“会被调度到多个核心上并行执行”是两回事,前者并不能提高性能,对于后者来说,既然你程序已经多核不支持并行那么后者并不能超过你程序实现来通过调度实现,有没有虚拟化都不能
GeruzoniAnsasu
2022-07-05 10:20:57 +08:00
@phpfpm

用户程序在哪个 cpu 上跑会取决于 os 内核的调度,而 os 会选择线程 affinity 指定的 cpu 来执行,但无论如何一个单线程程序同时只会有一个 cpu 在跑它的代码,因此固定在一个 cpu 上与调度到不同 cpu 上(从程序视角来看)并没有区别


不过一般都倾向直接选择第一个 cpu 来运行
phpfpm
2022-07-05 10:22:50 +08:00
@sujin190 是,我能区分出来调度和并行的区别。

一个 1e9 的空 loop 不管怎么调度都要串行的完成所有的循环,时间不会减少(甚至因为上下文切换导致性能劣化)

但是我在感慨(惊叹)或者说困惑的点是,如果一个原生不支持多线程,就在一个线程(一个核心)跑到天荒地老的程序(其实还是挺多的,比如某些游戏的服务端,上古时期),能被操作系统——或者虚拟化,均匀调度到所有 cpu 上分散执行(性能肯定过剩但是至少不浪费),这大大提升了资源的利用率。


打个比方,一个 4c 的机器,有一个程序一定能打满了一个核——那么无论调度不调度,资源只够跑四个这样的程序的的。
但是开启了调度之后,如果我们跑一个这样的程序,相当于每个核心只消耗 25~30%的资源,给其他多线程程序有更好的调度空间——这就很香了吧?

所以对于单线程程序的跨核心的调度,是操作系统做的,还是虚拟化层面做的呢?
phpfpm
2022-07-05 10:25:07 +08:00
@GeruzoniAnsasu 赞,那这样说我可以理解了,现在的操作系统比我想象中牛逼多了。
我这边有一个 php 写的队列处理任务,计算量比较大,但是看 top 的时候会发现这个任务始终只占用一个核心的资源,另外一个始终是 0 在围观。

所以这个切换不切换,不同操作系统的处理不一样吧?
感觉 windows 更均匀一些,但是 linux 会尽量固定?
sujin190
2022-07-05 10:51:09 +08:00
@phpfpm #10 两者都要做吧,否则万一你操作系统有 bug 或者本身就是恶意操作系统那岂不是提供虚拟化的宿主机都要挂了,比如阿里云这种一台物理机虚拟好几百台万一你买的那台其他虚拟机有人干坏事你担心?程序对操作系统也是一样的,操作系统和虚拟化一般不会均匀调度,只要有可能还是优先放在相同 cpu 的,毕竟可以提高状态、缓存、中断相关效率
liaohongxing
2022-07-05 10:51:56 +08:00
php 就别拿来说了,连多线程都没有 ,最多 fork 起一个进程, 一个进程要是计算密集型, 基本都是分配给一个 cpu 核, 可能会轮换其他核。

归根结底 没有多线程 ,就算多进程 php 也没有 ipc 通信 。够呛
phpfpm
2022-07-05 11:19:10 +08:00
@liaohongxing 不不不,我的点在于——有一些程序,不是自己写的,就是活生生都不支持多线程,想优化也没办法,我自己写的程序我肯定知道是不是多线程的——如果操作系统能做到多核调度就牛逼了。

@sujin190 但是分配给虚拟机的 cpu 数量是限制的,给你 2 vcore ,最多占据宿主机的 2c 的算力,再多就不分配了啊。。。。
sujin190
2022-07-05 12:00:04 +08:00
@phpfpm #14 操作系统也可以限制某个进程的 cpu 使用率的,本质上两者没啥区别
phpfpm
2022-07-05 12:18:31 +08:00
@sujin190 嗯。。是。。

所以说,我大概理解了——跨 cpu 调度一个单线程的程序是 trival 的——反正多任务调度的时候就是得让出执行资源执行别的,等回来的时候回到哪个核,操作系统说了算。
msg7086
2022-07-06 00:57:27 +08:00
@phpfpm #10

「打个比方,一个 4c 的机器,有一个程序一定能打满了一个核——那么无论调度不调度,资源只够跑四个这样的程序的的。但是开启了调度之后,如果我们跑一个这样的程序,相当于每个核心只消耗 25~30%的资源,给其他多线程程序有更好的调度空间——这就很香了吧?」

没太大的区别。算力是一样的,一定要说区别的话就是延迟。并行执行比顺序执行延迟低一些,但是基本可以忽略不计。
现代操作系统里 CPU 算力资源本质上是时间片,总时间片不变,算力就不会变,就算不分散到多核执行也不会有区别。

4 核的机器就算打满了一个核,剩下的 3 核也足够支持一个 4 线程的程序运行,而且剩下的算力是 300%。
如果分散开,每个核心只消耗 25%的资源,剩下 4 个 75%核,算力加起来还是 300%。
最终运行速度不会有太大的变化。
phpfpm
2022-07-06 10:08:52 +08:00
@msg7086 所以在我的认知里面,我以为单线程程序只会在一个 cpu 调度,无论是操作系统层面还是 cpu 层面都是这样。
非常感谢你的答疑解惑!

想问下,这个现代操作系统的 CPU 调度是从什么时代开始的? windows/linux 系
真的没有我说的单独绑定死 cpu 的么。。
msg7086
2022-07-06 17:22:52 +08:00
@phpfpm 从计算机有了多核支持以后吧。
古代的家用计算机都是单核的,有多路 CPU 设计但主要是给服务器用的,民用支持多 CPU 好像是 NT4 那个年代开始的吧(叫 SMP ),但是真正有双核 CPU 卖还是很久以后的事情了,Athlon x2 什么的(记忆模糊了)。

操作系统应该很早就支持了,毕竟操作系统管理的是时间片,100%时间片和 200%时间片没有太大的区别。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/864077

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX