mirror of
https://github.com/nicolargo/glances.git
synced 2024-08-17 08:20:25 +03:00
Compare commits
5 Commits
c18ee5dd89
...
31ad7656b8
Author | SHA1 | Date | |
---|---|---|---|
|
31ad7656b8 | ||
|
6af2340c5c | ||
|
46abd4b4c9 | ||
|
2801add7e2 | ||
|
afc66f2dcd |
@ -5,3 +5,4 @@ reuse
|
|||||||
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
||||||
sphinx
|
sphinx
|
||||||
sphinx_rtd_theme
|
sphinx_rtd_theme
|
||||||
|
urllib3>=2.2.2 # not directly required, pinned by Snyk to avoid a vulnerability
|
||||||
|
@ -8,16 +8,44 @@
|
|||||||
|
|
||||||
"""CPU percent stats shared between CPU and Quicklook plugins."""
|
"""CPU percent stats shared between CPU and Quicklook plugins."""
|
||||||
|
|
||||||
|
from typing import List, Optional, TypedDict
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
from glances.logger import logger
|
from glances.logger import logger
|
||||||
from glances.timer import Timer
|
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]
|
||||||
|
dpc: Optional[float]
|
||||||
|
interrupt: Optional[float]
|
||||||
|
|
||||||
|
|
||||||
class CpuPercent:
|
class CpuPercent:
|
||||||
"""Get and store the CPU percent."""
|
"""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
|
# cached_timer_cpu is the minimum time interval between stats updates
|
||||||
# since last update is passed (will retrieve old cached info instead)
|
# since last update is passed (will retrieve old cached info instead)
|
||||||
self.cached_timer_cpu = cached_timer_cpu
|
self.cached_timer_cpu = cached_timer_cpu
|
||||||
@ -27,21 +55,21 @@ class CpuPercent:
|
|||||||
|
|
||||||
# Get CPU name
|
# Get CPU name
|
||||||
self.timer_cpu_info = Timer(0)
|
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
|
# Warning from PsUtil documentation
|
||||||
# The first time this function is called with interval = 0.0 or None
|
# 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.
|
# it will return a meaningless 0.0 value which you are supposed to ignore.
|
||||||
self.timer_cpu = Timer(0)
|
self.timer_cpu = Timer(0)
|
||||||
self.cpu_percent = self.get_cpu()
|
self.cpu_percent = self._compute_cpu()
|
||||||
self.timer_percpu = Timer(0)
|
self.timer_percpu = Timer(0)
|
||||||
self.percpu_percent = self.get_percpu()
|
self.percpu_percent = self._compute_percpu()
|
||||||
|
|
||||||
def get_key(self):
|
def get_key(self):
|
||||||
"""Return the key of the per CPU list."""
|
"""Return the key of the per CPU list."""
|
||||||
return 'cpu_number'
|
return 'cpu_number'
|
||||||
|
|
||||||
def get_info(self):
|
def get_info(self) -> CpuInfo:
|
||||||
"""Get additional information about the CPU"""
|
"""Get additional information about the CPU"""
|
||||||
# Never update more than 1 time per cached_timer_cpu_info
|
# Never update more than 1 time per cached_timer_cpu_info
|
||||||
if self.timer_cpu_info.finished() and hasattr(psutil, 'cpu_freq'):
|
if self.timer_cpu_info.finished() and hasattr(psutil, 'cpu_freq'):
|
||||||
@ -63,70 +91,69 @@ class CpuPercent:
|
|||||||
self.timer_cpu_info.reset(duration=self.cached_timer_cpu_info)
|
self.timer_cpu_info.reset(duration=self.cached_timer_cpu_info)
|
||||||
return self.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
|
# Get the CPU name once from the /proc/cpuinfo file
|
||||||
# Read the first line with the "model name" ("Model" for Raspberry Pi)
|
# Read the first line with the "model name" ("Model" for Raspberry Pi)
|
||||||
ret = None
|
|
||||||
try:
|
try:
|
||||||
cpuinfo_file = open('/proc/cpuinfo').readlines()
|
cpuinfo_lines = open('/proc/cpuinfo').readlines()
|
||||||
except (FileNotFoundError, PermissionError):
|
except (FileNotFoundError, PermissionError):
|
||||||
pass
|
logger.debug("No permission to read '/proc/cpuinfo'")
|
||||||
else:
|
return 'CPU'
|
||||||
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'
|
|
||||||
|
|
||||||
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."""
|
"""Update and/or return the CPU using the psutil library."""
|
||||||
# Never update more than 1 time per cached_timer_cpu
|
# Never update more than 1 time per cached_timer_cpu
|
||||||
if self.timer_cpu.finished():
|
if self.timer_cpu.finished():
|
||||||
# Reset timer for cache
|
# Reset timer for cache
|
||||||
self.timer_cpu.reset(duration=self.cached_timer_cpu)
|
self.timer_cpu.reset(duration=self.cached_timer_cpu)
|
||||||
# Update the stats
|
# Update the stats
|
||||||
self.cpu_percent = psutil.cpu_percent(interval=0.0)
|
self.cpu_percent = self._compute_cpu()
|
||||||
return self.cpu_percent
|
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."""
|
"""Update and/or return the per CPU list using the psutil library."""
|
||||||
# Never update more than 1 time per cached_timer_cpu
|
# Never update more than 1 time per cached_timer_cpu
|
||||||
if self.timer_percpu.finished():
|
if self.timer_percpu.finished():
|
||||||
# Reset timer for cache
|
# Reset timer for cache
|
||||||
self.timer_percpu.reset(duration=self.cached_timer_cpu)
|
self.timer_percpu.reset(duration=self.cached_timer_cpu)
|
||||||
# Get stats
|
|
||||||
percpu_percent = []
|
|
||||||
psutil_percpu = enumerate(psutil.cpu_times_percent(interval=0.0, percpu=True))
|
|
||||||
for cpu_number, cputimes in psutil_percpu:
|
|
||||||
cpu = {
|
|
||||||
'key': self.get_key(),
|
|
||||||
'cpu_number': cpu_number,
|
|
||||||
'total': round(100 - cputimes.idle, 1),
|
|
||||||
'user': cputimes.user,
|
|
||||||
'system': cputimes.system,
|
|
||||||
'idle': cputimes.idle,
|
|
||||||
}
|
|
||||||
# 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
|
# Update stats
|
||||||
self.percpu_percent = percpu_percent
|
self.percpu_percent = self._compute_percpu()
|
||||||
return self.percpu_percent
|
return self.percpu_percent
|
||||||
|
|
||||||
|
def _compute_percpu(self) -> List[PerCpuPercentInfo]:
|
||||||
|
psutil_percpu = enumerate(psutil.cpu_times_percent(interval=0.0, percpu=True))
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'key': self.get_key(),
|
||||||
|
'cpu_number': cpu_number,
|
||||||
|
'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,
|
||||||
|
'dpc': cpu_times.dpc if hasattr(cpu_times, 'dpc') else None,
|
||||||
|
'interrupt': cpu_times.interrupt if hasattr(cpu_times, 'interrupt') else None,
|
||||||
|
}
|
||||||
|
for cpu_number, cpu_times in psutil_percpu
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# CpuPercent instance shared between plugins
|
# CpuPercent instance shared between plugins
|
||||||
cpu_percent = CpuPercent()
|
cpu_percent = CpuPercent()
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"""Per-CPU plugin."""
|
"""Per-CPU plugin."""
|
||||||
|
|
||||||
from glances.cpu_percent import cpu_percent
|
from glances.cpu_percent import cpu_percent
|
||||||
|
from glances.globals import BSD, LINUX, MACOS, WINDOWS
|
||||||
from glances.plugins.plugin.model import GlancesPluginModel
|
from glances.plugins.plugin.model import GlancesPluginModel
|
||||||
|
|
||||||
# Fields description
|
# Fields description
|
||||||
@ -76,9 +77,16 @@ guest operating systems under the control of the Linux kernel.',
|
|||||||
'description': '*(Linux)*: percent of time spent handling software interrupts.',
|
'description': '*(Linux)*: percent of time spent handling software interrupts.',
|
||||||
'unit': 'percent',
|
'unit': 'percent',
|
||||||
},
|
},
|
||||||
|
'dpc': {
|
||||||
|
'description': '*(Windows)*: percent of time spent handling deferred procedure calls.',
|
||||||
|
'unit': 'percent',
|
||||||
|
},
|
||||||
|
'interrupt': {
|
||||||
|
'description': '*(Windows)*: percent of time spent handling software interrupts.',
|
||||||
|
'unit': 'percent',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Define the history items list
|
# Define the history items list
|
||||||
items_history_list = [
|
items_history_list = [
|
||||||
{'name': 'user', 'description': 'User CPU usage', 'y_unit': '%'},
|
{'name': 'user', 'description': 'User CPU usage', 'y_unit': '%'},
|
||||||
@ -141,8 +149,17 @@ class PluginModel(GlancesPluginModel):
|
|||||||
if not self.stats or not self.args.percpu or self.is_disabled():
|
if not self.stats or not self.args.percpu or self.is_disabled():
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
# Define the default header
|
# Define the headers based on OS
|
||||||
header = ['user', 'system', 'idle', 'iowait', 'steal']
|
header = ['user', 'system']
|
||||||
|
|
||||||
|
if LINUX:
|
||||||
|
header.extend(['iowait', 'idle', 'irq', 'nice', 'steal', 'guest'])
|
||||||
|
elif MACOS:
|
||||||
|
header.extend(['idle', 'nice'])
|
||||||
|
elif BSD:
|
||||||
|
header.extend(['idle', 'irq', 'nice'])
|
||||||
|
elif WINDOWS:
|
||||||
|
header.extend(['dpc', 'interrupt'])
|
||||||
|
|
||||||
# Build the string message
|
# Build the string message
|
||||||
if self.is_disabled('quicklook'):
|
if self.is_disabled('quicklook'):
|
||||||
@ -152,8 +169,6 @@ class PluginModel(GlancesPluginModel):
|
|||||||
|
|
||||||
# Per CPU stats displayed per line
|
# Per CPU stats displayed per line
|
||||||
for stat in header:
|
for stat in header:
|
||||||
if stat not in self.stats[0]:
|
|
||||||
continue
|
|
||||||
msg = f'{stat:>7}'
|
msg = f'{stat:>7}'
|
||||||
ret.append(self.curse_add_line(msg))
|
ret.append(self.curse_add_line(msg))
|
||||||
|
|
||||||
@ -179,8 +194,6 @@ class PluginModel(GlancesPluginModel):
|
|||||||
msg = '{:4} '.format('?')
|
msg = '{:4} '.format('?')
|
||||||
ret.append(self.curse_add_line(msg))
|
ret.append(self.curse_add_line(msg))
|
||||||
for stat in header:
|
for stat in header:
|
||||||
if stat not in self.stats[0]:
|
|
||||||
continue
|
|
||||||
try:
|
try:
|
||||||
msg = f'{cpu[stat]:6.1f}%'
|
msg = f'{cpu[stat]:6.1f}%'
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@ -192,12 +205,10 @@ class PluginModel(GlancesPluginModel):
|
|||||||
ret.append(self.curse_new_line())
|
ret.append(self.curse_new_line())
|
||||||
if self.is_disabled('quicklook'):
|
if self.is_disabled('quicklook'):
|
||||||
ret.append(self.curse_add_line('CPU* '))
|
ret.append(self.curse_add_line('CPU* '))
|
||||||
|
|
||||||
for stat in header:
|
for stat in header:
|
||||||
if stat not in self.stats[0]:
|
percpu_stats = [i[stat] for i in percpu_list[0 : self.max_cpu_display]]
|
||||||
continue
|
cpu_stat = sum(percpu_stats) / len(percpu_stats)
|
||||||
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]]
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
msg = f'{cpu_stat:6.1f}%'
|
msg = f'{cpu_stat:6.1f}%'
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
Loading…
Reference in New Issue
Block a user