mirror of
https://github.com/Syllo/nvtop.git
synced 2026-08-02 08:25:53 -04:00
Merge pull request #315 from xiaohuirong/master
Add support for the Raspberry Pi VideoCore GPU.
This commit is contained in:
@@ -83,6 +83,7 @@ else()
|
||||
set(NVIDIA_SUPPORT_DEFAULT ON)
|
||||
set(AMDGPU_SUPPORT_DEFAULT ON)
|
||||
set(INTEL_SUPPORT_DEFAULT ON)
|
||||
set(V3D_SUPPORT_DEFAULT ON)
|
||||
set(MSM_SUPPORT_DEFAULT ON)
|
||||
set(PANFROST_SUPPORT_DEFAULT ON)
|
||||
set(PANTHOR_SUPPORT_DEFAULT ON)
|
||||
@@ -97,6 +98,7 @@ option(APPLE_SUPPORT "Build support for Apple GPUs through Metal" ${APPLE_SUPPOR
|
||||
option(PANFROST_SUPPORT "Build support for Mali GPUs through panfrost driver" ${PANFROST_SUPPORT_DEFAULT})
|
||||
option(PANTHOR_SUPPORT "Build support for Mali GPUs through panthor driver" ${PANTHOR_SUPPORT_DEFAULT})
|
||||
option(ASCEND_SUPPORT "Build support for Ascend NPUs through Ascend DCMI" ${ASCEND_SUPPORT_DEFAULT})
|
||||
option(V3D_SUPPORT "Build support for Raspberrypi through v3d" ${V3D_SUPPORT_DEFAULT})
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ accelerators. It can handle multiple GPUs and print information about them in a
|
||||
htop-familiar way.
|
||||
|
||||
Currently supported vendors are AMD (Linux amdgpu driver), Apple (limited M1 &
|
||||
M2 support), Huawei (Ascend), Intel (Linux i915 or Xe driver), NVIDIA (Linux
|
||||
proprietary divers), Qualcomm Adreno (Linux MSM driver).
|
||||
M2 support), Huawei (Ascend), Intel (Linux i915/Xe drivers), NVIDIA (Linux
|
||||
proprietary divers), Qualcomm Adreno (Linux MSM driver), Broadcom VideoCore (Linux v3d driver).
|
||||
|
||||
Because a picture is worth a thousand words:
|
||||
|
||||
@@ -30,6 +30,7 @@ Table of Contents
|
||||
- [Adreno](#adreno)
|
||||
- [Apple](#apple)
|
||||
- [Ascend](#ascend) (only tested on 910B)
|
||||
- [VideoCore](#videocore)
|
||||
- [Build](#build)
|
||||
- [Distribution Specific Installation Process](#distribution-specific-installation-process)
|
||||
- [Ubuntu / Debian](#ubuntu--debian)
|
||||
@@ -132,6 +133,14 @@ NVTOP supports Ascend (testing on Altas 800 (910B)) by DCMI API (version 6.0.0).
|
||||
|
||||
Currently, the DCMI only supports limited APIs, missing PCIe generation, tx/rx throughput info, max power draw etc.
|
||||
|
||||
### VideoCore
|
||||
|
||||
NVTOP supports VideoCore (testing on raspberrypi 4B).
|
||||
|
||||
Supports GPU frequency, temperature, utilization, per-process utilization, GPU memory usage, and H264 decoding utilization.
|
||||
|
||||
On non-raspberry pi os, you need to use the `linux-rpi` kernel, ensure the presence of the `/dev/vcio` device, and have access permissions to the `/sys/kernel/debug` directory.
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
|
||||
@@ -100,6 +100,11 @@ if(INTEL_SUPPORT)
|
||||
target_sources(nvtop PRIVATE extract_gpuinfo_intel.c)
|
||||
endif()
|
||||
|
||||
if(V3D_SUPPORT)
|
||||
target_sources(nvtop PRIVATE extract_gpuinfo_v3d.c)
|
||||
target_sources(nvtop PRIVATE extract_gpuinfo_v3d_utils.c)
|
||||
endif()
|
||||
|
||||
if(APPLE_SUPPORT)
|
||||
target_sources(nvtop PRIVATE extract_gpuinfo_apple.m)
|
||||
target_link_libraries(nvtop PRIVATE
|
||||
|
||||
270
src/extract_gpuinfo_v3d.c
Normal file
270
src/extract_gpuinfo_v3d.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2022 Hoream Xiao <horeamx@gmail.com>
|
||||
*
|
||||
* This file is part of Nvtop.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <uthash.h>
|
||||
|
||||
int mbox_open(void);
|
||||
void mbox_close(int mb);
|
||||
void set_debug_files(int card_id);
|
||||
void set_gpuinfo_from_vcio(struct gpuinfo_dynamic_info *dynamic_info, int mb);
|
||||
void set_memory_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info);
|
||||
void set_usage_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info);
|
||||
void set_pid_usage_gpuinfo(struct gpu_process *process_info);
|
||||
void set_init_max_memory(int mb);
|
||||
|
||||
#define HASH_FIND_CLIENT(head, key_ptr, out_ptr) HASH_FIND(hh, head, key_ptr, sizeof(struct unique_cache_id), out_ptr)
|
||||
#define HASH_ADD_CLIENT(head, in_ptr) HASH_ADD(hh, head, client_id, sizeof(struct unique_cache_id), in_ptr)
|
||||
|
||||
#define SET_V3D_CACHE(cachePtr, field, value) SET_VALUE(cachePtr, field, value, v3d_cache_)
|
||||
#define RESET_V3D_CACHE(cachePtr, field) INVALIDATE_VALUE(cachePtr, field, v3d_cache_)
|
||||
#define V3D_CACHE_FIELD_VALID(cachePtr, field) VALUE_IS_VALID(cachePtr, field, v3d_cache_)
|
||||
|
||||
enum v3d_process_info_cache_valid { v3d_cache_engine_render_valid = 0, v3d_cache_process_info_cache_valid_count };
|
||||
|
||||
struct __attribute__((__packed__)) unique_cache_id {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct v3d_process_info_cache {
|
||||
struct unique_cache_id client_id;
|
||||
uint64_t engine_render;
|
||||
nvtop_time last_measurement_tstamp;
|
||||
unsigned char valid[(v3d_cache_process_info_cache_valid_count + CHAR_BIT - 1) / CHAR_BIT];
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
struct gpu_info_v3d {
|
||||
struct gpu_info base;
|
||||
int mb;
|
||||
int card_id;
|
||||
|
||||
struct nvtop_device *card_device;
|
||||
struct nvtop_device *driver_device;
|
||||
struct v3d_process_info_cache *last_update_process_cache, *current_update_process_cache; // Cached processes info
|
||||
};
|
||||
|
||||
static bool gpuinfo_v3d_init(void);
|
||||
static void gpuinfo_v3d_shutdown(void);
|
||||
static const char *gpuinfo_v3d_last_error_string(void);
|
||||
static bool gpuinfo_v3d_get_device_handles(struct list_head *devices, unsigned *count);
|
||||
static void gpuinfo_v3d_populate_static_info(struct gpu_info *_gpu_info);
|
||||
static void gpuinfo_v3d_refresh_dynamic_info(struct gpu_info *_gpu_info);
|
||||
static void gpuinfo_v3d_get_running_processes(struct gpu_info *_gpu_info);
|
||||
|
||||
struct gpu_vendor gpu_vendor_v3d = {
|
||||
.init = gpuinfo_v3d_init,
|
||||
.shutdown = gpuinfo_v3d_shutdown,
|
||||
.last_error_string = gpuinfo_v3d_last_error_string,
|
||||
.get_device_handles = gpuinfo_v3d_get_device_handles,
|
||||
.populate_static_info = gpuinfo_v3d_populate_static_info,
|
||||
.refresh_dynamic_info = gpuinfo_v3d_refresh_dynamic_info,
|
||||
.refresh_running_processes = gpuinfo_v3d_get_running_processes,
|
||||
.name = "v3d",
|
||||
};
|
||||
|
||||
unsigned v3d_gpu_count;
|
||||
static struct gpu_info_v3d *gpu_infos;
|
||||
|
||||
__attribute__((constructor)) static void init_extract_gpuinfo_v3d(void) { register_gpu_vendor(&gpu_vendor_v3d); }
|
||||
|
||||
bool gpuinfo_v3d_init(void) { return true; }
|
||||
void gpuinfo_v3d_shutdown(void) {
|
||||
for (unsigned i = 0; i < v3d_gpu_count; ++i) {
|
||||
struct gpu_info_v3d *current = &gpu_infos[i];
|
||||
nvtop_device_unref(current->card_device);
|
||||
nvtop_device_unref(current->driver_device);
|
||||
if (current->mb >= 0)
|
||||
mbox_close(current->mb);
|
||||
}
|
||||
}
|
||||
|
||||
const char *gpuinfo_v3d_last_error_string(void) { return "Err"; }
|
||||
|
||||
static bool parse_drm_fdinfo_v3d(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info) {
|
||||
if (!fdinfo_file)
|
||||
return false;
|
||||
struct gpu_info_v3d *gpu_info = container_of(info, struct gpu_info_v3d, base);
|
||||
struct unique_cache_id ucid = {.pid = process_info->pid};
|
||||
|
||||
struct v3d_process_info_cache *added_cache_entry;
|
||||
HASH_FIND_CLIENT(gpu_info->current_update_process_cache, &ucid, added_cache_entry);
|
||||
if (added_cache_entry)
|
||||
return false;
|
||||
|
||||
set_pid_usage_gpuinfo(process_info);
|
||||
nvtop_time current_time;
|
||||
nvtop_get_current_time(¤t_time);
|
||||
|
||||
process_info->type |= gpu_process_graphical;
|
||||
|
||||
struct v3d_process_info_cache *cache_entry;
|
||||
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) &&
|
||||
V3D_CACHE_FIELD_VALID(cache_entry, engine_render) &&
|
||||
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.pid = process_info->pid;
|
||||
}
|
||||
|
||||
RESET_ALL(cache_entry->valid);
|
||||
if (GPUINFO_PROCESS_FIELD_VALID(process_info, gfx_engine_used))
|
||||
SET_V3D_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 void add_v3d_cards(struct nvtop_device *dev, const char *devname, struct list_head *devices, unsigned *count) {
|
||||
struct nvtop_device *parent;
|
||||
if (nvtop_device_get_parent(dev, &parent) < 0)
|
||||
return;
|
||||
|
||||
const char *driver;
|
||||
nvtop_device_get_driver(parent, &driver);
|
||||
if (strcmp(driver, "v3d"))
|
||||
return;
|
||||
|
||||
struct gpu_info_v3d *thisGPU = &gpu_infos[v3d_gpu_count++];
|
||||
thisGPU->base.vendor = &gpu_vendor_v3d;
|
||||
thisGPU->card_device = nvtop_device_ref(dev);
|
||||
thisGPU->driver_device = nvtop_device_ref(parent);
|
||||
list_add_tail(&thisGPU->base.list, devices);
|
||||
// Register a fdinfo callback for this GPU
|
||||
processinfo_register_fdinfo_callback(parse_drm_fdinfo_v3d, &thisGPU->base);
|
||||
thisGPU->mb = mbox_open();
|
||||
if (sscanf(devname, "/dev/dri/card%d", &thisGPU->card_id) != 1)
|
||||
thisGPU->card_id = 0;
|
||||
set_debug_files(thisGPU->card_id);
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
bool gpuinfo_v3d_get_device_handles(struct list_head *devices_list, unsigned *count) {
|
||||
*count = 0;
|
||||
nvtop_device_enumerator *enumerator;
|
||||
if (nvtop_enumerator_new(&enumerator) < 0)
|
||||
return false;
|
||||
|
||||
if (nvtop_device_enumerator_add_match_subsystem(enumerator, "drm", true) < 0)
|
||||
return false;
|
||||
|
||||
if (nvtop_device_enumerator_add_match_property(enumerator, "DEVNAME", "/dev/dri/*") < 0)
|
||||
return false;
|
||||
|
||||
unsigned num_devices = 0;
|
||||
for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device;
|
||||
device = nvtop_enumerator_get_device_next(enumerator)) {
|
||||
num_devices++;
|
||||
}
|
||||
|
||||
gpu_infos = calloc(num_devices, sizeof(*gpu_infos));
|
||||
if (!gpu_infos)
|
||||
return false;
|
||||
|
||||
for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device;
|
||||
device = nvtop_enumerator_get_device_next(enumerator)) {
|
||||
num_devices++;
|
||||
const char *devname;
|
||||
if (nvtop_device_get_devname(device, &devname) < 0)
|
||||
continue;
|
||||
if (strstr(devname, "/dev/dri/card")) {
|
||||
add_v3d_cards(device, devname, devices_list, count);
|
||||
}
|
||||
}
|
||||
|
||||
nvtop_enumerator_unref(enumerator);
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpuinfo_v3d_populate_static_info(struct gpu_info *_gpu_info) {
|
||||
struct gpu_info_v3d *gpu_info = container_of(_gpu_info, struct gpu_info_v3d, base);
|
||||
struct gpuinfo_static_info *static_info = &gpu_info->base.static_info;
|
||||
const char *dev_name = "VIDEO CORE";
|
||||
|
||||
static_info->integrated_graphics = true;
|
||||
static_info->encode_decode_shared = false;
|
||||
RESET_ALL(static_info->valid);
|
||||
|
||||
snprintf(static_info->device_name, sizeof(static_info->device_name), "%s", dev_name);
|
||||
SET_VALID(gpuinfo_device_name_valid, static_info->valid);
|
||||
if (gpu_info->mb >= 0)
|
||||
set_init_max_memory(gpu_info->mb);
|
||||
}
|
||||
|
||||
void gpuinfo_v3d_refresh_dynamic_info(struct gpu_info *_gpu_info) {
|
||||
struct gpu_info_v3d *gpu_info = container_of(_gpu_info, struct gpu_info_v3d, base);
|
||||
struct gpuinfo_dynamic_info *dynamic_info = &gpu_info->base.dynamic_info;
|
||||
|
||||
RESET_ALL(dynamic_info->valid);
|
||||
|
||||
nvtop_device *card_dev_copy;
|
||||
const char *syspath;
|
||||
nvtop_device_get_syspath(gpu_info->card_device, &syspath);
|
||||
nvtop_device_new_from_syspath(&card_dev_copy, syspath);
|
||||
|
||||
set_usage_gpuinfo(dynamic_info);
|
||||
set_memory_gpuinfo(dynamic_info);
|
||||
if (gpu_info->mb >= 0)
|
||||
set_gpuinfo_from_vcio(dynamic_info, gpu_info->mb);
|
||||
nvtop_device_unref(card_dev_copy);
|
||||
}
|
||||
|
||||
static void swap_process_cache_for_next_update(struct gpu_info_v3d *gpu_info) {
|
||||
// Free old cache data and set the cache for the next update
|
||||
if (gpu_info->last_update_process_cache) {
|
||||
struct v3d_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_v3d_get_running_processes(struct gpu_info *_gpu_info) {
|
||||
// For v3d, 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_v3d *gpu_info = container_of(_gpu_info, struct gpu_info_v3d, base);
|
||||
swap_process_cache_for_next_update(gpu_info);
|
||||
}
|
||||
295
src/extract_gpuinfo_v3d_utils.c
Normal file
295
src/extract_gpuinfo_v3d_utils.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2022 Hoream Xiao <horeamx@gmail.com>
|
||||
*
|
||||
* This file is part of Nvtop and adapted from the vcgencmd 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/extract_gpuinfo_common.h"
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* use ioctl to send mbox property message
|
||||
*/
|
||||
#define DEVICE_FILE_NAME "/dev/vcio"
|
||||
#define MAJOR_NUM 100
|
||||
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
|
||||
#define MAX_STRING 1024
|
||||
#define GET_GENCMD_RESULT 0x00030080
|
||||
#define MAX_DECODER_FREQUENCE 550006336
|
||||
|
||||
int mbox_open(void);
|
||||
void mbox_close(int mb);
|
||||
void set_debug_files(int card_id);
|
||||
void set_gpuinfo_from_vcio(struct gpuinfo_dynamic_info *dynamic_info, int mb);
|
||||
void set_memory_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info);
|
||||
void set_usage_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info);
|
||||
void set_pid_usage_gpuinfo(struct gpu_process *process_info);
|
||||
void set_init_max_memory(int mb);
|
||||
|
||||
static uint64_t last_timestamp = 0;
|
||||
static uint64_t last_runtime = 0;
|
||||
static uint64_t max_gpu_memory_bytes = 128 << 20;
|
||||
|
||||
static const char measure_temp[] = "measure_temp";
|
||||
static const char measure_clock_v3d[] = "measure_clock v3d";
|
||||
static const char measure_clock_h264[] = "measure_clock h264";
|
||||
static const char get_mem_gpu[] = "get_mem gpu";
|
||||
|
||||
static char gpu_usage_file[50];
|
||||
static char gpu_pid_usage_file[50];
|
||||
static char bo_stats_file[50];
|
||||
|
||||
void set_debug_files(int card_id) {
|
||||
snprintf(gpu_usage_file, sizeof(gpu_usage_file), "/sys/kernel/debug/dri/%d/gpu_usage", card_id);
|
||||
if (access(gpu_usage_file, F_OK))
|
||||
printf("%s is not available.\n", gpu_usage_file);
|
||||
snprintf(gpu_pid_usage_file, sizeof(gpu_pid_usage_file), "/sys/kernel/debug/dri/%d/gpu_pid_usage", card_id);
|
||||
if (access(gpu_pid_usage_file, F_OK))
|
||||
printf("%s is not available.\n", gpu_pid_usage_file);
|
||||
snprintf(bo_stats_file, sizeof(bo_stats_file), "/sys/kernel/debug/dri/%d/bo_stats", card_id);
|
||||
if (access(bo_stats_file, F_OK))
|
||||
printf("%s is not available.\n", bo_stats_file);
|
||||
}
|
||||
|
||||
static int mbox_property(int mb, void *buf) {
|
||||
int ret_val = ioctl(mb, IOCTL_MBOX_PROPERTY, buf);
|
||||
|
||||
if (ret_val < 0) {
|
||||
printf("ioctl_set_msg failed:%d\n", ret_val);
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int mbox_open(void) {
|
||||
int mb;
|
||||
|
||||
// open a char device file used for communicating with kernel mbox driver
|
||||
mb = open(DEVICE_FILE_NAME, 0);
|
||||
if (mb < 0) {
|
||||
printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
|
||||
printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
|
||||
}
|
||||
return mb;
|
||||
}
|
||||
|
||||
void mbox_close(int mb) { close(mb); }
|
||||
|
||||
static unsigned gencmd(int mb, const char *command, char *result, int result_len) {
|
||||
int i = 0;
|
||||
unsigned p[(MAX_STRING >> 2) + 7];
|
||||
int len = strlen(command);
|
||||
// maximum length for command or response
|
||||
if (len + 1 >= MAX_STRING) {
|
||||
fprintf(stderr, "gencmd length too long : %d\n", len);
|
||||
return -1;
|
||||
}
|
||||
p[i++] = 0; // size
|
||||
p[i++] = 0x00000000; // process request
|
||||
|
||||
p[i++] = GET_GENCMD_RESULT; // (the tag id)
|
||||
p[i++] = MAX_STRING; // buffer_len
|
||||
p[i++] = 0; // request_len (set to response length)
|
||||
p[i++] = 0; // error response
|
||||
|
||||
memcpy(p + i, command, len + 1);
|
||||
i += MAX_STRING >> 2;
|
||||
|
||||
p[i++] = 0x00000000; // end tag
|
||||
p[0] = i * sizeof *p; // actual size
|
||||
|
||||
mbox_property(mb, p);
|
||||
result[0] = 0;
|
||||
|
||||
size_t available_space = result_len - strlen(result) - 1;
|
||||
strncat(result, (const char *)(p + 6), available_space);
|
||||
|
||||
return p[5];
|
||||
}
|
||||
|
||||
void set_init_max_memory(int mb) {
|
||||
char result[MAX_STRING] = {};
|
||||
|
||||
int ret = gencmd(mb, get_mem_gpu, result, sizeof result);
|
||||
if (!ret) {
|
||||
if (sscanf(result, "gpu=%luM", &max_gpu_memory_bytes) == 1) {
|
||||
max_gpu_memory_bytes <<= 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned cal_percentage_usage(unsigned usage, unsigned all) { return (unsigned)(100.0 * usage / all + 0.5); }
|
||||
|
||||
static void set_gpuinfo_decode(struct gpuinfo_dynamic_info *dynamic_info, int mb) {
|
||||
unsigned int decode_usage = 0;
|
||||
char result[MAX_STRING] = {};
|
||||
|
||||
int ret = gencmd(mb, measure_clock_h264, result, sizeof result);
|
||||
if (!ret) {
|
||||
if (sscanf(result, "frequency(28)=%u", &decode_usage) == 1)
|
||||
// divide current frequency by max frequency; usage rate might not be accurate.
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, decoder_rate, cal_percentage_usage(decode_usage, MAX_DECODER_FREQUENCE));
|
||||
}
|
||||
}
|
||||
|
||||
static void set_gpuinfo_temp(struct gpuinfo_dynamic_info *dynamic_info, int mb) {
|
||||
float temperature = 0;
|
||||
char result[MAX_STRING] = {};
|
||||
|
||||
int ret = gencmd(mb, measure_temp, result, sizeof result);
|
||||
if (!ret) {
|
||||
if (sscanf(result, "temp=%f'C", &temperature) == 1) {
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, gpu_temp, (unsigned)temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_gpuinfo_clock(struct gpuinfo_dynamic_info *dynamic_info, int mb) {
|
||||
unsigned int clock = 0;
|
||||
char result[MAX_STRING] = {};
|
||||
|
||||
int ret = gencmd(mb, measure_clock_v3d, result, sizeof result);
|
||||
if (!ret) {
|
||||
if (sscanf(result, "frequency(46)=%u", &clock) == 1) {
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, gpu_clock_speed, clock >> 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_gpuinfo_from_vcio(struct gpuinfo_dynamic_info *dynamic_info, int mb) {
|
||||
set_gpuinfo_temp(dynamic_info, mb);
|
||||
set_gpuinfo_clock(dynamic_info, mb);
|
||||
set_gpuinfo_decode(dynamic_info, mb);
|
||||
}
|
||||
|
||||
void set_memory_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info) {
|
||||
FILE *fp = fopen(bo_stats_file, "rb");
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
uint64_t allocated_bo_size_kb = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (sscanf(line, "allocated bo size (kb): %lu", &allocated_bo_size_kb) == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
uint64_t allocated_bo_size_bytes = allocated_bo_size_kb << 10;
|
||||
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, used_memory, allocated_bo_size_bytes);
|
||||
if (allocated_bo_size_bytes >= max_gpu_memory_bytes)
|
||||
max_gpu_memory_bytes = allocated_bo_size_bytes;
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, total_memory, max_gpu_memory_bytes);
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, mem_util_rate, cal_percentage_usage(allocated_bo_size_bytes, max_gpu_memory_bytes));
|
||||
}
|
||||
|
||||
void set_usage_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info) {
|
||||
FILE *fp = fopen(gpu_usage_file, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
return;
|
||||
|
||||
char *buf = NULL;
|
||||
size_t res = 0;
|
||||
unsigned jobs, active;
|
||||
uint64_t timestamp, elapsed, runtime;
|
||||
|
||||
while (getline(&buf, &res, fp) > 0) {
|
||||
if (sscanf(buf, "timestamp;%lu;", ×tamp) == 1) {
|
||||
elapsed = timestamp - last_timestamp;
|
||||
last_timestamp = timestamp;
|
||||
} else if (sscanf(strchr(buf, ';'), ";%u;%lu;%u;", &jobs, &runtime, &active) == 3) {
|
||||
if (!strncmp(buf, "v3d_render", 10))
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
int usage = busy_usage_from_time_usage_round(runtime, last_runtime, elapsed);
|
||||
last_runtime = runtime;
|
||||
SET_GPUINFO_DYNAMIC(dynamic_info, gpu_util_rate, usage);
|
||||
return;
|
||||
}
|
||||
|
||||
static pid_t get_tgid_from_tid(pid_t tid) {
|
||||
char path[40];
|
||||
struct dirent *entry;
|
||||
DIR *dp;
|
||||
pid_t min_tid = INT_MAX;
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/task/", tid);
|
||||
|
||||
dp = opendir(path);
|
||||
if (dp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dp)) != NULL) {
|
||||
int current_tid = atoi(entry->d_name);
|
||||
if (current_tid > 0 && current_tid < min_tid) {
|
||||
min_tid = current_tid;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
return min_tid;
|
||||
}
|
||||
|
||||
void set_pid_usage_gpuinfo(struct gpu_process *process_info) {
|
||||
FILE *fp = fopen(gpu_pid_usage_file, "rb");
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *buf = NULL;
|
||||
size_t res = 0;
|
||||
unsigned jobs, active;
|
||||
pid_t tid;
|
||||
uint64_t runtime;
|
||||
uint64_t timestamp;
|
||||
|
||||
while (getline(&buf, &res, fp) > 0) {
|
||||
if (sscanf(buf, "timestamp;%lu;", ×tamp) == 1) {
|
||||
} else if (sscanf(strchr(buf, ';'), ";%u;%u;%lu;%u;", &tid, &jobs, &runtime, &active) == 4) {
|
||||
if (!strncmp(buf, "v3d_render", 10)) {
|
||||
if (get_tgid_from_tid(tid) == process_info->pid) {
|
||||
SET_GPUINFO_PROCESS(process_info, gfx_engine_used, runtime);
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SET_GPUINFO_PROCESS(process_info, gfx_engine_used, 0);
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user