mirror of
https://github.com/nicolargo/glances.git
synced 2024-08-17 00:10:48 +03:00
Merge pull request #2860 from nicolargo/2859-glances-411-on-windows-attributeerror-cpupercent-object-has-no-attribute-cpu_percent
fix: cpu_percent - initialization timer bugs
This commit is contained in:
commit
46abd4b4c9
@ -8,16 +8,42 @@
|
||||
|
||||
"""CPU percent stats shared between CPU and Quicklook plugins."""
|
||||
|
||||
from typing import List, Optional, TypedDict
|
||||
|
||||
import psutil
|
||||
|
||||
from glances.logger import logger
|
||||
from glances.timer import Timer
|
||||
|
||||
__all__ = ["cpu_percent"]
|
||||
|
||||
|
||||
class CpuInfo(TypedDict):
|
||||
cpu_name: str
|
||||
cpu_hz: Optional[float]
|
||||
cpu_hz_current: Optional[float]
|
||||
|
||||
|
||||
class PerCpuPercentInfo(TypedDict):
|
||||
key: str
|
||||
cpu_number: int
|
||||
total: float
|
||||
user: float
|
||||
system: float
|
||||
idle: float
|
||||
nice: Optional[float]
|
||||
iowait: Optional[float]
|
||||
irq: Optional[float]
|
||||
softirq: Optional[float]
|
||||
steal: Optional[float]
|
||||
guest: Optional[float]
|
||||
guest_nice: Optional[float]
|
||||
|
||||
|
||||
class CpuPercent:
|
||||
"""Get and store the CPU percent."""
|
||||
|
||||
def __init__(self, cached_timer_cpu=2):
|
||||
def __init__(self, cached_timer_cpu: int = 2):
|
||||
# cached_timer_cpu is the minimum time interval between stats updates
|
||||
# since last update is passed (will retrieve old cached info instead)
|
||||
self.cached_timer_cpu = cached_timer_cpu
|
||||
@ -27,21 +53,21 @@ class CpuPercent:
|
||||
|
||||
# Get CPU name
|
||||
self.timer_cpu_info = Timer(0)
|
||||
self.cpu_info = {'cpu_name': self.__get_cpu_name(), 'cpu_hz_current': None, 'cpu_hz': None}
|
||||
self.cpu_info: CpuInfo = {'cpu_name': self.__get_cpu_name(), 'cpu_hz_current': None, 'cpu_hz': None}
|
||||
|
||||
# Warning from PsUtil documentation
|
||||
# The first time this function is called with interval = 0.0 or None
|
||||
# it will return a meaningless 0.0 value which you are supposed to ignore.
|
||||
self.timer_cpu = Timer(0)
|
||||
self.cpu_percent = self.get_cpu()
|
||||
self.cpu_percent = self._compute_cpu()
|
||||
self.timer_percpu = Timer(0)
|
||||
self.percpu_percent = self.get_percpu()
|
||||
self.percpu_percent = self._compute_percpu()
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the per CPU list."""
|
||||
return 'cpu_number'
|
||||
|
||||
def get_info(self):
|
||||
def get_info(self) -> CpuInfo:
|
||||
"""Get additional information about the CPU"""
|
||||
# Never update more than 1 time per cached_timer_cpu_info
|
||||
if self.timer_cpu_info.finished() and hasattr(psutil, 'cpu_freq'):
|
||||
@ -63,69 +89,66 @@ class CpuPercent:
|
||||
self.timer_cpu_info.reset(duration=self.cached_timer_cpu_info)
|
||||
return self.cpu_info
|
||||
|
||||
def __get_cpu_name(self):
|
||||
@staticmethod
|
||||
def __get_cpu_name() -> str:
|
||||
# Get the CPU name once from the /proc/cpuinfo file
|
||||
# Read the first line with the "model name" ("Model" for Raspberry Pi)
|
||||
ret = None
|
||||
try:
|
||||
cpuinfo_file = open('/proc/cpuinfo').readlines()
|
||||
cpuinfo_lines = open('/proc/cpuinfo').readlines()
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
||||
else:
|
||||
for line in cpuinfo_file:
|
||||
if line.startswith('model name') or line.startswith('Model') or line.startswith('cpu model'):
|
||||
ret = line.split(':')[1].strip()
|
||||
break
|
||||
return ret if ret else 'CPU'
|
||||
logger.debug("No permission to read '/proc/cpuinfo'")
|
||||
return 'CPU'
|
||||
|
||||
def get_cpu(self):
|
||||
for line in cpuinfo_lines:
|
||||
if line.startswith('model name') or line.startswith('Model') or line.startswith('cpu model'):
|
||||
return line.split(':')[1].strip()
|
||||
|
||||
return 'CPU'
|
||||
|
||||
def get_cpu(self) -> float:
|
||||
"""Update and/or return the CPU using the psutil library."""
|
||||
# Never update more than 1 time per cached_timer_cpu
|
||||
if self.timer_cpu.finished():
|
||||
# Reset timer for cache
|
||||
self.timer_cpu.reset(duration=self.cached_timer_cpu)
|
||||
# Update the stats
|
||||
self.cpu_percent = psutil.cpu_percent(interval=0.0)
|
||||
self.cpu_percent = self._compute_cpu()
|
||||
return self.cpu_percent
|
||||
|
||||
def get_percpu(self):
|
||||
@staticmethod
|
||||
def _compute_cpu() -> float:
|
||||
return psutil.cpu_percent(interval=0.0)
|
||||
|
||||
def get_percpu(self) -> List[PerCpuPercentInfo]:
|
||||
"""Update and/or return the per CPU list using the psutil library."""
|
||||
# Never update more than 1 time per cached_timer_cpu
|
||||
if self.timer_percpu.finished():
|
||||
# Reset timer for cache
|
||||
self.timer_percpu.reset(duration=self.cached_timer_cpu)
|
||||
# Get stats
|
||||
percpu_percent = []
|
||||
# Update stats
|
||||
self.percpu_percent = self._compute_percpu()
|
||||
return self.percpu_percent
|
||||
|
||||
def _compute_percpu(self) -> List[PerCpuPercentInfo]:
|
||||
psutil_percpu = enumerate(psutil.cpu_times_percent(interval=0.0, percpu=True))
|
||||
for cpu_number, cputimes in psutil_percpu:
|
||||
cpu = {
|
||||
return [
|
||||
{
|
||||
'key': self.get_key(),
|
||||
'cpu_number': cpu_number,
|
||||
'total': round(100 - cputimes.idle, 1),
|
||||
'user': cputimes.user,
|
||||
'system': cputimes.system,
|
||||
'idle': cputimes.idle,
|
||||
'total': round(100 - cpu_times.idle, 1),
|
||||
'user': cpu_times.user,
|
||||
'system': cpu_times.system,
|
||||
'idle': cpu_times.idle,
|
||||
'nice': cpu_times.nice if hasattr(cpu_times, 'nice') else None,
|
||||
'iowait': cpu_times.iowait if hasattr(cpu_times, 'iowait') else None,
|
||||
'irq': cpu_times.irq if hasattr(cpu_times, 'irq') else None,
|
||||
'softirq': cpu_times.softirq if hasattr(cpu_times, 'softirq') else None,
|
||||
'steal': cpu_times.steal if hasattr(cpu_times, 'steal') else None,
|
||||
'guest': cpu_times.guest if hasattr(cpu_times, 'guest') else None,
|
||||
'guest_nice': cpu_times.steal if hasattr(cpu_times, 'guest_nice') else None,
|
||||
}
|
||||
# The following stats are for API purposes only
|
||||
if hasattr(cputimes, 'nice'):
|
||||
cpu['nice'] = cputimes.nice
|
||||
if hasattr(cputimes, 'iowait'):
|
||||
cpu['iowait'] = cputimes.iowait
|
||||
if hasattr(cputimes, 'irq'):
|
||||
cpu['irq'] = cputimes.irq
|
||||
if hasattr(cputimes, 'softirq'):
|
||||
cpu['softirq'] = cputimes.softirq
|
||||
if hasattr(cputimes, 'steal'):
|
||||
cpu['steal'] = cputimes.steal
|
||||
if hasattr(cputimes, 'guest'):
|
||||
cpu['guest'] = cputimes.guest
|
||||
if hasattr(cputimes, 'guest_nice'):
|
||||
cpu['guest_nice'] = cputimes.guest_nice
|
||||
# Append new CPU to the list
|
||||
percpu_percent.append(cpu)
|
||||
# Update stats
|
||||
self.percpu_percent = percpu_percent
|
||||
return self.percpu_percent
|
||||
for cpu_number, cpu_times in psutil_percpu
|
||||
]
|
||||
|
||||
|
||||
# CpuPercent instance shared between plugins
|
||||
|
@ -78,7 +78,6 @@ guest operating systems under the control of the Linux kernel.',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# Define the history items list
|
||||
items_history_list = [
|
||||
{'name': 'user', 'description': 'User CPU usage', 'y_unit': '%'},
|
||||
@ -142,7 +141,10 @@ class PluginModel(GlancesPluginModel):
|
||||
return ret
|
||||
|
||||
# Define the default header
|
||||
header = ['user', 'system', 'idle', 'iowait', 'steal']
|
||||
all_headers = ['user', 'system', 'idle', 'iowait', 'steal']
|
||||
|
||||
# Determine applicable headers
|
||||
header = [h for h in all_headers if self.stats[0].get(h) is not None]
|
||||
|
||||
# Build the string message
|
||||
if self.is_disabled('quicklook'):
|
||||
@ -152,8 +154,6 @@ class PluginModel(GlancesPluginModel):
|
||||
|
||||
# Per CPU stats displayed per line
|
||||
for stat in header:
|
||||
if stat not in self.stats[0]:
|
||||
continue
|
||||
msg = f'{stat:>7}'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
@ -179,8 +179,6 @@ class PluginModel(GlancesPluginModel):
|
||||
msg = '{:4} '.format('?')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
for stat in header:
|
||||
if stat not in self.stats[0]:
|
||||
continue
|
||||
try:
|
||||
msg = f'{cpu[stat]:6.1f}%'
|
||||
except TypeError:
|
||||
@ -192,12 +190,10 @@ class PluginModel(GlancesPluginModel):
|
||||
ret.append(self.curse_new_line())
|
||||
if self.is_disabled('quicklook'):
|
||||
ret.append(self.curse_add_line('CPU* '))
|
||||
|
||||
for stat in header:
|
||||
if stat not in self.stats[0]:
|
||||
continue
|
||||
cpu_stat = sum([i[stat] for i in percpu_list[0 : self.max_cpu_display]]) / len(
|
||||
[i[stat] for i in percpu_list[0 : self.max_cpu_display]]
|
||||
)
|
||||
percpu_stats = [i[stat] for i in percpu_list[0 : self.max_cpu_display]]
|
||||
cpu_stat = sum(percpu_stats) / len(percpu_stats)
|
||||
try:
|
||||
msg = f'{cpu_stat:6.1f}%'
|
||||
except TypeError:
|
||||
|
Loading…
Reference in New Issue
Block a user