下面,我就来分析一下psutil是怎样计算CPU的使用率的。
简单介绍一下psutil,psutil是一个python获取当前系统资源的第三方模块,可以跨平台的获取系统的各方面资源。
psutil获取系统cpu使用率的方法是cpu_percent(),其有两个参数,分别是interval和percpu,interval指定的是计算cpu使用率的时间间隔,percpu则指定是选择总的使用率还是每个cpu的使用率
描述系统cpu使用情况主要有一下几点:
user 从系统启动到现在,CPU处于用户态的运行时间。不包含nice值为负的进程。
nice 从系统启动到现在,CPUnice为负值的进程占用的cpu时间
system 从系统启动到现在,CPU处于内核态的运行时间
idle 从系统启动到现在,CPU除了 iowait外的等待时间
iowait 从系统启动到现在,CPUio 等待时间
irq 从系统启动到现在,CPU硬中断花费的时间
softirq 从系统启动到现在,CPU软中断花费的时间
steal 从系统启动到现在,CPU运行其他虚拟环境中的操作系统花费的时间
guest 从系统启动到现在,CPU运行在通过Linux内核控制的客户操作系统上的虚拟cpu的时间
guest_nice 从系统启动到现在,CPU运行在通过Linux内核控制的客户操作系统上的虚拟cpu的时间, nice 为负值进程
知道了以上参数的意思,计算某段时间内的cpu使用率就不难,由于cpu资源是在高速的变化,于是计算cpu使用率只能是在一段时间内的,设置两个时间点为t1和t2,
CPU在t1和t2时间内总的使用时间:( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2 + steal2 + guest2 + guest_nice2 ) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1 + steal1 + guest1 + guest_nice1)
CPU的空闲时间:(idle2 -idle1)
CPU在t1和t2时间内的使用率=CPU非空闲时间/CPU总时间*100%=(1-CPU的空闲时间/CPU总时间)*100%
则:
CPU(t1,t2)使用率:1-(idle2-idle1)/(( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2 + steal2 + guest2 + guest_nice2 ) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1 + steal1 + guest1 + guest_nice1))
简单了解了使用率的计算方法,下面我们看一下cpu_percent是怎样实现的
def cpu_percent(interval=None, percpu=False):
"""Return a float representing the current system-wide utilization as a percentage.
返回一个当前系统cpu使用率的百分比结果,
When interval is > 0.0 compares system CPU times elapsed before
and after the interval (blocking).
当interval大于0.0时,返回的是在这段时间内CUP的使用率
When interval is 0.0 or None compares system CPU times elapsed
since last call or module import, returning immediately (non
blocking). That means the first time this is called it will
return a meaningless 0.0 value which you should ignore.
In this case is recommended for accuracy that this function be
called with at least 0.1 seconds between calls.
当interval是0.0或者是None时,系统在调用此模块后,还没来得及运行就立即返回了,返回的是没有任何意义的0,你应该忽略调这个值,为避免这种情况,为了准确,调用这个模块时间至少为0.1秒
When percpu is True returns a list of floats representing the
utilization as a percentage for each CPU.
First element of the list refers to first CPU, second element
to second CPU and so on.
The order of the list is consistent across calls.
当percpu的值为True时,则返回的是一个列表,里面包含每个CPU在该段时间内的CPU使用率
Examples:
>>> # blocking, system-wide
>>> psutil.cpu_percent(interval=1)
2.0
>>>
>>> # blocking, per-cpu
>>> psutil.cpu_percent(interval=1, percpu=True)
[2.0, 1.0]
>>>
>>> # non-blocking (percentage since last call)
>>> psutil.cpu_percent(interval=None)
2.9
>>>
"""
global _last_cpu_times #全局变量,用于表示上一个时间点cpu的各项参数,用于和下一个时间点cpu各项参数进行计算
global _last_per_cpu_times #全局变量,用于表示上一个时间点,各个cpu在上一个时间点的各项cpu参数,作用同上
blocking = interval is not None and interval > 0.0 #判断interval的值,如果interval 不为空且大余0.0,则blocking值为真,否则为假
def calculate(t1, t2): #计算CPU使用率
t1_all = sum(t1) #计算t1时间,cpu的使用时间,为各项参数的和
t1_busy = t1_all - t1.idle #计算cpu的非空闲时间
t2_all = sum(t2) #计算t1时间,cpu的使用时间,为各项参数的和
t2_busy = t2_all - t2.idle #计算cpu的非空闲时间
# this usually indicates a float precision issue
if t2_busy <= t1_busy: #如果t2时刻的非空闲时间小余t1时刻的,则直接返回0.0
return 0.0
busy_delta = t2_busy - t1_busy #计算t1-t2时间段内CPU总的非空闲时间
all_delta = t2_all - t1_all #计算t1-t2时间段内CPU总的使用时间
busy_perc = (busy_delta / all_delta) * 100 #计算t1-t2时间段内CPU总的使用率
return round(busy_perc, 1) #保留一位小数后返回
# system-wide usage
if not percpu: #如果percpu为False
if blocking: #interval 不为空且大余0.0
t1 = cpu_times() #获取t1时刻,cpu各项参数
time.sleep(interval) #休眠interval时间
else:
t1 = _last_cpu_times #如果不满足interval 不为空且大余0.0
if t1 is None: #当interval为None
# Something bad happened at import time. We'll
# get a meaningful result on the next call. See:
# https://github.com/giampaolo/psutil/pull/715
t1 = cpu_times()
#当interval为None,_last_cpu_times与t1几乎是在同一时刻计算的,值几乎相同,因此将返回0.0
_last_cpu_times = cpu_times()
return calculate(t1, _last_cpu_times)
# per-cpu usage
else:
ret = []
if blocking:
tot1 = cpu_times(percpu=True)
time.sleep(interval)
else:
tot1 = _last_per_cpu_times
if tot1 is None:
# Something bad happened at import time. We'll
# get a meaningful result on the next call. See:
# https://github.com/giampaolo/psutil/pull/715
tot1 = cpu_times(percpu=True)
_last_per_cpu_times = cpu_times(percpu=True)
for t1, t2 in zip(tot1, _last_per_cpu_times):
ret.append(calculate(t1, t2)) #循环计算各个CPU的使用率
return ret
# Use separate global vars for cpu_times_percent() so that it's
# independent from cpu_percent() and they can both be used within
# the same program.
_last_cpu_times_2 = _last_cpu_times
_last_per_cpu_times_2 = _last_per_cpu_times