From b6d32e0fd46628ca12dd63466b69de48f846c59c Mon Sep 17 00:00:00 2001 From: Michael Maher Date: Mon, 11 Mar 2024 16:28:44 -0500 Subject: [PATCH 1/3] chore: Update sensors_librehardwaremonitor.py and stats.py files --- library/sensors/sensors_librehardwaremonitor.py | 17 +++++++++++++++++ library/stats.py | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/library/sensors/sensors_librehardwaremonitor.py b/library/sensors/sensors_librehardwaremonitor.py index 29436e3d..f7ba0af7 100644 --- a/library/sensors/sensors_librehardwaremonitor.py +++ b/library/sensors/sensors_librehardwaremonitor.py @@ -296,6 +296,23 @@ def stats(cls) -> Tuple[float, float, float, float]: # load (%) / used mem (%) return load, (used_mem / total_mem * 100.0), used_mem, temp + @classmethod + def total_memory(cls) -> float: + gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuAmd, cls.gpu_name) + if gpu_to_use is None: + gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuNvidia, cls.gpu_name) + if gpu_to_use is None: + gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuIntel, cls.gpu_name) + if gpu_to_use is None: + # GPU not supported + return math.nan + + for sensor in gpu_to_use.Sensors: + if sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Total"): + return float(sensor.Value) + + return math.nan + @classmethod def fps(cls) -> int: gpu_to_use = cls.get_gpu_to_use() diff --git a/library/stats.py b/library/stats.py index 0617ff2e..18bb28f2 100644 --- a/library/stats.py +++ b/library/stats.py @@ -359,6 +359,7 @@ def stats(cls): fps = sensors.Gpu.fps() fan_percent = sensors.Gpu.fan_percent() freq_ghz = sensors.Gpu.frequency() / 1000 + total_memory = sensors.Gpu.total_memory() theme_gpu_data = config.THEME_DATA['STATS']['GPU'] @@ -458,6 +459,16 @@ def stats(cls): unit=" M" ) + # GPU mem. total memory (M) + gpu_total_mem_text_data = theme_gpu_data['MEMORY_TOTAL']['TEXT'] + if gpu_total_mem_text_data and gpu_total_mem_text_data['SHOW']: + display_themed_value( + theme_data=gpu_total_mem_text_data, + value=int(total_memory), + 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'] From 0e32264b997f40fb7b19795d52c0cd898122b5ab Mon Sep 17 00:00:00 2001 From: Michael Maher Date: Mon, 11 Mar 2024 16:32:51 -0500 Subject: [PATCH 2/3] fix: Correct memory total display in default theme Updated the default theme configuration to correctly display memory total information and marked the deprecated memory field as not to be used. --- res/themes/default.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/res/themes/default.yaml b/res/themes/default.yaml index 1e1d2d5f..fd59b9ed 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: From 9d493f482753b1d467f88591c17498a86e06e5a2 Mon Sep 17 00:00:00 2001 From: Matthieu Houdebine Date: Sun, 21 Jul 2024 14:41:08 +0200 Subject: [PATCH 3/3] Make GPU total memory available widely --- library/sensors/sensors.py | 3 +- .../sensors/sensors_librehardwaremonitor.py | 24 +++----------- library/sensors/sensors_python.py | 32 +++++++++++++------ library/sensors/sensors_stub_random.py | 6 ++-- library/sensors/sensors_stub_static.py | 10 ++++-- library/stats.py | 24 ++++++++------ res/themes/theme_example.yaml | 19 +++++++++++ 7 files changed, 73 insertions(+), 45 deletions(-) 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 098d0f2c..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,24 +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 - - @classmethod - def total_memory(cls) -> float: - gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuAmd, cls.gpu_name) - if gpu_to_use is None: - gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuNvidia, cls.gpu_name) - if gpu_to_use is None: - gpu_to_use = get_hw_and_update(Hardware.HardwareType.GpuIntel, cls.gpu_name) - if gpu_to_use is None: - # GPU not supported - return math.nan - - for sensor in gpu_to_use.Sensors: - if sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Total"): - return float(sensor.Value) - - return math.nan + 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 31dbdbdc..09ed6478 100644 --- a/library/stats.py +++ b/library/stats.py @@ -367,11 +367,10 @@ 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 - total_memory = sensors.Gpu.total_memory() theme_gpu_data = config.THEME_DATA['STATS']['GPU'] @@ -472,14 +471,19 @@ def stats(cls): ) # GPU mem. total memory (M) - gpu_total_mem_text_data = theme_gpu_data['MEMORY_TOTAL']['TEXT'] - if gpu_total_mem_text_data and gpu_total_mem_text_data['SHOW']: - display_themed_value( - theme_data=gpu_total_mem_text_data, - value=int(total_memory), - min_size=5, # Adjust min_size as necessary for your display - unit=" M" # Assuming the unit is in Megabytes - ) + 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'] 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