Moj*_*abi 8 kernel sleep system-calls linux-kernel cpu-architecture
我正在尝试学习操作系统概念。这是两个简单的Python代码:
while True:
pass
Run Code Online (Sandbox Code Playgroud)
和这个:
from time import sleep
while True:
sleep(0.00000001)
Run Code Online (Sandbox Code Playgroud)
问题:为什么运行第一个代码时 CPU 使用率为 100%,但运行第二个代码时 CPU 使用率约为 1% 到 2%?我知道这可能听起来很愚蠢,但为什么我们不能实施类似的事情sleep
在不使用睡眠系统调用的情况下实现用户空间模式之类的东西?
注意:我试图理解Linux 内核的睡眠系统调用,但说实话我不明白那里发生了什么。我还搜索了 NOP 汇编代码,结果发现它并不是真的什么都不做做,而是做了一些无用的事情(比如 xchg eax、eax),也许这就是 100% CPU 使用率的原因。但我不确定。
究竟有哪些睡眠系统调用的汇编代码是我们无法在用户空间模式下执行的?是不是类似 HLT 的东西
我还尝试HLT
在代码中使用汇编,如下所示:
section .text
global _start
_start:
hlt
halter:
jmp _start
section .data
msg db 'Hello world',0xa
len equ $ - msg
Run Code Online (Sandbox Code Playgroud)
但运行此代码后,我看到内核一般保护错误如下:
[15499.991751] traps: hello[22512] general protection fault ip:401000 sp:7ffda4e83980 error:0 in hello[401000+1000]
Run Code Online (Sandbox Code Playgroud)
不知道是不是和保护环有关,或者是我的代码错误?这里的另一个问题是操作系统是否在系统HLT
调用下使用或其他受保护的汇编命令sleep
?
dir*_*rkt 16
为什么运行第一个代码时 CPU 使用率为 100%,但运行第二个代码时 CPU 使用率约为 1% 到 2%?
因为第一个是“繁忙循环”:您始终在执行代码。第二个告诉操作系统该特定进程想要暂停(睡眠),因此操作系统取消调度该进程,如果没有其他进程正在使用 CPU,则 CPU 会变得空闲。
我还搜索了 NOP 汇编代码,结果发现它并不是真的什么都不做
好吧,NOP = 无操作:它正在主动执行没有效果的代码。您可以使用它来填充代码,但不能将 CPU 置于低功耗状态。
究竟有哪些睡眠系统调用的汇编代码是我们无法在用户空间模式下执行的?
x86 CPU 上的现代操作系统使用mwait
. 其他 CPU 架构使用其他命令。
但运行此代码后,我看到像这样的内核一般保护错误
这是因为操作系统应该在管理员模式下执行此操作。正如我上面所写,操作系统需要能够保持调度进程,因此进程本身不允许将 CPU 置于空闲模式。
这里的另一个问题是操作系统在睡眠系统调用下使用 HLT 或其他受保护的汇编命令
是的,它确实。虽然它不是在睡眠调用期间执行,而是在调度程序循环内执行,当调度程序检测到没有要运行的进程时。
第一部分的一个问题。如果我使用很少的时间段,即:
sleep(0.0000000000000001)
调度程序是否仍然进入下一个进程?
对于实际的操作系统系统调用,请参阅man 3 sleep
(以秒为单位的分辨率)、man usleep
(以微秒为单位的分辨率)和man nanosleep
(以纳秒为单位的分辨率)。
无论您在 python 代码中使用什么浮点数,都不会比 python 使用的系统调用(无论它是什么变体)获得更好的分辨率。
联机帮助页说“将调用线程的执行暂停(至少)usec 微秒”。等等,所以我假设即使延迟为零(然后立即重新安排)它也会被取消调度,但我没有测试这一点,也没有阅读内核代码。。
操作系统的“CPU 使用率”测量基于用户空间进程/线程(任务)是否在 CPU 上运行,即使这些指令只是浪费时间。如果任务不使用 CPU 时间,则意味着操作系统可能正在运行其他任务。
当用户空间忙等待时,情况并非如此,即使它可以强制 CPU 进入低功耗状态。CPU 电源状态无关紧要,正如 marcelm 评论的那样:重要的是您是否告诉操作系统该任务应该休眠。如果没有其他任务,操作系统可以让 CPU 进入睡眠状态。
即使是 x86pause
指令也不允许操作系统在 CPU 上调度不同的任务。tpause
最近的或umonitor
/也不会umwait
,尽管它们可以将 CPU 置于 C0.1 或 C0.2 省电状态。
在 x86-64中nop
也是真正的 NOP,没有后端执行单元。xchg eax,eax
在64位模式下不是NOP,它将EAX零扩展为RAX,因此它不能0x90
在64位模式下使用编码,只能在16位或32位模式下使用。这就是为什么在Intel手册中nop
有自己的条目。当然,即使在 32 位模式下,现代 CPU 也会将0x90
其与其他长 nop 操作码一起识别为无操作和特殊情况。
但同样,这不是相关的事情,CPU 使用率是关于 CPU 是否可以进入省电状态或运行其他东西,因为内核知道这个进程没有任何东西可以运行。
hlt
是一条特权指令(仅在环 0 中有效,又名 CPL=0,如您在Intel 的手动条目例外中看到的:#GP(0) 如果当前特权级别不为 0。
用户空间无法让 CPU 进入睡眠状态,直到下一个中断到来为止,只有内核可以做到这一点(如果调度程序决定在该用户空间任务执行期间没有其他事情可做sleep
)。
或者直到 WAITPKG CPU 功能(Tremont 和 Alder Lake)为止,尽管umwait
让内核为用户空间启动的睡眠设置持续时间限制,以便操作系统可以限制用户空间的睡眠时间不那么长。而且它们的睡眠深度受到限制,甚至比hlt
(C1) 还浅,这对于唤醒延迟很重要。也许实时操作系统知道某个关键中断即将到来,并希望 CPU 没有任何额外的唤醒延迟。或者不想让任何事情让 CPU 进入睡眠状态。(umwait
控制知道内核要设置,hlt
但不知道。)
不过,用户空间可能会浪费 CPU 时间,直到下一次中断为止,这是抢占式多任务内核重新获得 CPU 控制权的唯一方法,除非用户空间发生系统调用或 CPU 异常。(也许像这样的系统调用yield()
专门用于提示操作系统上下文切换到等待空闲 CPU 核心的其他任务。)
跨站重复:
以及相关问答:
/sf/ask/4087022971/(NOP不消耗固定的时间。输出阶超标量 CPU 对于每条线性相加的指令没有单独的成本)
这个问题IMO属于Stack Overflow,带有标签[程序集][操作系统][x86][CPU架构]。至少那里更适合;unix.SE 主要是关于使用它,而不是操作系统理论/概念。
如果可能的话,不要使用大量的微小睡眠,而是使用poll
或select
等待文件描述符上的活动。然后您的进程(和 CPU)可以保持睡眠状态,而不是不断醒来进行另一个系统调用。
如果您要忙等待,在该循环中放入睡眠会减轻其糟糕程度,但与睡眠或阻塞相比,操作系统会在有事情要做时唤醒您,这仍然不是很好。
打个比方,想象一下人们在银行排队等候的过程。 银行出纳员是CPU,他们执行客户(进程)的请求。
sleep()
就像离开出纳员并坐在椅子上,在指定的时间后重新排队。(如果大多数人都这样做,该行通常是空的:CPU 空闲,因此新任务可以立即运行)。(与真正的银行不同,先发制人的多任务处理涉及柜员强迫客户走到队伍后面,即使他们还没有完成他们想做的所有事情。)
归档时间: |
|
查看次数: |
2481 次 |
最近记录: |