6 Commits
Author SHA1 Message Date
moosecrap a8bea7b62c Fixes to overwrite mode 2026-09-30 00:35:04 -07:00
moosecrap 3f3e03755f Documentation update 2026-09-30 00:34:49 -07:00
moosecrap bfbc978da8 Blackwell die, system, and VRAM temps.
Code reorganization to better support non-iCX cards.
2026-09-30 00:16:02 -07:00
moosecrap cecc34f0a6 Pull out card functions from evga-card 2026-09-29 01:28:05 -07:00
moosecrap 30bf43627d Commenting and reordering 2026-09-20 22:06:27 -07:00
moosecrap a729bdee3b Added DCGM metrics for those with Quadro cards.
Updated include paths for certain CUDA installations
2025-12-06 14:23:36 -08:00
15 changed files with 692 additions and 318 deletions
+7 -7
View File
@@ -1,19 +1,19 @@
.PHONY : clean debug
OBJS = evga-icx.o evga-card.o icx3.o board-sensors.o zen3-rapl.o
OBJS = blackwell-sensors.o card.o evga-icx.o evga-card.o gddr6.o icx3.o board-sensors.o zen3-rapl.o
LDLIBS = -li2c -lm
CFLAGS = -MD
CFLAGS = -MD -I/usr/local/cuda/targets/x86_64-linux/include/
ifdef USE_NVML
LDLIBS += -lnvidia-ml
LDLIBS += -lnvidia-ml -L/usr/local/cuda/targets/x86_64-linux/lib/stubs/
CFLAGS += -DUSE_NVML
OBJS += nvidia-sensors.o
endif
ifdef USE_LIBPCI
LDLIBS += -lpci
CFLAGS += -DUSE_LIBPCI
OBJS += gddr6.o
ifdef USE_DCGM
LDLIBS += -ldcgm
CFLAGS += -DUSE_DCGM -I/usr/include/datacenter-gpu-manager-4/
OBJS += nvidia-dcgm.o
endif
evga-icx : $(OBJS)
+7 -2
View File
@@ -2,6 +2,8 @@
This program allows you to read temperature sensors off of supported EVGA 30-series iCX3 video cards, as well as control the fans individually.
Also a mashup of a bunch of other temperature sensor stuff too like Blackwell cards, lm_sensors, and DCGM metrics that I have just thrown in here.
## Prerequisites
A supported EVGA 30-series card with iCX3. This includes:
* RTX 3060 Ti
@@ -23,7 +25,7 @@ Access to the `/dev/i2c` device files, which means either:
## Dependencies
* libi2c-dev
* libnvidia-ml-dev (if building with `USE_NVML=1`)
* libpci-dev (if building with `USE_LIBPCI=1`)
* datacenter-gpu-manager-4-dev (if building with `USE_DCGM=1`)
## Building
`make`
@@ -34,7 +36,10 @@ Access to the `/dev/i2c` device files, which means either:
Add the make flag `USE_NVML=1` and the it will also display the main GPU temperature ("GPU1") as reported by the NVIDIA driver. It will also display the performance cap/clock reason and memory controller utilization. This requires the NVIDIA management library (NVML) to be installed.
### VRAM and Hotspot temperature
Add the make flag `USE_LIBPCI=1` and you can also read the VRAM and "hotspot" temperatures. These require direct memory access to the PCI device so you must run as root and also enable the kernel parameter `iomem=relaxed`. These sensors are **extremely** undocumented so I can't say anything about their accuracy.
Run as root and you can also read the VRAM and "hotspot" temperatures. These require access the BAR0 through the `/sys/bus/pci/devices/*/resource0` device files. These sensors are **extremely** undocumented so I can't say anything about their accuracy. If you have a Blackwell (50 series) card you can read all 4 die temp sensors, a 'system' temperature, and every individual VRAM chip temp (add your card in blackwell-temps.c).
### Datacenter GPU Manager metrics
Add the make flag `USE_DCGM=1` and it can display real-time metrics from supported Nvidia GPUs like SM occupancy, integer/fp pipe usage, tensor usage, and DRAM bandwidth utilization. This requires a Quadro/Workstation or a Tesla/Datacenter card, it does not work on GeForce cards.
### Hardware monitoring
This program can also monitor hardware sensors using the standard linux `hwmon` API. See board-sensors.h for examples of how to configure these, they must be staticlly compiled in.
+187
View File
@@ -0,0 +1,187 @@
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdint.h>
#include <math.h>
#include "blackwell-sensors.h"
/* Number of die sensors, 4 for Blackwell */
#define BLACKWELL_NUM_DIE_SENSORS 4
/* Memory spacing between DRAM FBPA blocks */
#define BLACKWELL_FBPA_STRIDE 0x4000
/* Maximum count of FBPA blocks, technically up to 18 but no consumer card has more than 8 */
#define BLACKWELL_MAX_NUM_FBPA 9
/* Yeah I know this is duplicated */
#define HEADER_COLOR_START "\x1b[36m"
#define HEADER_COLOR_END "\x1b[39m"
static float read_temp_sensor(void *addr);
static int read_dram_temp_sensor(void *addr);
struct blackwell_card_info {
char *card_name;
unsigned short vendor_id;
unsigned short device_id;
int die_temp_offset[BLACKWELL_NUM_DIE_SENSORS];
int sys_temp_offset;
int dram_temp_offset_start;
int clamshell; /* If the card has dual-side ram, if not then half the DRAM temps are repeated */
};
static struct blackwell_card_info blackwell_card_list[] =
{
{"NVIDIA RTX PRO 6000 Blackwell Workstation Edition", NVIDIA_VEN, NVIDIA_RTXPRO6000_WORKSTATION_DEV, {0xAD0A90, 0xAD0A94, 0xAD0A98, 0xAD0A9C}, 0xAD06EC, 0x9024C0, true}
};
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
and respond with the correct iCX3 version information */
int find_blackwell_gpus(struct card_info *infos, int num_gpus, int max_gpus)
{
char pci_devices_path[PATH_MAX];
char device_path[PATH_MAX];
char dev_file[PATH_MAX];
char pci_path[PATH_MAX];
char *pci_addr;
DIR *dir;
struct dirent *ent;
unsigned short pci_vendor, pci_device = 0;
/* Start looking for PCI */
strcpy(pci_devices_path, "/sys/bus/pci/devices/");
dir = opendir(pci_devices_path);
/* make sure we can open the PCI device */
if(dir == NULL)
return num_gpus;
/* loop over all PCI devices */
while((ent = readdir(dir)) != NULL)
{
strcpy(device_path, pci_devices_path);
strcat(device_path, ent->d_name);
pci_vendor = read_pci_id(device_path, "/vendor");
pci_device = read_pci_id(device_path, "/device");
/* See if it's a supported Blackwell card*/
for (int i = 0; i < (sizeof(blackwell_card_list) / sizeof(struct blackwell_card_info)); i++) {
if (pci_vendor == blackwell_card_list[i].vendor_id &&
pci_device == blackwell_card_list[i].device_id) {
infos[num_gpus].card_name = blackwell_card_list[i].card_name;
infos[num_gpus].pci_id = strdup(ent->d_name);
infos[num_gpus].pci_dev_path = strdup(device_path);
infos[num_gpus].pci_device_id = pci_device;
infos[num_gpus].i2c_dev_path = NULL;
infos[num_gpus].i2c_fd = -1;
mmap_bar0(&infos[num_gpus]);
num_gpus++;
break;
}
}
if (num_gpus == max_gpus)
break;
}
return num_gpus;
}
void print_blackwell_info(int compact, int overwrite, struct card_info *gpu)
{
if (gpu->bar0_mmap == NULL)
return;
for (int i = 0; i < (sizeof(blackwell_card_list) / sizeof(struct blackwell_card_info)); i++) {
if (!compact)
printf("%s @ %s\n", gpu->card_name, gpu->pci_id);
float temp;
if (blackwell_card_list[i].device_id == gpu->pci_device_id) {
/* Print die sensors */
if (compact)
printf("%sDIE%s", HEADER_COLOR_START, HEADER_COLOR_END);
for (int die_sens_num = 0; die_sens_num < BLACKWELL_NUM_DIE_SENSORS; die_sens_num++) {
temp = read_temp_sensor(gpu->bar0_mmap + blackwell_card_list[i].die_temp_offset[die_sens_num]);
if (compact)
printf(" %3.0f", temp);
else
printf("Die %d: %+.1f°C\n", die_sens_num, temp);
}
/* Sys temp */
temp = read_temp_sensor(gpu->bar0_mmap + blackwell_card_list[i].sys_temp_offset);
if (compact)
printf(" %sSYS%s %3.0f", HEADER_COLOR_START, temp, HEADER_COLOR_END);
else
printf("System: %+.1f°C\n", temp);
/* DRAM temps */
int dram_num = 0;
int num_channels = blackwell_card_list[i].clamshell ? 4 : 2;
int dram_max = 0;
int dram_min = 120;
int dram_total = 0.0;
for (int fbpa_num = 0; fbpa_num < BLACKWELL_MAX_NUM_FBPA; fbpa_num++) {
for (int chan_num = 0; chan_num < num_channels; chan_num++) {
temp = read_dram_temp_sensor(gpu->bar0_mmap +
blackwell_card_list[i].dram_temp_offset_start +
BLACKWELL_FBPA_STRIDE * fbpa_num +
0x4 * chan_num +
2);
if (temp == 0.0)
break;
dram_max = (temp > dram_max) ? temp : dram_max;
dram_min = (temp < dram_min) ? temp : dram_min;
dram_total += temp;
if (!compact)
printf("DRAM %i: %+.0f°C\n", dram_num, temp);
dram_num++;
}
}
if (compact) {
printf(" %sDRAM HI%s %3.0f %sAVG%s %5.1f %sLO%s %3.0f",
HEADER_COLOR_START,
HEADER_COLOR_END,
(float)dram_max,
HEADER_COLOR_START,
HEADER_COLOR_END,
(float)dram_total/dram_num,
HEADER_COLOR_START,
HEADER_COLOR_END,
(float)dram_min);
} else {
printf("DRAM average: %+.1f°C\n", (float)dram_total/dram_num);
printf("DRAM min: %+.0f°C\n", (float)dram_min);
printf("DRAM max: %+.0f°C\n", (float)dram_max);
}
return;
}
}
}
float read_temp_sensor(void *addr)
{
return (*(uint16_t *)addr) / (float)0x100;
}
int read_dram_temp_sensor(void *addr)
{
uint16_t raw = *(uint16_t *)addr;
if (raw == 0xBADF)
return 0.0;
int code = (raw >> 8) & 0xFF;
if (code > 80) code = 80;
return (code > 19) ? (code - 20) * 2 : -(40 - code * 2);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef BLACKWELL_SENSORS_H
#define BLACKWELL_SENSORS_H
#include "card.h"
#endif
int find_blackwell_gpus(struct card_info *infos, int num_gpus, int max_gpus);
void print_blackwell_info(int compact, int overwrite, struct card_info *gpu);
+28 -27
View File
@@ -18,33 +18,34 @@ struct hwmon_sensor {
/* Note the order here matters, it's the order these will be printed in */
static struct hwmon_sensor hwmon_sensor_info[] =
{
{"zenpower", "temp1", "CPU ", "CPU", "°C", 1000.0, -40.0 }, /* Tdie */
{"asusec", "temp2", "Motherboard ", "CPU", "°C", 1000.0, -40.0 }, /* CPU */
{"zenpower", "temp3", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd1 */
{"zenpower", "temp4", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd2 */
{"zenpower", "temp5", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd3 */
{"zenpower", "temp6", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd4 */
{"zenpower", "temp7", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd5 */
{"zenpower", "temp8", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd6 */
{"zenpower", "temp9", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd7 */
{"zenpower", "temp10", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd8 */
{"zen-rapl", "", "CPU ", "POW", " W", 0.0, 0.0 }, /* Zen RAPL placeholder */
{"asusec", "temp1", "Motherboard ", "CHIP", "°C", 1000.0, -40.0 }, /* Chipset */
{"asusec", "temp5", "Motherboard ", "VRM", "°C", 1000.0, -40.0 }, /* VRM */
{"asusec", "temp3", "", "MOBO", "°C", 1000.0, -40.0 }, /* Motherboard */
{"asusec", "temp4", "Motherboard ", "SENS", "°C", 1000.0, -40.0 }, /* T_Sensor */
{"asusec", "temp6", "Motherboard ", "H2O", "°C", 1000.0, -40.0 }, /* Water_In */
{"asusec", "temp7", "Motherboard ", "H2O", "°C", 1000.0, -40.0 }, /* Water_Out */
{"nvme", "temp1", "NVMe ", "NVME", "°C", 1000.0, -40.0 }, /* NVME Composite */
{"nct6798", "fan2", "CPU fan", "CPU", "%", 15.0, 0.0 }, /* cpu_fan, cpu mid */
{"asusec", "fan1", "", "CPU", "%", 15.0, 0.0 }, /* cpu_opt, cpu front */
{"nct6798", "fan5", "H amp", "CHA", "%", 12.0, 0.0 }, /* h_amp, front fan */
{"nct6798", "fan3", "Chassis 2", "CHA", "%", 12.0, 0.0 }, /* cha2, top front */
{"nct6798", "fan1", "Chassis 1", "CHA", "%", 12.0, 0.0 }, /* cha1, top rear */
{"nct6798", "fan4", "Chassis 3", "CHA", "%", 13.0, 0.0 }, /* cha3, rear */
{"nct6798", "fan6", "AIO pump", "CHA", "%", 12.0, 0.0 }, /* aio_pump? */
{"nct6798", "fan7", "W pump", "CHA", "%", 12.0, 0.0 }, /* w_pump+? */
{"asusec", "fan2", "", "CHIP", "%", 35.0, 0.0 }, /* chipset */
{"zenpower", "temp1", "CPU ", "CPU", "°C", 1000.0, -40.0 }, /* Tdie */
{"asusec", "temp2", "Motherboard ", "CPU", "°C", 1000.0, -40.0 }, /* CPU */
{"zenpower", "temp3", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd1 */
{"zenpower", "temp4", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd2 */
{"zenpower", "temp5", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd3 */
{"zenpower", "temp6", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd4 */
{"zenpower", "temp7", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd5 */
{"zenpower", "temp8", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd6 */
{"zenpower", "temp9", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd7 */
{"zenpower", "temp10", "CPU ", "CCD", "°C", 1000.0, -40.0 }, /* Tccd8 */
{"zen-rapl", "", "CPU ", "POW", " W", 0.0, 0.0 }, /* Zen RAPL placeholder */
{"asusec", "temp1", "Motherboard ", "CHIP", "°C", 1000.0, -40.0 }, /* Chipset */
{"asusec", "temp5", "Motherboard ", "VRM", "°C", 1000.0, -40.0 }, /* VRM */
{"asusec", "temp3", "", "MOBO", "°C", 1000.0, -40.0 }, /* Motherboard */
/*{"r8169_0_500:00", "temp1", "Ethernet", "ETH", "°C", 1000.0, -40.0 }, /* Ethernet adapter */
{"nvme", "temp1", "NVMe ", "NVME", "°C", 1000.0, -40.0 }, /* NVME Composite */
{"asusec", "temp6", "Motherboard ", "AIR", "°C", 1000.0, -40.0 }, /* Water_In */
{"asusec", "temp4", "Motherboard ", "AIR", "°C", 1000.0, -40.0 }, /* T_Sensor */
{"asusec", "temp7", "Motherboard ", "AIR", "°C", 1000.0, -40.0 }, /* Water_Out */
{"nct6798", "fan2", "CPU fan", "CPU", "%", 15.0, 0.0 }, /* cpu_fan, cpu mid */
{"asusec", "fan1", "", "CPU", "%", 15.0, 0.0 }, /* cpu_opt, cpu front */
{"nct6798", "fan5", "H amp", "CHA", "%", 12.0, 0.0 }, /* h_amp, front fan */
{"nct6798", "fan3", "Chassis 2", "CHA", "%", 12.0, 0.0 }, /* cha2, top front */
{"nct6798", "fan1", "Chassis 1", "CHA", "%", 12.0, 0.0 }, /* cha1, top rear */
{"nct6798", "fan4", "Chassis 3", "CHA", "%", 13.0, 0.0 }, /* cha3, rear */
{"nct6798", "fan6", "AIO pump", "CHA", "%", 12.0, 0.0 }, /* aio_pump? */
{"nct6798", "fan7", "W pump", "CHA", "%", 12.0, 0.0 }, /* w_pump+? */
{"asusec", "fan2", "", "CHIP", "%", 35.0, 0.0 }, /* chipset */
};
struct hwmon_avail_sensor {
+96
View File
@@ -0,0 +1,96 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "card.h"
/* Read a 16-bit unsigned int from a pci id file */
unsigned short read_pci_id(char *device_path, char *field)
{
char buf[16];
char file_path[PATH_MAX];
strcpy(file_path, device_path);
strcat(file_path, field);
FILE *fp = fopen(file_path, "r");
if (fp == NULL)
return 0;
if (fgets(buf, sizeof(buf), fp) == NULL) {
fclose(fp);
return 0;
}
fclose(fp);
return (unsigned short)strtoul(buf, NULL, 16);
}
/* Read a PCI ID from the name of an Nvidia i2c device */
char *read_nvidia_pci_address(char *device_path)
{
char file_path[PATH_MAX];
char *ret = calloc(16 + 1, sizeof(char)); /* assuming pci ids could look as large as 00000000:0C:00.0 */
strcpy(file_path, device_path);
strcat(file_path, "/name");
FILE *fp = fopen(file_path, "r");
if (fp == NULL) {
free(ret);
return NULL;
}
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
fclose(fp);
if (strlen(ret) == 0) {
free(ret);
return NULL;
}
return ret;
}
/* Open an mmap to the BAR0 of a PCI device using its /sys/bus/pci device files */
void mmap_bar0(struct card_info *card)
{
char resource_path[PATH_MAX];
snprintf(resource_path, sizeof(resource_path), "%s/resource0", card->pci_dev_path);
/* Open FD on the resource file */
int fd = open(resource_path, O_RDONLY);
if (fd == -1) {
printf("Unable to open %s\n", resource_path);
card->bar0_mmap = NULL;
return;
}
/* Figure out the size of BAR0 fomr the size of the resource file */
struct stat st;
if (fstat(fd, &st) == -1) {
printf("Unable to stat %s\n", resource_path);
close(fd);
card->bar0_mmap = NULL;
return;
}
/* mmap the bar0 resource file */
card->bar0_mmap = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (card->bar0_mmap == MAP_FAILED) {
printf("Unable to mmap %s\n", resource_path);
card->bar0_mmap = NULL;
}
/* mmap stays open after the FD has been closed */
close(fd);
}
+38
View File
@@ -0,0 +1,38 @@
#define NVIDIA_VEN 0x10DE
#define NVIDIA_RTX3060_DEV 0x2503
#define NVIDIA_RTX3060_GA104_DEV 0x2487
#define NVIDIA_RTX3060_GA106_DEV 0x2503
#define NVIDIA_RTX3060_LHR_DEV 0x2504
#define NVIDIA_RTX3060TI_DEV 0x2486
#define NVIDIA_RTX3060TI_GDDR6X_DEV 0x24C9
#define NVIDIA_RTX3060TI_LHR_DEV 0x2489
#define NVIDIA_RTX3060TI_V1_LHR_DEV 0x2414
#define NVIDIA_RTX3070_DEV 0x2484
#define NVIDIA_RTX3070_LHR_DEV 0x2488
#define NVIDIA_RTX3070TI_DEV 0x2482
#define NVIDIA_RTX3070TI_GA102_DEV 0x2207
#define NVIDIA_RTX3080_DEV 0x2206
#define NVIDIA_RTX3080_LHR_DEV 0x2216
#define NVIDIA_RTX3080_12G_LHR_DEV 0x220A
#define NVIDIA_RTX3080TI_DEV 0x2208
#define NVIDIA_RTX3090_DEV 0x2204
#define NVIDIA_RTX3090TI_DEV 0x2203
#define NVIDIA_RTXPRO6000_WORKSTATION_DEV 0x2BB1
struct card_info {
char *card_name; /* The 'nice' name of the card */
char *pci_id; /* PCI bus address in domain:bus:device.function format. May be shortened (e.g. c:00.0) */
char *pci_dev_path; /* Path to the PCI device file */
void *bar0_mmap; /* Mmap of the PCI BAR0 */
unsigned short pci_device_id; /* The device ID of the card, i.e. corresponds to the NVIDIA model number */
char *i2c_dev_path; /* Path to the i2c device file */
int i2c_fd; /* File descriptor for the i2c device file, for re-use */
int product_id; /* EVGA internal product ID, as reported by the iCX3 controller */
void *nvml_device; /* Pointer to nvmlDevice_t for use in NVML calls */
};
unsigned short read_pci_id(char *device_path, char *field);
char *read_nvidia_pci_address(char *device_path);
void mmap_bar0(struct card_info *card);
+74 -55
View File
@@ -6,6 +6,77 @@
#include "evga-card.h"
#include "icx3.h"
struct gpu_pci_info {
char *card_name;
unsigned short vendor_id;
unsigned short device_id;
unsigned short subvendor_id;
unsigned short subdevice_id;
};
static struct gpu_pci_info evga_pci_ids[] =
{
{"EVGA GeForce RTX 3060 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3060 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3060 Ti FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3060TI_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_KL_SUB_DEV },
{"EVGA GeForce RTX 3070 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_GAMING_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_FTW3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti FTW3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_FTW3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Black" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Black LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_BLACK_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Gaming LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_GAMING_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hybrid LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HYBRID_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra v2 LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_LHR_V2_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid Gaming LHR" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra 12G" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra 12GB" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hydro Copper 12G" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_ULTRA_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Black" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra v3" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_V3_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 K|NGP|N Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 K|NGP|N Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV }
};
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
and respond with the correct iCX3 version information */
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
@@ -46,7 +117,6 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
continue;
}
strcpy(device_path, i2c_devices_path);
strcat(device_path, ent->d_name);
@@ -81,9 +151,10 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
/* Write our card info into the provided struct array */
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
infos[num_gpus].pci_id = pci_addr;
infos[num_gpus].pci_dev_path = strdup(pci_path);
infos[num_gpus].pci_device_id = pci_device;
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
infos[num_gpus].i2c_dev_path = strdup(dev_file);
mmap_bar0(&infos[num_gpus]);
num_gpus++;
break;
}
@@ -92,59 +163,7 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
if (num_gpus == max_gpus)
break;
}
return num_gpus;
}
/* Read a 16-bit unsigned int from a pci id file */
unsigned short read_pci_id(char *device_path, char *field)
{
char buf[16];
char file_path[PATH_MAX];
strcpy(file_path, device_path);
strcat(file_path, field);
FILE *fp = fopen(file_path, "r");
if (fp == NULL)
return 0;
if (fgets(buf, sizeof(buf), fp) == NULL) {
fclose(fp);
return 0;
}
fclose(fp);
return (unsigned short)strtoul(buf, NULL, 16);
}
char *read_nvidia_pci_address(char *device_path)
{
char file_path[PATH_MAX];
char *ret = calloc(16 + 1, sizeof(char)); /* assuming pci ids could look as large as 00000000:0C:00.0 */
strcpy(file_path, device_path);
strcat(file_path, "/name");
FILE *fp = fopen(file_path, "r");
if (fp == NULL) {
free(ret);
return NULL;
}
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
fclose(fp);
if (strlen(ret) == 0) {
free(ret);
return NULL;
}
return ret;
}
+1 -104
View File
@@ -1,26 +1,7 @@
#ifndef EVGA_CARD_H
#define EVGA_CARD_H
#define NVIDIA_VEN 0x10DE
#define NVIDIA_RTX3060_DEV 0x2503
#define NVIDIA_RTX3060_GA104_DEV 0x2487
#define NVIDIA_RTX3060_GA106_DEV 0x2503
#define NVIDIA_RTX3060_LHR_DEV 0x2504
#define NVIDIA_RTX3060TI_DEV 0x2486
#define NVIDIA_RTX3060TI_GDDR6X_DEV 0x24C9
#define NVIDIA_RTX3060TI_LHR_DEV 0x2489
#define NVIDIA_RTX3060TI_V1_LHR_DEV 0x2414
#define NVIDIA_RTX3070_DEV 0x2484
#define NVIDIA_RTX3070_LHR_DEV 0x2488
#define NVIDIA_RTX3070TI_DEV 0x2482
#define NVIDIA_RTX3070TI_GA102_DEV 0x2207
#define NVIDIA_RTX3080_DEV 0x2206
#define NVIDIA_RTX3080_LHR_DEV 0x2216
#define NVIDIA_RTX3080_12G_LHR_DEV 0x220A
#define NVIDIA_RTX3080TI_DEV 0x2208
#define NVIDIA_RTX3090_DEV 0x2204
#define NVIDIA_RTX3090TI_DEV 0x2203
#include "card.h"
#define EVGA_SUB_VEN 0x3842
@@ -83,90 +64,6 @@
#define EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV 0x4983
#define EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV 0x4985
struct card_info {
char *card_name; /* The 'nice' name of the card */
char *pci_id; /* PCI bus address in domain:bus:device.function format. May be shortened (e.g. c:00.0) */
unsigned short pci_device_id; /* The device ID of the card, i.e. corresponds to the NVIDIA model number */
char *i2c_dev_path; /* Path to the i2c device file */
int i2c_fd; /* File descriptor for the i2c device file, for re-use */
int product_id; /* EVGA internal product ID, as reported by the iCX3 controller */
unsigned int bar0; /* Address of the card's PCI base address register */
void *nvml_device; /* Pointer to nvmlDevice_t for use in NVML calls */
void *vram_addr; /* Memory mapping for GDDR6 temps */
void *hotspot_addr; /* Memory mapping for hotspot temperature */
};
struct gpu_pci_info {
char *card_name;
unsigned short vendor_id;
unsigned short device_id;
unsigned short subvendor_id;
unsigned short subdevice_id;
};
static struct gpu_pci_info evga_pci_ids[] =
{
{"EVGA GeForce RTX 3060 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3060 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3060 Ti FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3060TI_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_KL_SUB_DEV },
{"EVGA GeForce RTX 3070 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 XC3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_XC3_ULTRA_GAMING_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070_DEV, EVGA_SUB_VEN, EVGA_RTX3070_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3070_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3070_FTW3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti XC3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_XC3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3070 Ti FTW3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, EVGA_SUB_VEN, EVGA_RTX3070TI_FTW3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Black" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Black LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_BLACK_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Gaming LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_GAMING_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hybrid LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HYBRID_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_XC3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra v2 LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_LHR_V2_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid LHR" , NVIDIA_VEN, NVIDIA_RTX3080_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_LHR_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hybrid Gaming LHR" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HYBRID_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080_DEV, EVGA_SUB_VEN, EVGA_RTX3080_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 XC3 Ultra 12G" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra 12GB" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 FTW3 Ultra Hydro Copper 12G" , NVIDIA_VEN, NVIDIA_RTX3080_12G_LHR_DEV, EVGA_SUB_VEN, EVGA_RTX3080_12G_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_ULTRA_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti XC3 Gaming Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_XC3_GAMING_HC_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3080 Ti FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, EVGA_SUB_VEN, EVGA_RTX3080TI_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Black" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 XC3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_XC3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra v2" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_V2_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra v3" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_V3_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 FTW3 Ultra Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_FTW3_ULTRA_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 K|NGP|N Hybrid" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HYBRID_SUB_DEV },
{"EVGA GeForce RTX 3090 K|NGP|N Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV }
};
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus);
unsigned short read_pci_id(char *device_path, char *field);
char *read_nvidia_pci_address(char *device_path);
#endif
+34 -20
View File
@@ -6,13 +6,15 @@
#include <stdlib.h>
#ifdef USE_NVML
#include "nvidia-sensors.h"
#include "nvidia-sensors.h"
#endif
#ifdef USE_LIBPCI
#ifdef USE_DCGM
#include "nvidia-dcgm.h"
#endif
#include "blackwell-sensors.h"
#include "gddr6.h"
#endif
#include "icx3.h"
#include "evga-card.h"
#include "board-sensors.h"
@@ -146,6 +148,8 @@ int main (int argc, char **argv)
/* Scan for supported GPUs */
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS, i2c_bus);
/* Scan for supported Blackwell GPUs */
gpu_count = find_blackwell_gpus(gpus, gpu_count, MAX_GPUS);
/* Check for no GPUs found or other errors */
if (gpu_count == -1) {
@@ -153,7 +157,6 @@ int main (int argc, char **argv)
return -1;
} else if (gpu_count == 0) {
printf("No supported GPUs found.\nAre you root or do you have udev access to i2c devices?\nDo you need to run `modprobe i2c-dev`?\n");
return -1;
}
/* Check for invalid GPUs */
if (gpu_num > gpu_count - 1) {
@@ -195,10 +198,8 @@ int main (int argc, char **argv)
}
#endif
/* PCI init for VRAM/hotspot temps */
#ifdef USE_LIBPCI
for (int i = 0; i < gpu_count; i++)
init_gddr6(&gpus[i]);
#ifdef USE_DCGM
init_dcgm();
#endif
/* print sensor info */
@@ -215,19 +216,37 @@ int main (int argc, char **argv)
for (int i = 0; i < gpu_count; i++){
if (i > 0)
printf("\n");
print_gpu_info(i, &gpus[i]);
if (gpus[i].i2c_dev_path == NULL) {
print_blackwell_info(compact, overwrite, &gpus[i]);
} else {
print_gpu_info(i, &gpus[i]);
}
}
} else if (gpu_num <= gpu_count - 1) {
print_gpu_info(gpu_num, &gpus[gpu_num]);
}
#ifdef USE_DCGM
if (compact && (gpu_count > 0))
printf("\n");
print_dcgm(compact, overwrite);
#endif
if (!overwrite)
printf("\n"); /* Print line break at the end for continuous output */
if (overwrite && compact) {
int total_lines = 0;
if (print_board_sensors) total_lines++;
if (gpu_count > 0) {
total_lines += (gpu_num == -1) ? gpu_count : 1;
}
#ifdef USE_DCGM
total_lines++;
#endif
printf("\x1b[1G"); /* Move cursor back to column 1 */
if (gpu_count > 1 || print_board_sensors)
printf("\x1b[%dA", gpu_count-1+print_board_sensors); /* Move cursor back up to the top of gpu list */
if (total_lines > 1)
printf("\x1b[%dA", total_lines - 1); /* Move cursor back up to the top */
}
fflush(stdout);
@@ -238,6 +257,9 @@ int main (int argc, char **argv)
#ifdef USE_NVML
nvmlShutdown();
#endif
#ifdef USE_DCGM
shutdown_dcgm();
#endif
}
void print_board_info(struct hwmon_avail_sensor *board_sensors, int num_sensors)
@@ -330,16 +352,12 @@ void print_gpu_info(int gpu_num, struct card_info *gpu)
for (int i = 0; i < ICX3_NUM_TEMP_SENSORS; i++) {
if (i > 0 && strncmp(icx3_temp_sensor_names[i], icx3_temp_sensor_names[i-1], 3))
printf("%s %.3s%s", header_start, icx3_temp_sensor_names[i], header_end);
#ifdef USE_LIBPCI
if (strncmp(icx3_temp_sensor_names[i], "MEM1", 4) == 0)
printf(" %3.0f", get_vram_temp(gpu)); /* Print the VRAM temp before the rest of the memory sensors */
#endif
printf(" %3.0f", icx_temp_sensors[i]);
}
#ifdef USE_LIBPCI
printf("%s HOT%s %3.0f", header_start, header_end, get_hotspot_temp(gpu));
#endif
printf("°C ");
@@ -364,18 +382,14 @@ void print_gpu_info(int gpu_num, struct card_info *gpu)
float icx_temp_sensors[ICX3_NUM_TEMP_SENSORS] = {};
get_temp_sensors(icx_temp_sensors, gpu);
for (int i = 0; i < ICX3_NUM_TEMP_SENSORS; i++) {
#ifdef USE_LIBPCI
if (strncmp(icx3_temp_sensor_names[i], "MEM1", 4) == 0)
printf("VRAM: +%.0f°C\n", get_vram_temp(gpu)); /* Print the VRAM temp before the rest of the memory sensors */
#endif
printf("%s: %+.1f°C\n",
icx3_temp_sensor_names[i],
icx_temp_sensors[i]);
}
#ifdef USE_LIBPCI
printf("HotSpot: +%.0f°C\n", get_hotspot_temp(gpu));
#endif
#ifdef USE_NVML
printf("Mem util: %d%%\n", get_nvml_mem_util(gpu));
+28 -84
View File
@@ -1,104 +1,48 @@
#include <string.h>
#include <stdio.h>
#include <pci/pci.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#define PG_SZ sysconf(_SC_PAGE_SIZE)
#include "gddr6.h"
void init_gddr6(struct card_info *card)
static struct device_offset device_offset_info[] =
{
/* Parse the address of the card to get the PCI info */
char pci_address[] = "00000000:00:00.0";
int len = strlen(card->pci_id);
strcpy(&pci_address[sizeof(pci_address) - len - 1], card->pci_id);
int domain = 0;
int bus = 0;
int dev = 0;
int func = 0;
sscanf(pci_address, "%x:%x:%x.%x", &domain, &bus, &dev, &func);
struct pci_access *pacc = NULL;
struct pci_dev *pci_dev = NULL;
pacc = pci_alloc();
pci_init(pacc);
pci_dev = pci_get_dev(pacc, domain, bus, dev, func);
pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
card->bar0 = (pci_dev->base_addr[0] & 0xFFFFFFFF);
pci_cleanup(pacc);
/* Open our memory mappings */
card->vram_addr = NULL;
card->hotspot_addr = NULL;
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
{
printf("Can't read memory for VRAM and Hotspot temperatures. If you are root, enable kernel parameter iomem=relaxed\n");
return;
}
unsigned int phys_addr, base_offset;
void *map_base;
for (int i = 0; i < sizeof(device_offset_info) / sizeof(struct device_offset); i++) {
if (card->pci_device_id == device_offset_info[i].device_id){
/* Map for VRAM */
phys_addr = (card->bar0 + device_offset_info[i].vram_offset);
base_offset = phys_addr & ~(PG_SZ-1);
map_base = mmap(0, PG_SZ, PROT_READ, MAP_SHARED, fd, base_offset);
if(map_base == (void *) -1)
printf("Can't map memory for VRAM temperature. If you are root, enable kernel parameter iomem=relaxed\n");
else
card->vram_addr = (void *) map_base + (phys_addr - base_offset);
/* Map for hotspot */
phys_addr = (card->bar0 + device_offset_info[i].hotspot_offset);
base_offset = phys_addr & ~(PG_SZ-1);
map_base = mmap(0, PG_SZ, PROT_READ, MAP_SHARED, fd, base_offset);
if(map_base == (void *) -1)
printf("Can't map memory for Hotspot temperature. If you are root, enable kernel parameter iomem=relaxed\n");
else
card->hotspot_addr = (void *) map_base + (phys_addr - base_offset);
}
}
close(fd);
}
{.device_id = NVIDIA_RTX3090TI_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3090 Ti */
{.device_id = NVIDIA_RTX3090_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3090 */
{.device_id = NVIDIA_RTX3080TI_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 Ti */
{.device_id = NVIDIA_RTX3080_12G_LHR_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 12G LHR */
{.device_id = NVIDIA_RTX3080_LHR_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 LHR */
{.device_id = NVIDIA_RTX3080_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 */
{.device_id = NVIDIA_RTX3070TI_GA102_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 Ti GA102 TODO:check */
{.device_id = NVIDIA_RTX3070TI_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 Ti TODO:check */
{.device_id = NVIDIA_RTX3070_LHR_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 LHR */
{.device_id = NVIDIA_RTX3070_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 */
};
float get_vram_temp(struct card_info *card)
{
float temp = 0.0;
if(card->vram_addr == NULL)
if (card->bar0_mmap == NULL)
return 0.0;
int read_result = *((unsigned int *) card->vram_addr);
temp = ((read_result & 0x00000fff) / 0x20);
for (int i = 0; i < sizeof(device_offset_info) / sizeof(struct device_offset); i++) {
if (card->pci_device_id == device_offset_info[i].device_id) {
unsigned int read_result = *((unsigned int *)((char *)card->bar0_mmap + device_offset_info[i].vram_offset));
return (float)((read_result & 0x00000fff) / 0x20);
}
}
return temp;
return 0.0;
}
float get_hotspot_temp(struct card_info *card)
{
float temp = 0.0;
if(card->hotspot_addr == NULL)
if (card->bar0_mmap == NULL)
return 0.0;
int read_result = *((unsigned int *) card->hotspot_addr);
temp = (read_result >> 8) & 0xff;
for (int i = 0; i < sizeof(device_offset_info) / sizeof(struct device_offset); i++) {
if (card->pci_device_id == device_offset_info[i].device_id) {
unsigned int read_result = *((unsigned int *)((char *)card->bar0_mmap + device_offset_info[i].hotspot_offset));
return (float)((read_result >> 8) & 0xff);
}
}
return temp;
return 0.0;
}
-16
View File
@@ -6,21 +6,5 @@ struct device_offset {
int hotspot_offset;
};
static struct device_offset device_offset_info[] =
{
{.device_id = NVIDIA_RTX3090TI_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3090 Ti */
{.device_id = NVIDIA_RTX3090_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3090 */
{.device_id = NVIDIA_RTX3080TI_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 Ti */
{.device_id = NVIDIA_RTX3080_12G_LHR_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 12G LHR */
{.device_id = NVIDIA_RTX3080_LHR_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 LHR */
{.device_id = NVIDIA_RTX3080_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 */
{.device_id = NVIDIA_RTX3080_DEV, .vram_offset = 0x0000E2A8, .hotspot_offset = 0x0002046c}, /* RTX 3080 */
{.device_id = NVIDIA_RTX3070TI_GA102_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 Ti GA102 TODO:check */
{.device_id = NVIDIA_RTX3070TI_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 Ti TODO:check */
{.device_id = NVIDIA_RTX3070_LHR_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 */
{.device_id = NVIDIA_RTX3070_DEV, .vram_offset = 0x0000EE50, .hotspot_offset = 0x0002046c}, /* RTX 3070 LHR */
};
void init_gddr6(struct card_info *card);
float get_vram_temp(struct card_info *card);
float get_hotspot_temp(struct card_info *card);
+127
View File
@@ -0,0 +1,127 @@
#include <stdio.h>
#include "nvidia-dcgm.h"
/* Yeah I know this is duplicated */
#define HEADER_COLOR_START "\x1b[36m"
#define HEADER_COLOR_END "\x1b[39m"
dcgmHandle_t dcgm_handle = (dcgmHandle_t)NULL;
dcgmFieldGrp_t field_group_id;
unsigned long long clock_reasons = 0;
void init_dcgm()
{
/* Init DCGM */
dcgmReturn_t result;
result = dcgmInit();
if (result != DCGM_ST_OK)
printf("Could not init DCGM: %s\n", errorString(result));
/* Start embedded */
result = dcgmStartEmbedded(DCGM_OPERATION_MODE_MANUAL, &dcgm_handle);
if (result != DCGM_ST_OK)
printf("Could not start embedded DCGM engine: %s\n", errorString(result));
/* Create metric group */
int num_metrics = sizeof(metric_readings) / sizeof(metric_readings[0]);
unsigned short field_ids[num_metrics + 1];
for (int i = 0; i < num_metrics; i++) {
field_ids[i] = metric_readings[i].field_id;
metric_readings[i].last_reading = 0.0;
}
field_ids[num_metrics] = DCGM_FI_DEV_CLOCKS_EVENT_REASONS;
result = dcgmFieldGroupCreate(dcgm_handle, num_metrics + 1, &field_ids[0], (char *)"evga_icx_fields", &field_group_id);
if (result != DCGM_ST_OK)
printf("Could not create DCGM metric group: %s\n", errorString(result));
/* Start recording */
result = dcgmWatchFields(dcgm_handle, DCGM_GROUP_ALL_GPUS , field_group_id, 1000000, 30, 1);
if (result != DCGM_ST_OK)
printf("Could not record DCGM metrics: %s\n", errorString(result));
}
void shutdown_dcgm()
{
dcgmStopEmbedded(dcgm_handle);
dcgmShutdown();
}
void print_dcgm(int compact, int overwrite)
{
dcgmReturn_t result;
dcgmUpdateAllFields(dcgm_handle, 1);
result = dcgmGetLatestValues(dcgm_handle, DCGM_GROUP_ALL_GPUS, field_group_id, &update_field_values, NULL);
if (result != DCGM_ST_OK)
printf("Could not read DCGM metrics: %s\n", errorString(result));
/* Print the float metrics */
for (int i = 0; i < sizeof(metric_readings) / sizeof(metric_readings[0]); i++) {
if (compact)
printf("%s%s%s%s %4.1f",
i==0 ? "": " ",
HEADER_COLOR_START,
metric_readings[i].short_name,
HEADER_COLOR_END,
metric_readings[i].last_reading * 100);
else
printf("%s: %.1f%\n", metric_readings[i].long_name, metric_readings[i].last_reading * 100);
}
if (compact)
printf("%%");
/* Print clock reasons */
int single_reason = 1;
if (compact)
printf("%s CLK %s", HEADER_COLOR_START, HEADER_COLOR_END);
else
printf("Clock reasons: ");
for (int i = 0; i < (sizeof(clock_reason_names) / sizeof(struct clock_reason)); i++) {
if (clock_reasons & clock_reason_names[i].mask) {
if (!single_reason) {
if (compact)
printf(",");
else
printf(", ");
}
single_reason = 0;
if (compact)
printf("%s", clock_reason_names[i].short_name);
else
printf("%s", clock_reason_names[i].long_name);
}
}
if (single_reason)
printf("None");
if (!compact)
printf(" (0x%llx)", clock_reasons);
else
printf("%-15s", " ");
}
int update_field_values(unsigned int gpu_id, dcgmFieldValue_v1 *values, int num_values, void *userdata)
{
for (int j = 0; j < num_values; j++) {
if (values[j].fieldType == DCGM_FT_DOUBLE) {
/* A double reading so read it into our readings array */
for (int i = 0; i < sizeof(metric_readings) / sizeof(metric_readings[0]); i++) {
if (metric_readings[i].field_id == values[j].fieldId) {
double val = values[j].value.dbl;
if (val >= 1)
metric_readings[i].last_reading = 0.0;
else
metric_readings[i].last_reading = values[j].value.dbl;
}
}
} else if (values[j].fieldType == DCGM_FT_INT64) {
/* Int is probably the bitmask of our clock reasons */
clock_reasons = values[j].value.i64;
}
}
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
#include <dcgm_agent.h>
#include <dcgm_structs.h>
#include "evga-card.h"
struct metric_reading {
unsigned short field_id;
char *short_name;
char *long_name;
double last_reading;
};
static struct metric_reading metric_readings[] =
{
{DCGM_FI_PROF_GR_ENGINE_ACTIVE, "GFX", "Graphics Engine Activity"},
{DCGM_FI_PROF_SM_ACTIVE, "SM ACT", "SM Activity"},
{DCGM_FI_PROF_SM_OCCUPANCY, "OCC", "SM Occupancy"},
{DCGM_FI_PROF_PIPE_FP16_ACTIVE, "FP16", "FP16 Engine Activity"},
{DCGM_FI_PROF_PIPE_FP32_ACTIVE, "FP32", "FP32 Engine Activity"},
{DCGM_FI_PROF_PIPE_FP64_ACTIVE, "FP64", "FP64 Engine Activity"},
{DCGM_FI_PROF_PIPE_INT_ACTIVE, "INT", "Integer Activity"},
{DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, "TENS", "Tensor Activity"},
{DCGM_FI_PROF_PIPE_TENSOR_HMMA_ACTIVE, "HMMA", "Half Precision Tensor"},
{DCGM_FI_PROF_PIPE_TENSOR_IMMA_ACTIVE, "IMMA", "Integer Tensor"},
{DCGM_FI_PROF_PIPE_TENSOR_DFMA_ACTIVE, "DFMA", "Double Precision Tensor"},
{DCGM_FI_PROF_DRAM_ACTIVE, "DRAM", "Memory BW Utilization"}
};
struct clock_reason {
unsigned long long mask;
char *short_name;
char *long_name;
};
static struct clock_reason clock_reason_names[] =
{
{DCGM_CLOCKS_EVENT_REASON_GPU_IDLE, "Idle", "GPU idle"},
{DCGM_CLOCKS_EVENT_REASON_CLOCKS_SETTING, "AppClk", "Application clocks"},
{DCGM_CLOCKS_EVENT_REASON_SW_POWER_CAP, "Pwr", "Power cap"},
{DCGM_CLOCKS_EVENT_REASON_HW_SLOWDOWN, "HWSlow", "Hardware slowdown"},
{DCGM_CLOCKS_EVENT_REASON_SYNC_BOOST, "Sync", "Sync boost"},
{DCGM_CLOCKS_EVENT_REASON_SW_THERMAL, "SWTherm", "Software thermal"},
{DCGM_CLOCKS_EVENT_REASON_HW_THERMAL, "HWTherm", "Hardware thermal"},
{DCGM_CLOCKS_EVENT_REASON_HW_POWER_BRAKE, "HWPower", "Hardware power brake"},
{DCGM_CLOCKS_EVENT_REASON_DISPLAY_CLOCKS, "DispClk", "Display clock"}
};
void init_dcgm();
void shutdown_dcgm();
void print_dcgm(int compact, int overwrite);
int update_field_values(unsigned int gpu_id, dcgmFieldValue_v1 *values, int num_values, void *userdata);
+3 -1
View File
@@ -36,7 +36,7 @@ void print_nvml_clock_reason(int compact, struct card_info *card)
single_reason = 0;
if (compact)
printf("%-15s", clock_reason_names[i].short_name);
printf("%s", clock_reason_names[i].short_name);
else
printf("%s", clock_reason_names[i].long_name);
}
@@ -47,6 +47,8 @@ void print_nvml_clock_reason(int compact, struct card_info *card)
if (!compact)
printf(" (0x%llx)", reasons);
else
printf("%-15s", " ");
}
unsigned int get_nvml_temp(struct card_info *card)