From ec11dff2cd4c43fa749f26403bf408ba4e4332ca Mon Sep 17 00:00:00 2001 From: Ognyan Kulev Date: Sat, 13 Dec 2025 21:33:22 +0200 Subject: [PATCH 1/3] Get amdgpu name from amdgpu.ids --- glances/plugins/gpu/cards/amd.py | 77 +++++++++++++++++++------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/glances/plugins/gpu/cards/amd.py b/glances/plugins/gpu/cards/amd.py index b57cb3c7..d548cdf2 100644 --- a/glances/plugins/gpu/cards/amd.py +++ b/glances/plugins/gpu/cards/amd.py @@ -11,6 +11,7 @@ The class grabs the stats from the /sys/class/drm/ directory. See: https://wiki.archlinux.org/title/AMDGPU#Manually +amdgpu.ids source: https://cgit.freedesktop.org/drm/libdrm/tree/data/amdgpu.ids """ # Example @@ -20,6 +21,7 @@ See: https://wiki.archlinux.org/title/AMDGPU#Manually # │   └── drm # │   └── card0 # │   └── device +# │   ├── device # │   ├── gpu_busy_percent # │   ├── hwmon # │   │   └── hwmon0 @@ -27,7 +29,8 @@ See: https://wiki.archlinux.org/title/AMDGPU#Manually # │   ├── mem_info_vram_total # │   ├── mem_info_vram_used # │   ├── pp_dpm_mclk -# │   └── pp_dpm_sclk +# │   ├── pp_dpm_sclk +# │   └── revision # └── kernel # └── debug # └── dri @@ -37,10 +40,14 @@ See: https://wiki.archlinux.org/title/AMDGPU#Manually import os import re from typing import Optional +import functools DRM_ROOT_FOLDER: str = '/sys/class/drm' CARD_REGEX: str = r"^card\d$" DEVICE_FOLDER: str = 'device' +AMDGPU_IDS: str = '/usr/share/libdrm/amdgpu.ids' +PCI_DEVICE_ID: str = 'device' +PCI_REVISION_ID: str = 'revision' GPU_PROC_PERCENT: str = 'gpu_busy_percent' GPU_MEM_TOTAL: str = 'mem_info_vram_total' GPU_MEM_USED: str = 'mem_info_vram_used' @@ -99,28 +106,46 @@ def get_device_list(drm_root_folder: str) -> list: return ret +def read_file(*path_segments: str) -> Optional[str]: + """Return content of file.""" + path = os.path.join(*path_segments) + if os.path.isfile(path): + with open(path) as f: + try: + return f.read().strip() + except PermissionError: + # Catch exception (see issue #3125) + return None + return None + + +@functools.cache def get_device_name(device_folder: str) -> str: """Return the GPU name.""" + + device_id = read_file(device_folder, PCI_DEVICE_ID) + revision_id = read_file(device_folder, PCI_REVISION_ID) + amdgpu_ids = read_file(AMDGPU_IDS) + if device_id and revision_id and amdgpu_ids: + # Strip leading "0x" and convert to uppercase hexadecimal + device_id = device_id[2:].upper() + revision_id = revision_id[2:].upper() + # Syntax: + # device_id, revision_id, product_name <-- single tab after comma + pattern = re.compile(f'^{device_id},\\s{revision_id},\\s(.+)$', re.MULTILINE) + if match := pattern.search(amdgpu_ids): + return match.group(1) + return 'AMD GPU' def get_mem(device_folder: str) -> Optional[int]: """Return the memory consumption in %.""" - mem_info_vram_total = os.path.join(device_folder, GPU_MEM_TOTAL) - mem_info_vram_used = os.path.join(device_folder, GPU_MEM_USED) - if os.path.isfile(mem_info_vram_total) and os.path.isfile(mem_info_vram_used): - with open(mem_info_vram_total) as f: - try: - mem_info_vram_total = int(f.read()) - except PermissionError: - # Catch exception (see issue #3125) - return None - with open(mem_info_vram_used) as f: - try: - mem_info_vram_used = int(f.read()) - except PermissionError: - # Catch exception (see issue #3125) - return None + mem_info_vram_total = read_file(device_folder, GPU_MEM_TOTAL) + mem_info_vram_used = read_file(device_folder, GPU_MEM_USED) + if mem_info_vram_total and mem_info_vram_used: + mem_info_vram_total = int(mem_info_vram_total) + mem_info_vram_used = int(mem_info_vram_used) if mem_info_vram_total > 0: return round(mem_info_vram_used / mem_info_vram_total * 100) return None @@ -128,14 +153,8 @@ def get_mem(device_folder: str) -> Optional[int]: def get_proc(device_folder: str) -> Optional[int]: """Return the processor consumption in %.""" - gpu_busy_percent = os.path.join(device_folder, GPU_PROC_PERCENT) - if os.path.isfile(gpu_busy_percent): - with open(gpu_busy_percent) as f: - try: - return int(f.read()) - except PermissionError: - # Catch exception (see issue #3125) - return None + if gpu_busy_percent := read_file(device_folder, GPU_PROC_PERCENT): + return int(gpu_busy_percent) return None @@ -148,12 +167,10 @@ def get_temperature(device_folder: str) -> Optional[int]: for _, _, files in os.walk(os.path.join(root, d)): for f in files: if re.match(GPU_TEMPERATURE_REGEXP, f): - with open(os.path.join(root, d, f)) as f: - try: - temp_input.append(int(f.read())) - except PermissionError: - # Catch exception (see issue #3125) - return None + if a_temp_input := read_file(root, d, f): + temp_input.append(int(a_temp_input)) + else: + return None if temp_input: return round(sum(temp_input) / len(temp_input) / 1000) return None From bc629d12b276861e7c416343a9493975e5aad8fc Mon Sep 17 00:00:00 2001 From: Ognyan Kulev Date: Sun, 14 Dec 2025 12:44:30 +0200 Subject: [PATCH 2/3] Remove 'AMD' prefix and 'Graphics' suffix. --- glances/plugins/gpu/cards/amd.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/glances/plugins/gpu/cards/amd.py b/glances/plugins/gpu/cards/amd.py index d548cdf2..8f031137 100644 --- a/glances/plugins/gpu/cards/amd.py +++ b/glances/plugins/gpu/cards/amd.py @@ -11,7 +11,6 @@ The class grabs the stats from the /sys/class/drm/ directory. See: https://wiki.archlinux.org/title/AMDGPU#Manually -amdgpu.ids source: https://cgit.freedesktop.org/drm/libdrm/tree/data/amdgpu.ids """ # Example @@ -45,7 +44,7 @@ import functools DRM_ROOT_FOLDER: str = '/sys/class/drm' CARD_REGEX: str = r"^card\d$" DEVICE_FOLDER: str = 'device' -AMDGPU_IDS: str = '/usr/share/libdrm/amdgpu.ids' +AMDGPU_IDS_FILE: str = '/usr/share/libdrm/amdgpu.ids' PCI_DEVICE_ID: str = 'device' PCI_REVISION_ID: str = 'revision' GPU_PROC_PERCENT: str = 'gpu_busy_percent' @@ -123,18 +122,19 @@ def read_file(*path_segments: str) -> Optional[str]: def get_device_name(device_folder: str) -> str: """Return the GPU name.""" + # Table source: https://cgit.freedesktop.org/drm/libdrm/tree/data/amdgpu.ids device_id = read_file(device_folder, PCI_DEVICE_ID) revision_id = read_file(device_folder, PCI_REVISION_ID) - amdgpu_ids = read_file(AMDGPU_IDS) + amdgpu_ids = read_file(AMDGPU_IDS_FILE) if device_id and revision_id and amdgpu_ids: # Strip leading "0x" and convert to uppercase hexadecimal device_id = device_id[2:].upper() revision_id = revision_id[2:].upper() # Syntax: # device_id, revision_id, product_name <-- single tab after comma - pattern = re.compile(f'^{device_id},\\s{revision_id},\\s(.+)$', re.MULTILINE) + pattern = re.compile(f'^{device_id},\\s{revision_id},\\s(?P.+)$', re.MULTILINE) if match := pattern.search(amdgpu_ids): - return match.group(1) + return match.group('product_name').removeprefix('AMD ').removesuffix(' Graphics') return 'AMD GPU' From 2800e81cb02e1f6283476d508d5008b82567e7cf Mon Sep 17 00:00:00 2001 From: Ognyan Kulev Date: Sun, 14 Dec 2025 14:19:18 +0200 Subject: [PATCH 3/3] Add pci id files to tests-data --- tests-data/plugins/gpu/amd/sys/class/drm/card0/device/device | 1 + tests-data/plugins/gpu/amd/sys/class/drm/card0/device/revision | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests-data/plugins/gpu/amd/sys/class/drm/card0/device/device create mode 100644 tests-data/plugins/gpu/amd/sys/class/drm/card0/device/revision diff --git a/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/device b/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/device new file mode 100644 index 00000000..350fb565 --- /dev/null +++ b/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/device @@ -0,0 +1 @@ +0x1586 diff --git a/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/revision b/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/revision new file mode 100644 index 00000000..fe442834 --- /dev/null +++ b/tests-data/plugins/gpu/amd/sys/class/drm/card0/device/revision @@ -0,0 +1 @@ +0xc1