Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package nvtop for openSUSE:Factory checked in at 2023-06-22 23:27:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nvtop (Old) and /work/SRC/openSUSE:Factory/.nvtop.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nvtop" Thu Jun 22 23:27:07 2023 rev:2 rq:1094674 version:3.0.2+2 Changes: -------- --- /work/SRC/openSUSE:Factory/nvtop/nvtop.changes 2023-04-26 17:27:00.102197417 +0200 +++ /work/SRC/openSUSE:Factory/.nvtop.new.15902/nvtop.changes 2023-06-22 23:27:51.542391743 +0200 @@ -1,0 +2,12 @@ +Thu Jun 22 13:00:22 UTC 2023 - [email protected] + +- Update to version 3.0.2+2: + * Fix a potential issue when using multiple AMDGPUs. + * Fix amdgpu wrong tx/rx computation + * Remove workaround for driver bug + * Uniqueness is pdev+id on amdgpu + * Uniqueness is pdev+id on intel + * README MSM information. + * MSM and Adreno support + +------------------------------------------------------------------- Old: ---- nvtop-3.0.1+29.obscpio New: ---- nvtop-3.0.2+2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nvtop.spec ++++++ --- /var/tmp/diff_new_pack.OKosug/_old 2023-06-22 23:27:52.034394253 +0200 +++ /var/tmp/diff_new_pack.OKosug/_new 2023-06-22 23:27:52.038394273 +0200 @@ -1,6 +1,7 @@ # # spec file for package nvtop # +# Copyright (c) 2023 SUSE LLC # Copyright (c) 2020-2023 Malcolm J Lewis <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -12,15 +13,16 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # + Name: nvtop -Version: 3.0.1+29 +Version: 3.0.2+2 Release: 0 -License: GPL-3.0+ +License: GPL-3.0-or-later Summary: A (h)top like task monitor for NVIDIA and AMD GPUs -Url: https://github.com/Syllo/nvtop +URL: https://github.com/Syllo/nvtop Source0: %{name}-%{version}.tar.xz BuildRequires: cmake BuildRequires: gcc-c++ ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.OKosug/_old 2023-06-22 23:27:52.086394518 +0200 +++ /var/tmp/diff_new_pack.OKosug/_new 2023-06-22 23:27:52.090394538 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/Syllo/nvtop.git</param> - <param name="changesrevision">d3dddbdeb16e0d5982414829a03383df93b6a4b1</param></service></servicedata> + <param name="changesrevision">9a8458b541a195a0c5cadafb66e240962c852b39</param></service></servicedata> (No newline at EOF) ++++++ nvtop-3.0.1+29.obscpio -> nvtop-3.0.2+2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/CMakeLists.txt new/nvtop-3.0.2+2/CMakeLists.txt --- old/nvtop-3.0.1+29/CMakeLists.txt 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/CMakeLists.txt 2023-06-15 11:47:30.000000000 +0200 @@ -4,7 +4,7 @@ # PROJECT # #///////////////////////////////////////////////////////////////////# -project(nvtop VERSION 3.0.1 +project(nvtop VERSION 3.0.2 LANGUAGES C CXX) set(default_build_type "Release") @@ -63,6 +63,7 @@ option(NVIDIA_SUPPORT "Build support for NVIDIA GPUs through libnvml" ON) option(AMDGPU_SUPPORT "Build support for AMD GPUs through amdgpu driver" ON) option(INTEL_SUPPORT "Build support for Intel GPUs through i915 driver" ON) +option(MSM_SUPPORT "Build support for Adreno GPUs through msm driver" ON) add_subdirectory(src) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/README.markdown new/nvtop-3.0.2+2/README.markdown --- old/nvtop-3.0.1+29/README.markdown 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/README.markdown 2023-06-15 11:47:30.000000000 +0200 @@ -23,11 +23,12 @@ - [AMD](#amd) - [Intel](#intel) - [NVIDIA](#nvidia) + - [Adreno](#adreno) - [Build](#build) - [Distribution Specific Installation Process](#distribution-specific-installation-process) - [Ubuntu / Debian](#ubuntu--debian) - - [Ubuntu disco (19.04) / Debian buster (stable)](#ubuntu-disco-1904--debian-buster-stable) - - [Fedora / RedHat / CentOS](#fedora--redhat--centos) + - [Ubuntu Impish (21.10) / Debian buster (stable) and more recent (stable)](#ubuntu-impish-2110-debian-buster-stable-and-more-recent) + - [Fedora / Red Hat / CentOS](#fedora--red-hat--centos) - [OpenSUSE](#opensuse) - [Arch Linux](#arch-linux) - [AppImage](#appimage) @@ -102,6 +103,15 @@ successor should work fine. For more information about supported GPUs please take a look at the [NVML documentation](http://docs.nvidia.com/deploy/nvml-api/nvml-api-reference.html#nvml-api-reference). +### Adreno + +NVTOP supports Adreno GPUs using the `msm` linux driver. + +msm introduced the fdinfo interface in kernel 6.0 ([browse kernel +source](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/gpu/drm/msm/msm_drv.c?h=linux-6.0.y)). +Hence, you will need a kernel with a version greater or equal to 6.0 to see the +processes using Adreno GPUs. + Build ----- @@ -160,11 +170,31 @@ - Follow the [NVTOP Build](#nvtop-build) -### Fedora / RedHat / CentOS +### Fedora / Red Hat / CentOS A standalone application is available as [AppImage](#appimage). -#### Build process for Fedora / RedHat / CentOS: +#### Fedora 36 and newer + +- ```bash + sudo dnf install nvtop + ``` + +#### Red Hat Enterprise Linux 8 and 9 + +- ```bash + sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E %{rhel}).noarch.rpm + sudo dnf install nvtop + ``` + +#### CentOS Stream, Rocky Linux, AlmaLinux + +- ```bash + sudo dnf install -y epel-release + sudo dnf install nvtop + ``` + +#### Build process for Fedora / Red Hat / CentOS: - AMD and Intel Dependencies ```bash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/CMakeLists.txt new/nvtop-3.0.2+2/src/CMakeLists.txt --- old/nvtop-3.0.1+29/src/CMakeLists.txt 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/CMakeLists.txt 2023-06-15 11:47:30.000000000 +0200 @@ -58,17 +58,24 @@ target_sources(nvtop PRIVATE device_discovery_linux.c) endif() -if(AMDGPU_SUPPORT) +if(AMDGPU_SUPPORT OR MSM_SUPPORT) # Search for libdrm for AMDGPU support find_package(Libdrm) if(Libdrm_FOUND) - message(STATUS "Found libdrm; Enabling AMDGPU support") + message(STATUS "Found libdrm; Enabling support") target_include_directories(nvtop PRIVATE ${Libdrm_INCLUDE_DIRS}) - target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu.c) - target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu_utils.c) + if (AMDGPU_SUPPORT) + target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu.c) + target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu_utils.c) + endif() + + if (MSM_SUPPORT) + target_sources(nvtop PRIVATE extract_gpuinfo_msm.c) + target_sources(nvtop PRIVATE extract_gpuinfo_msm_utils.c) + endif() else() - message(FATAL_ERROR "libdrm not found; This library is required for AMDGPU support") + message(FATAL_ERROR "libdrm not found; This library is required for AMDGPU and MSM support") endif() endif() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_gpuinfo.c new/nvtop-3.0.2+2/src/extract_gpuinfo.c --- old/nvtop-3.0.1+29/src/extract_gpuinfo.c 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_gpuinfo.c 2023-06-15 11:47:30.000000000 +0200 @@ -154,11 +154,9 @@ if (!GPUINFO_DYNAMIC_FIELD_VALID(dynamic_info, gpu_util_rate) && validReportedGpuRate) { SET_GPUINFO_DYNAMIC(dynamic_info, gpu_util_rate, reportedGpuRate); } else if (GPUINFO_DYNAMIC_FIELD_VALID(dynamic_info, gpu_util_rate) && validReportedGpuRate) { - // Reinstate the driver reported usage if within reasonable margin of processes usage - if (!(/*more than 10% lower*/ reportedGpuRate < dynamic_info->gpu_util_rate - 10 || - /*more than 10% greater*/ reportedGpuRate > dynamic_info->gpu_util_rate + 10)) { - SET_GPUINFO_DYNAMIC(dynamic_info, gpu_util_rate, reportedGpuRate); - } + SET_GPUINFO_DYNAMIC( + dynamic_info, gpu_util_rate, + (dynamic_info->gpu_util_rate > reportedGpuRate ? dynamic_info->gpu_util_rate : reportedGpuRate)); } } return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_gpuinfo_amdgpu.c new/nvtop-3.0.2+2/src/extract_gpuinfo_amdgpu.c --- old/nvtop-3.0.1+29/src/extract_gpuinfo_amdgpu.c 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_gpuinfo_amdgpu.c 2023-06-15 11:47:30.000000000 +0200 @@ -53,7 +53,7 @@ #include <xf86drm.h> // extern -const char * amdgpu_parse_marketing_name(struct amdgpu_gpu_info *info); +const char *amdgpu_parse_marketing_name(struct amdgpu_gpu_info *info); // Local function pointers to DRM interface static typeof(drmGetDevices) *_drmGetDevices; @@ -99,6 +99,7 @@ struct __attribute__((__packed__)) unique_cache_id { unsigned client_id; pid_t pid; + char *pdev; }; struct amdgpu_process_info_cache { @@ -459,7 +460,7 @@ gpu_infos[amdgpu_count].fd = fd; gpu_infos[amdgpu_count].base.vendor = &gpu_vendor_amdgpu; - snprintf(gpu_infos[*count].base.pdev, PDEV_LEN - 1, "%04x:%02x:%02x.%d", devs[i]->businfo.pci->domain, + snprintf(gpu_infos[amdgpu_count].base.pdev, PDEV_LEN - 1, "%04x:%02x:%02x.%d", devs[i]->businfo.pci->domain, devs[i]->businfo.pci->bus, devs[i]->businfo.pci->dev, devs[i]->businfo.pci->func); initDeviceSysfsPaths(&gpu_infos[amdgpu_count]); list_add_tail(&gpu_infos[amdgpu_count].base.list, devices); @@ -528,7 +529,7 @@ * It may take long time for a Linux distribution to get latest GPU info. * here a GPU IDS is maintained, which allows to support GPU info faster. */ if (!name) { - name = amdgpu_parse_marketing_name(&info); + name = amdgpu_parse_marketing_name(&info); } static_info->device_name[MAX_DEVICE_NAME - 1] = '\0'; @@ -753,6 +754,9 @@ if (NreadPatterns == 3) { received *= maxPayloadSize; transmitted *= maxPayloadSize; + // Set in KiB + received /= 1024; + transmitted /= 1024; SET_GPUINFO_DYNAMIC(dynamic_info, pcie_rx, received); SET_GPUINFO_DYNAMIC(dynamic_info, pcie_tx, transmitted); } @@ -906,7 +910,7 @@ // busy percentage since the last measurement. if (client_id_set) { struct amdgpu_process_info_cache *cache_entry; - struct unique_cache_id ucid = {.client_id = cid, .pid = process_info->pid}; + struct unique_cache_id ucid = {.client_id = cid, .pid = process_info->pid, .pdev = gpu_info->base.pdev}; HASH_FIND_CLIENT(gpu_info->last_update_process_cache, &ucid, cache_entry); if (cache_entry) { uint64_t time_elapsed = nvtop_difftime_u64(cache_entry->last_measurement_tstamp, current_time); @@ -952,6 +956,7 @@ goto parse_fdinfo_exit; cache_entry->client_id.client_id = cid; cache_entry->client_id.pid = process_info->pid; + cache_entry->client_id.pdev = gpu_info->base.pdev; } #ifndef NDEBUG diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_gpuinfo_intel.c new/nvtop-3.0.2+2/src/extract_gpuinfo_intel.c --- old/nvtop-3.0.1+29/src/extract_gpuinfo_intel.c 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_gpuinfo_intel.c 2023-06-15 11:47:30.000000000 +0200 @@ -47,6 +47,7 @@ struct __attribute__((__packed__)) unique_cache_id { unsigned client_id; pid_t pid; + char *pdev; }; struct intel_process_info_cache { @@ -183,7 +184,7 @@ process_info->type |= gpu_process_graphical; struct intel_process_info_cache *cache_entry; - struct unique_cache_id ucid = {.client_id = cid, .pid = process_info->pid}; + struct unique_cache_id ucid = {.client_id = cid, .pid = process_info->pid, .pdev = gpu_info->base.pdev}; HASH_FIND_CLIENT(gpu_info->last_update_process_cache, &ucid, cache_entry); if (cache_entry) { uint64_t time_elapsed = nvtop_difftime_u64(cache_entry->last_measurement_tstamp, current_time); @@ -219,6 +220,7 @@ goto parse_fdinfo_exit; cache_entry->client_id.client_id = cid; cache_entry->client_id.pid = process_info->pid; + cache_entry->client_id.pdev = gpu_info->base.pdev; } #ifndef NDEBUG diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_gpuinfo_msm.c new/nvtop-3.0.2+2/src/extract_gpuinfo_msm.c --- old/nvtop-3.0.1+29/src/extract_gpuinfo_msm.c 1970-01-01 01:00:00.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_gpuinfo_msm.c 2023-06-15 11:47:30.000000000 +0200 @@ -0,0 +1,523 @@ +/* + * + * Copyright (C) 2023 Ryan Houdek <[email protected]> + * + * This file is part of Nvtop and adapted from the amdgpu implementation. + * + * Nvtop is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Nvtop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nvtop. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "nvtop/device_discovery.h" +#include "nvtop/extract_gpuinfo_common.h" +#include "nvtop/extract_processinfo_fdinfo.h" +#include "nvtop/time.h" + +#include <assert.h> +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <libdrm/msm_drm.h> +#include <stdio.h> +#include <string.h> +#include <sys/sysinfo.h> +#include <unistd.h> +#include <uthash.h> +#include <xf86drm.h> + +// extern +const char * msm_parse_marketing_name(uint64_t gpu_id); + +#define HASH_FIND_CLIENT(head, key_ptr, out_ptr) HASH_FIND(hh, head, key_ptr, sizeof(unsigned), out_ptr) +#define HASH_ADD_CLIENT(head, in_ptr) HASH_ADD(hh, head, client_id, sizeof(unsigned), in_ptr) + +#define SET_MSM_CACHE(cachePtr, field, value) SET_VALUE(cachePtr, field, value, msm_cache_) +#define RESET_MSM_CACHE(cachePtr, field) INVALIDATE_VALUE(cachePtr, field, msm_cache_) +#define MSM_CACHE_FIELD_VALID(cachePtr, field) VALUE_IS_VALID(cachePtr, field, msm_cache_) + +enum intel_process_info_cache_valid { + msm_cache_engine_render_valid = 0, + msm_cache_process_info_cache_valid_count +}; + +struct __attribute__((__packed__)) unique_cache_id { + unsigned client_id; + pid_t pid; +}; + +struct msm_process_info_cache { + struct unique_cache_id client_id; + uint64_t engine_render; + nvtop_time last_measurement_tstamp; + unsigned char valid[(msm_cache_process_info_cache_valid_count + CHAR_BIT - 1) / CHAR_BIT]; + UT_hash_handle hh; +}; + +struct gpu_info_msm { + drmVersionPtr drmVersion; + struct gpu_info base; + int fd; + + struct msm_process_info_cache *last_update_process_cache, *current_update_process_cache; // Cached processes info +}; + +static bool gpuinfo_msm_init(void); +static void gpuinfo_msm_shutdown(void); +static const char *gpuinfo_msm_last_error_string(void); +static bool gpuinfo_msm_get_device_handles(struct list_head *devices, unsigned *count); +static void gpuinfo_msm_populate_static_info(struct gpu_info *_gpu_info); +static void gpuinfo_msm_refresh_dynamic_info(struct gpu_info *_gpu_info); +static void gpuinfo_msm_get_running_processes(struct gpu_info *_gpu_info); + +struct gpu_vendor gpu_vendor_msm = { + .init = gpuinfo_msm_init, + .shutdown = gpuinfo_msm_shutdown, + .last_error_string = gpuinfo_msm_last_error_string, + .get_device_handles = gpuinfo_msm_get_device_handles, + .populate_static_info = gpuinfo_msm_populate_static_info, + .refresh_dynamic_info = gpuinfo_msm_refresh_dynamic_info, + .refresh_running_processes = gpuinfo_msm_get_running_processes, + .name = "msm", +}; + +unsigned msm_gpu_count; +static struct gpu_info_msm *gpu_infos; + +static void *libdrm_handle; + +static int last_libdrm_return_status = 0; +static char didnt_call_gpuinfo_init[] = "uninitialized"; +static const char *local_error_string = didnt_call_gpuinfo_init; + +// Local function pointers to DRM interface +static typeof(drmGetDevices) *_drmGetDevices; +static typeof(drmGetDevices2) *_drmGetDevices2; +static typeof(drmFreeDevices) *_drmFreeDevices; +static typeof(drmGetVersion) *_drmGetVersion; +static typeof(drmFreeVersion) *_drmFreeVersion; +static typeof(drmGetMagic) *_drmGetMagic; +static typeof(drmAuthMagic) *_drmAuthMagic; +static typeof(drmDropMaster) *_drmDropMaster; +static typeof(drmCommandWriteRead) *_drmCommandWriteRead; + +static int wrap_drmGetDevices(drmDevicePtr devices[], int max_devices) { + assert(_drmGetDevices2 || _drmGetDevices); + + if (_drmGetDevices2) + return _drmGetDevices2(0, devices, max_devices); + return _drmGetDevices(devices, max_devices); +} + +static void authenticate_drm(int fd) { + drm_magic_t magic; + + if (_drmGetMagic(fd, &magic) < 0) { + return; + } + + if (_drmAuthMagic(fd, magic) == 0) { + if (_drmDropMaster(fd)) { + perror("Failed to drop DRM master"); + fprintf( + stderr, + "\nWARNING: other DRM clients will crash on VT switch while nvtop is running!\npress ENTER to continue\n"); + fgetc(stdin); + } + return; + } + + // XXX: Ideally I'd implement this too, but I'd need to pull in libxcb and yet + // more functions and structs that may break ABI compatibility. + // See radeontop auth_xcb.c for what is involved here + fprintf(stderr, "Failed to authenticate to DRM; XCB authentication unimplemented\n"); +} + +#define STRINGIFY(x) STRINGIFY_HELPER_(x) +#define STRINGIFY_HELPER_(x) #x + +__attribute__((constructor)) static void init_extract_gpuinfo_msm(void) { register_gpu_vendor(&gpu_vendor_msm); } + +bool gpuinfo_msm_init(void) { + libdrm_handle = dlopen("libdrm.so", RTLD_LAZY); + if (!libdrm_handle) + libdrm_handle = dlopen("libdrm.so.2", RTLD_LAZY); + if (!libdrm_handle) + libdrm_handle = dlopen("libdrm.so.1", RTLD_LAZY); + if (!libdrm_handle) { + local_error_string = dlerror(); + return false; + } + + _drmGetDevices2 = dlsym(libdrm_handle, "drmGetDevices2"); + if (!_drmGetDevices2) + _drmGetDevices = dlsym(libdrm_handle, "drmGetDevices"); + if (!_drmGetDevices2 && !_drmGetDevices) + goto init_error_clean_exit; + + _drmFreeDevices = dlsym(libdrm_handle, "drmFreeDevices"); + if (!_drmFreeDevices) + goto init_error_clean_exit; + + _drmGetVersion = dlsym(libdrm_handle, "drmGetVersion"); + if (!_drmGetVersion) + goto init_error_clean_exit; + + _drmFreeVersion = dlsym(libdrm_handle, "drmFreeVersion"); + if (!_drmFreeVersion) + goto init_error_clean_exit; + + _drmGetMagic = dlsym(libdrm_handle, "drmGetMagic"); + if (!_drmGetMagic) + goto init_error_clean_exit; + + _drmAuthMagic = dlsym(libdrm_handle, "drmAuthMagic"); + if (!_drmAuthMagic) + goto init_error_clean_exit; + + _drmDropMaster = dlsym(libdrm_handle, "drmDropMaster"); + if (!_drmDropMaster) + goto init_error_clean_exit; + + _drmCommandWriteRead = dlsym(libdrm_handle, "drmCommandWriteRead"); + if (!_drmCommandWriteRead) + goto init_error_clean_exit; + + local_error_string = NULL; + return true; + +init_error_clean_exit: + dlclose(libdrm_handle); + libdrm_handle = NULL; + return false; +} + +void gpuinfo_msm_shutdown(void) { + for (unsigned i = 0; i < msm_gpu_count; ++i) { + struct gpu_info_msm *current = &gpu_infos[i]; + _drmFreeVersion(current->drmVersion); + } + + free(gpu_infos); + gpu_infos = NULL; + msm_gpu_count = 0; + + if (libdrm_handle) { + dlclose(libdrm_handle); + libdrm_handle = NULL; + local_error_string = didnt_call_gpuinfo_init; + } +} + +static const char *gpuinfo_msm_last_error_string(void) { + if (local_error_string) { + return local_error_string; + } else if (last_libdrm_return_status < 0) { + switch (last_libdrm_return_status) { + case DRM_ERR_NO_DEVICE: + return "no device\n"; + case DRM_ERR_NO_ACCESS: + return "no access\n"; + case DRM_ERR_NOT_ROOT: + return "not root\n"; + case DRM_ERR_INVALID: + return "invalid args\n"; + case DRM_ERR_NO_FD: + return "no fd\n"; + default: + return "unknown error\n"; + } + } else { + return "An unanticipated error occurred while accessing AMDGPU " + "information\n"; + } +} + +static const char drm_msm_engine_gpu[] = "drm-engine-gpu"; +static const char drm_msm_cycles_gpu[] = "drm-cycles-gpu"; +static const char drm_msm_maxfreq_gpu[] = "drm-maxfreq-gpu"; +static const char drm_msm_resident_mem[] = "drm-resident-memory"; + +static bool parse_drm_fdinfo_msm(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info) { + struct gpu_info_msm *gpu_info = container_of(info, struct gpu_info_msm, base); + static char *line = NULL; + static size_t line_buf_size = 0; + ssize_t count = 0; + + bool client_id_set = false; + unsigned cid; + nvtop_time current_time; + nvtop_get_current_time(¤t_time); + + while ((count = getline(&line, &line_buf_size, fdinfo_file)) != -1) { + char *key, *val; + // Get rid of the newline if present + if (line[count - 1] == '\n') { + line[--count] = '\0'; + } + + if (!extract_drm_fdinfo_key_value(line, &key, &val)) + continue; + + if (!strcmp(key, drm_client_id)) { + char *endptr; + cid = strtoul(val, &endptr, 10); + if (*endptr) + continue; + client_id_set = true; + } else { + bool is_engine = !strcmp(key, drm_msm_engine_gpu); + bool is_cycles = !strcmp(key, drm_msm_cycles_gpu); + bool is_maxfreq = !strcmp(key, drm_msm_maxfreq_gpu); + bool is_resident = !strcmp(key, drm_msm_resident_mem); + + if (is_engine || is_cycles || is_maxfreq) { + char *endptr; + uint64_t time_spent = strtoull(val, &endptr, 10); + if (endptr == val || strcmp(endptr, " ns")) + continue; + if (is_engine) { + SET_GPUINFO_PROCESS(process_info, gfx_engine_used, time_spent); + } + } + else if (is_resident) { + uint64_t mem_int; + char *endptr; + + mem_int = strtoull(val, &endptr, 10); + if (endptr == val) + continue; + + uint64_t multiplier = 1; + if (strcmp(endptr, " B") == 0) { + multiplier = 1; + } + else if (strcmp(endptr, " KiB") == 0) { + multiplier = 1024; + } + else if (strcmp(endptr, " MiB") == 0) { + multiplier = 1024 * 1024; + } + else if (strcmp(endptr, " GiB") == 0) { + multiplier = 1024 * 1024 * 1024; + } + + SET_GPUINFO_PROCESS(process_info, gpu_memory_usage, mem_int * multiplier); + } + } + } + if (!client_id_set) + return false; + + // The msm driver does not expose compute engine metrics as of yet + process_info->type |= gpu_process_graphical; + + struct msm_process_info_cache *cache_entry; + struct unique_cache_id ucid = {.client_id = cid, .pid = process_info->pid}; + HASH_FIND_CLIENT(gpu_info->last_update_process_cache, &ucid, cache_entry); + if (cache_entry) { + uint64_t time_elapsed = nvtop_difftime_u64(cache_entry->last_measurement_tstamp, current_time); + HASH_DEL(gpu_info->last_update_process_cache, cache_entry); + if (GPUINFO_PROCESS_FIELD_VALID(process_info, gfx_engine_used) && + MSM_CACHE_FIELD_VALID(cache_entry, engine_render) && + // In some rare occasions, the gfx engine usage reported by the driver is lowering (might be a driver bug) + process_info->gfx_engine_used >= cache_entry->engine_render && + process_info->gfx_engine_used - cache_entry->engine_render <= time_elapsed) { + SET_GPUINFO_PROCESS( + process_info, gpu_usage, + busy_usage_from_time_usage_round(process_info->gfx_engine_used, cache_entry->engine_render, time_elapsed)); + } + } else { + cache_entry = calloc(1, sizeof(*cache_entry)); + if (!cache_entry) + goto parse_fdinfo_exit; + cache_entry->client_id.client_id = cid; + cache_entry->client_id.pid = process_info->pid; + } + +#ifndef NDEBUG + // We should only process one fdinfo entry per client id per update + struct msm_process_info_cache *cache_entry_check; + HASH_FIND_CLIENT(gpu_info->current_update_process_cache, &cid, cache_entry_check); + assert(!cache_entry_check && "We should not be processing a client id twice per update"); +#endif + + RESET_ALL(cache_entry->valid); + if (GPUINFO_PROCESS_FIELD_VALID(process_info, gfx_engine_used)) + SET_MSM_CACHE(cache_entry, engine_render, process_info->gfx_engine_used); + + cache_entry->last_measurement_tstamp = current_time; + HASH_ADD_CLIENT(gpu_info->current_update_process_cache, cache_entry); + +parse_fdinfo_exit: + return true; +} + +static bool gpuinfo_msm_get_device_handles(struct list_head *devices, unsigned *count) { + if (!libdrm_handle) + return false; + + last_libdrm_return_status = wrap_drmGetDevices(NULL, 0); + if (last_libdrm_return_status <= 0) + return false; + + drmDevicePtr devs[last_libdrm_return_status]; + last_libdrm_return_status = wrap_drmGetDevices(devs, last_libdrm_return_status); + if (last_libdrm_return_status <= 0) + return false; + + unsigned int libdrm_count = last_libdrm_return_status; + gpu_infos = calloc(libdrm_count, sizeof(*gpu_infos)); + if (!gpu_infos) { + local_error_string = strerror(errno); + return false; + } + + for (unsigned int i = 0; i < libdrm_count; i++) { + int fd = -1; + + // Try render node first + if (1 << DRM_NODE_RENDER & devs[i]->available_nodes) { + fd = open(devs[i]->nodes[DRM_NODE_RENDER], O_RDWR); + } + if (fd < 0) { + // Fallback to primary node (control nodes are unused according to the DRM documentation) + if (1 << DRM_NODE_PRIMARY & devs[i]->available_nodes) { + fd = open(devs[i]->nodes[DRM_NODE_PRIMARY], O_RDWR); + } + } + + if (fd < 0) + continue; + + drmVersionPtr ver = _drmGetVersion(fd); + + if (!ver) { + close(fd); + continue; + } + + bool is_msm = !strcmp(ver->name, "msm"); + + if (!is_msm) { + _drmFreeVersion(ver); + close(fd); + continue; + } + + authenticate_drm(fd); + + gpu_infos[msm_gpu_count].drmVersion = ver; + gpu_infos[msm_gpu_count].fd = fd; + gpu_infos[msm_gpu_count].base.vendor = &gpu_vendor_msm; + + list_add_tail(&gpu_infos[msm_gpu_count].base.list, devices); + // Register a fdinfo callback for this GPU + processinfo_register_fdinfo_callback(parse_drm_fdinfo_msm, &gpu_infos[msm_gpu_count].base); + msm_gpu_count++; + } + + _drmFreeDevices(devs, libdrm_count); + *count = msm_gpu_count; + + return true; +} + +static int gpuinfo_msm_query_param(int gpu, uint32_t param, uint64_t *value) { + struct drm_msm_param req = { + .pipe = MSM_PIPE_3D0, // Only the 3D pipe. + .param = param, + }; + + int ret = _drmCommandWriteRead(gpu, DRM_MSM_GET_PARAM, &req, sizeof(req)); + + if (ret) + return ret; + + *value = req.value; + + return 0; +} + +void gpuinfo_msm_populate_static_info(struct gpu_info *_gpu_info) { + struct gpu_info_msm *gpu_info = container_of(_gpu_info, struct gpu_info_msm, base); + struct gpuinfo_static_info *static_info = &gpu_info->base.static_info; + const char *dev_name; + + static_info->integrated_graphics = true; + RESET_ALL(static_info->valid); + + uint64_t gpuid; + if (gpuinfo_msm_query_param(gpu_info->fd, MSM_PARAM_CHIP_ID, &gpuid) == 0) { + const char* name = msm_parse_marketing_name(gpuid); + if (name) { + strncpy(static_info->device_name, name, sizeof(static_info->device_name)); + } + else { + snprintf(static_info->device_name, sizeof(static_info->device_name), "Unknown Adreno %lx", gpuid); + } + SET_VALID(gpuinfo_device_name_valid, static_info->valid); + } +} + +void gpuinfo_msm_refresh_dynamic_info(struct gpu_info *_gpu_info) { + struct gpu_info_msm *gpu_info = container_of(_gpu_info, struct gpu_info_msm, base); + struct gpuinfo_static_info *static_info = &gpu_info->base.static_info; + struct gpuinfo_dynamic_info *dynamic_info = &gpu_info->base.dynamic_info; + + RESET_ALL(dynamic_info->valid); + dynamic_info->encode_decode_shared = true; + + // GPU clock + uint64_t val; + if (gpuinfo_msm_query_param(gpu_info->fd, MSM_PARAM_MAX_FREQ, &val) == 0) { + // TODO: No way to query current clock speed. + SET_GPUINFO_DYNAMIC(dynamic_info, gpu_clock_speed, val / 1000000); + SET_GPUINFO_DYNAMIC(dynamic_info, gpu_clock_speed_max, val / 1000000); + } + + // Mem clock + // TODO: No way to query. + + // TODO: find how to extract global utilization + // gpu util will be computed as the sum of all the processes utilization for now + + struct sysinfo info; + if (sysinfo(&info) == 0) { + SET_GPUINFO_DYNAMIC(dynamic_info, total_memory, info.totalram); + SET_GPUINFO_DYNAMIC(dynamic_info, used_memory, info.totalram - info.freeram); + SET_GPUINFO_DYNAMIC(dynamic_info, free_memory, info.freeram); + SET_GPUINFO_DYNAMIC(dynamic_info, mem_util_rate, + (dynamic_info->total_memory - dynamic_info->free_memory) * 100 / dynamic_info->total_memory); + } +} + +static void swap_process_cache_for_next_update(struct gpu_info_msm *gpu_info) { + // Free old cache data and set the cache for the next update + if (gpu_info->last_update_process_cache) { + struct msm_process_info_cache *cache_entry, *tmp; + HASH_ITER(hh, gpu_info->last_update_process_cache, cache_entry, tmp) { + HASH_DEL(gpu_info->last_update_process_cache, cache_entry); + free(cache_entry); + } + } + gpu_info->last_update_process_cache = gpu_info->current_update_process_cache; + gpu_info->current_update_process_cache = NULL; +} + +void gpuinfo_msm_get_running_processes(struct gpu_info *_gpu_info) { + // For Adreno, we register a fdinfo callback that will fill the gpu_process datastructure of the gpu_info structure + // for us. This avoids going through /proc multiple times per update for multiple GPUs. + struct gpu_info_msm *gpu_info = container_of(_gpu_info, struct gpu_info_msm, base); + swap_process_cache_for_next_update(gpu_info); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_gpuinfo_msm_utils.c new/nvtop-3.0.2+2/src/extract_gpuinfo_msm_utils.c --- old/nvtop-3.0.1+29/src/extract_gpuinfo_msm_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_gpuinfo_msm_utils.c 2023-06-15 11:47:30.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * + * Copyright (C) 2023 Ryan Houdek <[email protected]> + * + * Nvtop is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Nvtop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nvtop. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "nvtop/interface_internal_common.h" +#include <stdint.h> + +struct msm_id_struct { + uint64_t id; + const char *name; +}; + +#define GetHundredDigit(coreid) (coreid / 100) +#define GetHundred(coreid) (GetHundredDigit(coreid) * 100) +#define GetTenDigit(coreid) ((coreid - GetHundred(coreid)) / 10) +#define GetTen(coreid) (GetTenDigit(coreid) * 10) +#define GetOneDigit(coreid) (coreid - (GetHundred(coreid) + GetTen(coreid))) + +#define CHIPID(coreid) \ + (GetHundredDigit(coreid) << 24) | \ + (GetTenDigit(coreid) << 16) | \ + (GetOneDigit(coreid) << 8) + +static const struct msm_id_struct msm_ids[] = { + // Adreno 2xx + {CHIPID(200), "Adreno 200"}, + {CHIPID(201), "Adreno 201"}, + {CHIPID(205), "Adreno 205"}, + {CHIPID(220), "Adreno 220"}, + + // Adreno 3xx + {CHIPID(305), "Adreno 305"}, + {CHIPID(307), "Adreno 307"}, + {CHIPID(320), "Adreno 320"}, + {CHIPID(330), "Adreno 330"}, + + // Adreno 4xx + {CHIPID(405), "Adreno 405"}, + {CHIPID(420), "Adreno 420"}, + {CHIPID(430), "Adreno 430"}, + + // Adreno 5xx + {CHIPID(508), "Adreno 508"}, + {CHIPID(509), "Adreno 509"}, + {CHIPID(510), "Adreno 510"}, + {CHIPID(512), "Adreno 512"}, + {CHIPID(530), "Adreno 530"}, + {CHIPID(540), "Adreno 540"}, + + // Adreno 6xx + {CHIPID(615), "Adreno 615"}, + {CHIPID(616), "Adreno 616"}, + {CHIPID(618), "Adreno 618"}, + {CHIPID(619), "Adreno 619"}, + {CHIPID(620), "Adreno 620"}, + {CHIPID(630), "Adreno 630"}, + {CHIPID(640), "Adreno 640"}, + {CHIPID(650), "Adreno 650"}, + {CHIPID(660), "Adreno 660"}, + {CHIPID(680), "Adreno 680"}, + {CHIPID(690), "Adreno 690"}, + + // Adreno 7xx + {CHIPID(730), "Adreno 730"}, + {CHIPID(740), "Adreno 740"}, + + // Misc + {0x00be06030500, "Adreno 8c Gen 3"}, + {0x007506030500, "Adreno 7c+ Gen 3"}, + {0x006006030500, "Adreno 7c+ Gen 3 Lite"}, +}; + +const char * msm_parse_marketing_name(uint64_t gpu_id) { + for (unsigned i = 0; i < ARRAY_SIZE(msm_ids); i++) { + if (gpu_id == msm_ids[i].id) { + return msm_ids[i].name; + } + } + + return NULL; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/extract_processinfo_fdinfo.c new/nvtop-3.0.2+2/src/extract_processinfo_fdinfo.c --- old/nvtop-3.0.1+29/src/extract_processinfo_fdinfo.c 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/extract_processinfo_fdinfo.c 2023-06-15 11:47:30.000000000 +0200 @@ -25,13 +25,16 @@ #include <ctype.h> #include <dirent.h> #include <fcntl.h> -#include <linux/kcmp.h> #include <string.h> #include <sys/stat.h> #include <sys/syscall.h> #include <sys/sysmacros.h> #include <unistd.h> +#ifndef KCMP_FILE +#define KCMP_FILE 0 +#endif + struct callback_entry { struct gpu_info *gpu_info; processinfo_fdinfo_callback callback; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nvtop-3.0.1+29/src/info_messages_linux.c new/nvtop-3.0.2+2/src/info_messages_linux.c --- old/nvtop-3.0.1+29/src/info_messages_linux.c 2023-02-25 12:30:33.000000000 +0100 +++ new/nvtop-3.0.2+2/src/info_messages_linux.c 2023-06-15 11:47:30.000000000 +0200 @@ -41,6 +41,7 @@ "Nvtop won't be able to show AMD GPU processes on your kernel version (requires Linux >= 5.14)", "Nvtop won't be able to show Intel GPU utilization and processes on your kernel version (requires Linux >= 5.19)", "This version of Nvtop is missing support for reporting Intel GPU memory, power, fan and temperature", + "This version of Nvtop is missing support for reporting MSM power, fan and temperature", }; static const char *message_array[sizeof(allMessages) / sizeof(*allMessages)]; @@ -52,12 +53,16 @@ *messages = message_array; bool hasIntel = false; + bool hasMSM = false; bool hasAMD = false; struct gpu_info *gpuinfo; list_for_each_entry(gpuinfo, devices, list) { if (strcmp(gpuinfo->vendor->name, "Intel") == 0) { hasIntel = true; } + if (strcmp(gpuinfo->vendor->name, "msm") == 0) { + hasMSM = true; + } if (strcmp(gpuinfo->vendor->name, "AMD") == 0) { hasAMD = true; } @@ -73,4 +78,7 @@ } message_array[(*num_messages)++] = allMessages[2]; } -} \ No newline at end of file + if (hasMSM) { + message_array[(*num_messages)++] = allMessages[3]; + } +} ++++++ nvtop.obsinfo ++++++ --- /var/tmp/diff_new_pack.OKosug/_old 2023-06-22 23:27:52.274395477 +0200 +++ /var/tmp/diff_new_pack.OKosug/_new 2023-06-22 23:27:52.278395497 +0200 @@ -1,5 +1,5 @@ name: nvtop -version: 3.0.1+29 -mtime: 1677324633 -commit: d3dddbdeb16e0d5982414829a03383df93b6a4b1 +version: 3.0.2+2 +mtime: 1686822450 +commit: 9a8458b541a195a0c5cadafb66e240962c852b39
