diff --git a/library/sensors/sensors.py b/library/sensors/sensors.py index a23766b9..0a9ada94 100644 --- a/library/sensors/sensors.py +++ b/library/sensors/sensors.py @@ -53,7 +53,8 @@ def fan_percent(fan_name: str = None) -> float: class Gpu(ABC): @staticmethod @abstractmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) pass @staticmethod diff --git a/library/sensors/sensors_librehardwaremonitor.py b/library/sensors/sensors_librehardwaremonitor.py index 7f95df11..f619a5b3 100644 --- a/library/sensors/sensors_librehardwaremonitor.py +++ b/library/sensors/sensors_librehardwaremonitor.py @@ -274,11 +274,12 @@ def get_gpu_to_use(cls): return gpu_to_use @classmethod - def stats(cls) -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) + def stats(cls) -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) gpu_to_use = cls.get_gpu_to_use() if gpu_to_use is None: # GPU not supported - return math.nan, math.nan, math.nan, math.nan + return math.nan, math.nan, math.nan, math.nan, math.nan load = math.nan used_mem = math.nan @@ -310,7 +311,7 @@ def stats(cls) -> Tuple[float, float, float, float]: # load (%) / used mem (%) "GPU Core") and sensor.Value is not None: temp = float(sensor.Value) - return load, (used_mem / total_mem * 100.0), used_mem, temp + return load, (used_mem / total_mem * 100.0), used_mem, total_mem, temp @classmethod def fps(cls) -> int: diff --git a/library/sensors/sensors_python.py b/library/sensors/sensors_python.py index cbcee89c..ea36fe65 100644 --- a/library/sensors/sensors_python.py +++ b/library/sensors/sensors_python.py @@ -173,14 +173,15 @@ def fan_percent(fan_name: str = None) -> float: class Gpu(sensors.Gpu): @staticmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) global DETECTED_GPU if DETECTED_GPU == GpuType.AMD: return GpuAmd.stats() elif DETECTED_GPU == GpuType.NVIDIA: return GpuNvidia.stats() else: - return math.nan, math.nan, math.nan, math.nan + return math.nan, math.nan, math.nan, math.nan, math.nan @staticmethod def fps() -> int: @@ -233,7 +234,8 @@ def is_available() -> bool: class GpuNvidia(sensors.Gpu): @staticmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) # Unlike other sensors, Nvidia GPU with GPUtil pulls in all the stats at once nvidia_gpus = GPUtil.getGPUs() @@ -246,6 +248,10 @@ def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / u try: memory_total_all = [item.memoryTotal for item in nvidia_gpus] memory_total_mb = sum(memory_total_all) / len(memory_total_all) + except: + memory_total_mb = math.nan + + try: memory_percentage = (memory_used_mb / memory_total_mb) * 100 except: memory_percentage = math.nan @@ -262,7 +268,7 @@ def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / u except: temperature = math.nan - return load, memory_percentage, memory_used_mb, temperature + return load, memory_percentage, memory_used_mb, memory_total_mb, temperature @staticmethod def fps() -> int: @@ -298,7 +304,8 @@ def is_available() -> bool: class GpuAmd(sensors.Gpu): @staticmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) if pyamdgpuinfo: # Unlike other sensors, AMD GPU with pyamdgpuinfo pulls in all the stats at once pyamdgpuinfo.detect_gpus() @@ -306,13 +313,19 @@ def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / u try: memory_used_bytes = amd_gpu.query_vram_usage() - memory_used = memory_used_bytes / 1000000 + memory_used = memory_used_bytes / 1024 / 1024 except: memory_used_bytes = math.nan memory_used = math.nan try: memory_total_bytes = amd_gpu.memory_info["vram_size"] + memory_total = memory_total_bytes / 1024 / 1024 + except: + memory_total_bytes = math.nan + memory_total = math.nan + + try: memory_percentage = (memory_used_bytes / memory_total_bytes) * 100 except: memory_percentage = math.nan @@ -327,7 +340,7 @@ def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / u except: temperature = math.nan - return load, memory_percentage, memory_used, temperature + return load, memory_percentage, memory_used, memory_total, temperature elif pyadl: amd_gpu = pyadl.ADLManager.getInstance().getDevices()[0] @@ -341,8 +354,8 @@ def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / u except: temperature = math.nan - # Memory absolute (M) and relative (%) usage not supported by pyadl - return load, math.nan, math.nan, temperature + # GPU memory data not supported by pyadl + return load, math.nan, math.nan, math.nan, temperature @staticmethod def fps() -> int: @@ -425,6 +438,7 @@ def virtual_free() -> int: # In bytes except: return -1 + class Disk(sensors.Disk): @staticmethod def disk_usage_percent() -> float: diff --git a/library/sensors/sensors_stub_random.py b/library/sensors/sensors_stub_random.py index 28a5f4b8..07e37748 100644 --- a/library/sensors/sensors_stub_random.py +++ b/library/sensors/sensors_stub_random.py @@ -49,8 +49,10 @@ def fan_percent(fan_name: str = None) -> float: class Gpu(sensors.Gpu): @staticmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) - return random.uniform(0, 100), random.uniform(0, 100), random.uniform(300, 16000), random.uniform(30, 90) + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) + return random.uniform(0, 100), random.uniform(0, 100), random.uniform(300, 16000), 16000.0, random.uniform(30, + 90) @staticmethod def fps() -> int: diff --git a/library/sensors/sensors_stub_static.py b/library/sensors/sensors_stub_static.py index e5485df0..5aa16168 100644 --- a/library/sensors/sensors_stub_static.py +++ b/library/sensors/sensors_stub_static.py @@ -62,9 +62,13 @@ def fan_percent(fan_name: str = None) -> float: class Gpu(sensors.Gpu): @staticmethod - def stats() -> Tuple[float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / temp (°C) - return PERCENTAGE_SENSOR_VALUE, PERCENTAGE_SENSOR_VALUE, \ - GPU_MEM_TOTAL_SIZE_GB / 100 * PERCENTAGE_SENSOR_VALUE * 1000, TEMPERATURE_SENSOR_VALUE + def stats() -> Tuple[ + float, float, float, float, float]: # load (%) / used mem (%) / used mem (Mb) / total mem (Mb) / temp (°C) + return (PERCENTAGE_SENSOR_VALUE, + PERCENTAGE_SENSOR_VALUE, + GPU_MEM_TOTAL_SIZE_GB / 100 * PERCENTAGE_SENSOR_VALUE * 1024, + GPU_MEM_TOTAL_SIZE_GB * 1024, + TEMPERATURE_SENSOR_VALUE) @staticmethod def fps() -> int: diff --git a/library/stats.py b/library/stats.py index 1afa9fe6..09ed6478 100644 --- a/library/stats.py +++ b/library/stats.py @@ -367,7 +367,7 @@ class Gpu: @classmethod def stats(cls): - load, memory_percentage, memory_used_mb, temperature = sensors.Gpu.stats() + load, memory_percentage, memory_used_mb, total_memory_mb, temperature = sensors.Gpu.stats() fps = sensors.Gpu.fps() fan_percent = sensors.Gpu.fan_percent() freq_ghz = sensors.Gpu.frequency() / 1000 @@ -470,6 +470,21 @@ def stats(cls): unit=" M" ) + # GPU mem. total memory (M) + gpu_mem_total_text_data = theme_gpu_data['MEMORY_TOTAL']['TEXT'] + if math.isnan(memory_used_mb): + memory_used_mb = 0 + if gpu_mem_total_text_data['SHOW']: + logger.warning("Your GPU total memory capacity (M) is not supported yet") + gpu_mem_total_text_data['SHOW'] = False + + display_themed_value( + theme_data=gpu_mem_total_text_data, + value=int(total_memory_mb), + min_size=5, # Adjust min_size as necessary for your display + unit=" M" # Assuming the unit is in Megabytes + ) + # GPU temperature (°C) gpu_temp_text_data = theme_gpu_data['TEMPERATURE']['TEXT'] gpu_temp_radial_data = theme_gpu_data['TEMPERATURE']['RADIAL'] diff --git a/res/themes/default.yaml b/res/themes/default.yaml index 28b1f186..6528d7db 100644 --- a/res/themes/default.yaml +++ b/res/themes/default.yaml @@ -76,7 +76,10 @@ STATS: MEMORY_USED: TEXT: SHOW: False - MEMORY: # Deprecated, do not use + MEMORY_TOTAL: + TEXT: + SHOW: False + MEMORY: # Deprecated, do not use GRAPH: SHOW: False RADIAL: diff --git a/res/themes/theme_example.yaml b/res/themes/theme_example.yaml index c9b14040..cd98483d 100644 --- a/res/themes/theme_example.yaml +++ b/res/themes/theme_example.yaml @@ -580,6 +580,25 @@ STATS: BACKGROUND_IMAGE: background.png ALIGN: left # left / center / right ANCHOR: lt # Check https://pillow.readthedocs.io/en/stable/handbook/text-anchors.html + MEMORY_TOTAL: + TEXT: + SHOW: False + SHOW_UNIT: True + X: 204 + Y: 195 + # Text sensors may vary in size and create "ghosting" effects where old value stay displayed under the new one. + # To avoid this use one of these 2 methods (or both): + # - either use a monospaced font (fonts with "mono" in name, see res/fonts/ for available fonts) + # - or force a static width/height for the text field. Be sure to have enough space for the longest value that can be displayed (e.g. "100%" for a percentage) + # WIDTH: 200 # Uncomment to force a static width + # HEIGHT: 50 # Uncomment to force static height + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + # BACKGROUND_COLOR: 132, 154, 165 + BACKGROUND_IMAGE: background.png + ALIGN: left # left / center / right + ANCHOR: lt # Check https://pillow.readthedocs.io/en/stable/handbook/text-anchors.html TEMPERATURE: TEXT: SHOW: False