Compare commits
12
Commits
13aa5b023e
...
v2.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e78a059a6 | ||
|
|
20e2683110 | ||
|
|
b7d22ed9ac | ||
|
|
46eb773820 | ||
|
|
dc63b57bbe | ||
|
|
7cd23384f6 | ||
|
|
c4e7f7e8b9 | ||
|
|
442a524243 | ||
|
|
d4e32a78fc | ||
|
|
65aa52ac42 | ||
|
|
8d4a8f7ee1 | ||
|
|
54885e16f0 |
@@ -0,0 +1,8 @@
|
|||||||
|
MIT No Attribution
|
||||||
|
|
||||||
|
Copyright 2025 admin@long-cat.net
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
@@ -10,6 +10,12 @@ CFLAGS += -DUSE_NVML
|
|||||||
OBJS += nvidia-sensors.o
|
OBJS += nvidia-sensors.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef USE_LIBPCI
|
||||||
|
LDLIBS += -lpci
|
||||||
|
CFLAGS += -DUSE_LIBPCI
|
||||||
|
OBJS += gddr6.o
|
||||||
|
endif
|
||||||
|
|
||||||
evga-icx : $(OBJS)
|
evga-icx : $(OBJS)
|
||||||
|
|
||||||
debug : CFLAGS += -g -O0
|
debug : CFLAGS += -g -O0
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This program allows you to read temperature sensors off of supported EVGA 30-series iCX3 video cards, as well as control the fans individually.
|
This program allows you to read temperature sensors off of supported EVGA 30-series iCX3 video cards, as well as control the fans individually.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
A supported EVGA 30-series iCX3 card. I have not done extensive testing but belive this is every model of their:
|
A supported EVGA 30-series card with iCX3. This includes:
|
||||||
* RTX 3060 Ti
|
* RTX 3060 Ti
|
||||||
* RTX 3070
|
* RTX 3070
|
||||||
* RTX 3070 Ti
|
* RTX 3070 Ti
|
||||||
@@ -14,6 +14,8 @@ A supported EVGA 30-series iCX3 card. I have not done extensive testing but bel
|
|||||||
|
|
||||||
The number of fans supported depends, of course, on your particular model.
|
The number of fans supported depends, of course, on your particular model.
|
||||||
|
|
||||||
|
You must have the `i2c-dev` kernel module loaded with `modprobe i2c-dev`
|
||||||
|
|
||||||
Access to the `/dev/i2c` device files, which means either:
|
Access to the `/dev/i2c` device files, which means either:
|
||||||
* Run as root, or
|
* Run as root, or
|
||||||
* Install udev rules to allow user access. If you have the OpenRGB udev rules installed to control the LEDs you already have this set up.
|
* Install udev rules to allow user access. If you have the OpenRGB udev rules installed to control the LEDs you already have this set up.
|
||||||
@@ -21,6 +23,7 @@ Access to the `/dev/i2c` device files, which means either:
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
* libi2c-dev
|
* libi2c-dev
|
||||||
* libnvidia-ml-dev (if building with `USE_NVML=1`)
|
* libnvidia-ml-dev (if building with `USE_NVML=1`)
|
||||||
|
* libpci-dev (if building with `USE_LIBPCI=1`)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
`make`
|
`make`
|
||||||
@@ -28,13 +31,17 @@ Access to the `/dev/i2c` device files, which means either:
|
|||||||
## Optional features
|
## Optional features
|
||||||
|
|
||||||
### NVML support
|
### NVML support
|
||||||
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. This requires NVML development files to be installed.
|
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.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
Note that when controlling fans directly through iCX3 they will fall offline from the Nvidia driver and show as 0 RPM until you return them to automatic mode.
|
Note that when controlling fans directly through iCX3 they will fall offline from the Nvidia driver and show as 0 RPM until you return them to automatic mode.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Available options:
|
Available options:
|
||||||
|
--i2c N : Only probe I2C bus N instead of all (may help with stuttering or freezing when probing I2C devices)
|
||||||
--gpu N : Control only GPU N instead of all supported cards
|
--gpu N : Control only GPU N instead of all supported cards
|
||||||
--fan SPEED : Set all fans at once to SPEED (see below)
|
--fan SPEED : Set all fans at once to SPEED (see below)
|
||||||
--fanN SPEED : Set fan N (0-3) to SPEED
|
--fanN SPEED : Set fan N (0-3) to SPEED
|
||||||
@@ -46,6 +53,8 @@ Available options:
|
|||||||
--sensors : Print sensor readings even if setting a fan speed
|
--sensors : Print sensor readings even if setting a fan speed
|
||||||
--compact : Print sensor reading in a compact one-line per card format
|
--compact : Print sensor reading in a compact one-line per card format
|
||||||
--watch N : Keep printing output every N seconds
|
--watch N : Keep printing output every N seconds
|
||||||
|
--overwrite : Overwrite previously displayed info with --watch and --compact instead of continuously logging new lines
|
||||||
|
--color : Print headers in color in --compact mode for better readability
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
@@ -53,27 +62,30 @@ Read sensors:
|
|||||||
```text
|
```text
|
||||||
$ ./evga-icx
|
$ ./evga-icx
|
||||||
#0: EVGA GeForce RTX 3090 FTW3 Ultra v2 (/dev/i2c-3) @ c:00.0
|
#0: EVGA GeForce RTX 3090 FTW3 Ultra v2 (/dev/i2c-3) @ c:00.0
|
||||||
Fan 0: 1122 RPM (37/0%, Auto)
|
Fan 0: 1751 RPM (58/0%, Auto)
|
||||||
Fan 1: 1177 RPM (39/0%, Auto)
|
Fan 1: 1730 RPM (57/0%, Auto)
|
||||||
Fan 2: 1189 RPM (39/0%, Offset)
|
Fan 2: 1712 RPM (57/0%, Offset)
|
||||||
Ext. fan: 0 RPM (0/0%, Offset)
|
Ext. fan: 0 RPM (0/0%, Offset)
|
||||||
GPU1: +36°C
|
GPU1: +65°C
|
||||||
GPU2: +41.2°C
|
GPU2: +57.8°C
|
||||||
MEM1: +42.8°C
|
VRAM: +74°C
|
||||||
MEM2: +41.1°C
|
MEM1: +56.1°C
|
||||||
MEM3: +41.5°C
|
MEM2: +53.5°C
|
||||||
PWR1: +40.5°C
|
MEM3: +55.5°C
|
||||||
PWR2: +41.2°C
|
PWR1: +48.2°C
|
||||||
PWR3: +41.9°C
|
PWR2: +53.2°C
|
||||||
PWR4: +42.5°C
|
PWR3: +59.6°C
|
||||||
PWR5: +42.0°C
|
PWR4: +58.0°C
|
||||||
Clock reasons: GPU idle (0x1)
|
PWR5: +51.1°C
|
||||||
|
HotSpot: +75°C
|
||||||
|
Mem util: 43%
|
||||||
|
Clock reasons: Power cap (0x4)
|
||||||
```
|
```
|
||||||
|
|
||||||
Compact one-line mode:
|
Compact one-line mode:
|
||||||
```text
|
```text
|
||||||
$ ./evga-icx --compact
|
$ ./evga-icx --compact
|
||||||
#0 FAN 37 39 39 0% GPU 35 41 MEM 41 41 41 PWR 40 41 42 42 42°C CLK Idle
|
#0 FAN 59 59 58 0% GPU 66 60 MEM 74 58 55 58 PWR 49 55 61 60 53 HOT 77°C MEM 42% CLK Pwr
|
||||||
```
|
```
|
||||||
|
|
||||||
Set external fan to follow Nvidia driver controlled speed with a -500 RPM offset:
|
Set external fan to follow Nvidia driver controlled speed with a -500 RPM offset:
|
||||||
|
|||||||
+11
-1
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
|
/* Search all i2c device files for ones are on a PCI device of a supported GPU,
|
||||||
and respond with the correct iCX3 version information */
|
and respond with the correct iCX3 version information */
|
||||||
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus)
|
||||||
{
|
{
|
||||||
char i2c_devices_path[NAME_MAX];
|
char i2c_devices_path[NAME_MAX];
|
||||||
char device_path[NAME_MAX];
|
char device_path[NAME_MAX];
|
||||||
@@ -20,6 +20,7 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
|
|
||||||
int num_gpus = 0;
|
int num_gpus = 0;
|
||||||
|
int current_i2c_bus = -1;
|
||||||
unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0;
|
unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0;
|
||||||
|
|
||||||
/* Start looking for I2C adapters in /sys/bus/i2c/devices/ */
|
/* Start looking for I2C adapters in /sys/bus/i2c/devices/ */
|
||||||
@@ -37,6 +38,14 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
if(strncmp(ent->d_name, "i2c-", 4) != 0)
|
if(strncmp(ent->d_name, "i2c-", 4) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Only probe the specific device given (if provided) */
|
||||||
|
if (i2c_bus >= 0) {
|
||||||
|
sscanf(ent->d_name, "i2c-%i", ¤t_i2c_bus);
|
||||||
|
if (current_i2c_bus != i2c_bus)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
strcpy(device_path, i2c_devices_path);
|
strcpy(device_path, i2c_devices_path);
|
||||||
strcat(device_path, ent->d_name);
|
strcat(device_path, ent->d_name);
|
||||||
|
|
||||||
@@ -67,6 +76,7 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
|
|||||||
/* Write our card info into the provided struct array */
|
/* Write our card info into the provided struct array */
|
||||||
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
|
infos[num_gpus].card_name = evga_pci_ids[i].card_name;
|
||||||
infos[num_gpus].pci_id = pci_addr;
|
infos[num_gpus].pci_id = pci_addr;
|
||||||
|
infos[num_gpus].pci_device_id = pci_device;
|
||||||
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
|
infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
|
||||||
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
|
strcpy(infos[num_gpus].i2c_dev_path, dev_file);
|
||||||
num_gpus++;
|
num_gpus++;
|
||||||
|
|||||||
+11
-6
@@ -84,11 +84,16 @@
|
|||||||
#define EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV 0x4985
|
#define EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV 0x4985
|
||||||
|
|
||||||
struct card_info {
|
struct card_info {
|
||||||
char *card_name;
|
char *card_name; /* The 'nice' name of the card */
|
||||||
char *pci_id;
|
char *pci_id; /* PCI bus address in domain:bus:device.function format. May be shortened (e.g. c:00.0) */
|
||||||
char *i2c_dev_path;
|
unsigned short pci_device_id; /* The device ID of the card, i.e. corresponds to the NVIDIA model number */
|
||||||
int i2c_fd;
|
char *i2c_dev_path; /* Path to the i2c device file */
|
||||||
int product_id;
|
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 {
|
struct gpu_pci_info {
|
||||||
@@ -160,7 +165,7 @@ static struct gpu_pci_info evga_pci_ids[] =
|
|||||||
{"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_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 find_evga_gpu_i2cs(struct card_info *infos, int max_gpus, int i2c_bus);
|
||||||
unsigned short read_pci_id(char *device_path, char *field);
|
unsigned short read_pci_id(char *device_path, char *field);
|
||||||
char *read_nvidia_pci_address(char *device_path);
|
char *read_nvidia_pci_address(char *device_path);
|
||||||
|
|
||||||
|
|||||||
+109
-14
@@ -9,12 +9,22 @@
|
|||||||
#include "nvidia-sensors.h"
|
#include "nvidia-sensors.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_LIBPCI
|
||||||
|
#include "gddr6.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "icx3.h"
|
#include "icx3.h"
|
||||||
#include "evga-card.h"
|
#include "evga-card.h"
|
||||||
|
|
||||||
#define MAX_GPUS 16
|
#define MAX_GPUS 16
|
||||||
|
#define HEADER_COLOR_START "\x1b[36m"
|
||||||
|
#define HEADER_COLOR_END "\x1b[39m"
|
||||||
|
|
||||||
|
char *header_start = "";
|
||||||
|
char *header_end = "";
|
||||||
|
|
||||||
static const char helpstring[] = "Available options:\n"
|
static const char helpstring[] = "Available options:\n"
|
||||||
|
"--i2c N : Only probe I2C bus N instead of all (may help with stuttering or freezing when probing I2C devices)\n"
|
||||||
"--gpu N : Control only GPU N instead of all supported cards\n"
|
"--gpu N : Control only GPU N instead of all supported cards\n"
|
||||||
"--fan SPEED : Set all fans at once to SPEED (see below)\n"
|
"--fan SPEED : Set all fans at once to SPEED (see below)\n"
|
||||||
"--fanN SPEED : Set fan N (0-3) to SPEED\n"
|
"--fanN SPEED : Set fan N (0-3) to SPEED\n"
|
||||||
@@ -25,7 +35,9 @@ static const char helpstring[] = "Available options:\n"
|
|||||||
"--reset : Reset all fans to their default mode\n"
|
"--reset : Reset all fans to their default mode\n"
|
||||||
"--sensors : Print sensor readings even if setting a fan speed \n"
|
"--sensors : Print sensor readings even if setting a fan speed \n"
|
||||||
"--compact : Print sensor reading in a compact one-line per card format\n"
|
"--compact : Print sensor reading in a compact one-line per card format\n"
|
||||||
"--watch N : Keep printing output every N seconds\n";
|
"--watch N : Keep printing output every N seconds\n"
|
||||||
|
"--overwrite : Overwrite previously displayed info with --watch and --compact instead of continuously logging\n"
|
||||||
|
"--color : Print headers in color in --compact mode for better readability\n";
|
||||||
|
|
||||||
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact);
|
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact);
|
||||||
|
|
||||||
@@ -36,12 +48,22 @@ int main (int argc, char **argv)
|
|||||||
int print_info = 0;
|
int print_info = 0;
|
||||||
int compact = 0;
|
int compact = 0;
|
||||||
int gpu_num = -1; /* Card to control */
|
int gpu_num = -1; /* Card to control */
|
||||||
|
int i2c_bus = -1;
|
||||||
|
int overwrite = 0;
|
||||||
unsigned int watch = 0;
|
unsigned int watch = 0;
|
||||||
char *fan_speed[ICX3_MAX_FANS] = {NULL};
|
char *fan_speed[ICX3_MAX_FANS] = {NULL};
|
||||||
|
|
||||||
/* Input parsing */
|
/* Input parsing */
|
||||||
for (int i = 1; i < argc; i++){
|
for (int i = 1; i < argc; i++){
|
||||||
if (strcmp(argv[i], "--gpu") == 0) {
|
if (strcmp(argv[i], "--i2c") == 0) {
|
||||||
|
i++;
|
||||||
|
if (i < argc) {
|
||||||
|
i2c_bus = atoi(argv[i]);
|
||||||
|
} else {
|
||||||
|
printf(helpstring);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[i], "--gpu") == 0) {
|
||||||
i++;
|
i++;
|
||||||
if (i < argc) {
|
if (i < argc) {
|
||||||
gpu_num = atoi(argv[i]);
|
gpu_num = atoi(argv[i]);
|
||||||
@@ -83,6 +105,11 @@ int main (int argc, char **argv)
|
|||||||
printf(helpstring);
|
printf(helpstring);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(argv[i], "--overwrite") == 0) {
|
||||||
|
overwrite = 1;
|
||||||
|
} else if (strcmp(argv[i], "--color") == 0) {
|
||||||
|
header_start = HEADER_COLOR_START;
|
||||||
|
header_end = HEADER_COLOR_END;
|
||||||
} else {
|
} else {
|
||||||
printf(helpstring);
|
printf(helpstring);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -98,7 +125,11 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS);
|
/* Don't use overwrite mode unless set to compact (we can't tell how many lines the output will be per GPU) */
|
||||||
|
if (overwrite && !compact)
|
||||||
|
overwrite = 0;
|
||||||
|
|
||||||
|
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS, i2c_bus);
|
||||||
|
|
||||||
if (gpu_count == -1) {
|
if (gpu_count == -1) {
|
||||||
printf("Error scanning I2C devices\n");
|
printf("Error scanning I2C devices\n");
|
||||||
@@ -131,20 +162,44 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
/* NVML init */
|
/* NVML init */
|
||||||
#ifdef USE_NVML
|
#ifdef USE_NVML
|
||||||
int nvml_ok = init_nvml();
|
init_nvml();
|
||||||
nvmlDevice_t* device[MAX_GPUS];
|
for (int i = 0; i < gpu_count; i++)
|
||||||
|
get_nvml_handle(&gpus[i]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PCI init for VRAM/hotspot temps */
|
||||||
|
#ifdef USE_LIBPCI
|
||||||
|
for (int i = 0; i < gpu_count; i++)
|
||||||
|
init_gddr6(&gpus[i]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* print sensor info */
|
/* print sensor info */
|
||||||
if (print_info) {
|
if (print_info) {
|
||||||
do {
|
do {
|
||||||
|
if (overwrite)
|
||||||
|
printf("\x1b[K"); /* Clear current console line */
|
||||||
|
|
||||||
if (gpu_num == -1) {
|
if (gpu_num == -1) {
|
||||||
|
/* No GPU specified on command line, loop over all supported GPUs */
|
||||||
for (int i = 0; i < gpu_count; i++){
|
for (int i = 0; i < gpu_count; i++){
|
||||||
|
if (i > 0)
|
||||||
|
printf("\n");
|
||||||
print_gpu_info(i, &gpus[i], compact);
|
print_gpu_info(i, &gpus[i], compact);
|
||||||
}
|
}
|
||||||
} else if (gpu_num <= gpu_count - 1) {
|
} else if (gpu_num <= gpu_count - 1) {
|
||||||
print_gpu_info(gpu_num, &gpus[gpu_num], compact);
|
print_gpu_info(gpu_num, &gpus[gpu_num], compact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!overwrite)
|
||||||
|
printf("\n"); /* Print line break at the end for continuous output */
|
||||||
|
|
||||||
|
if (overwrite && compact) {
|
||||||
|
printf("\x1b[1G"); /* Move cursor back to column 1 */
|
||||||
|
if (gpu_count > 1)
|
||||||
|
printf("\x1b[%dA", gpu_count-1); /* Move cursor back up to the top of gpu list */
|
||||||
|
}
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
sleep(watch);
|
sleep(watch);
|
||||||
} while (watch > 0);
|
} while (watch > 0);
|
||||||
}
|
}
|
||||||
@@ -157,30 +212,70 @@ int main (int argc, char **argv)
|
|||||||
void print_gpu_info(int gpu_num, struct card_info *gpu, int compact) {
|
void print_gpu_info(int gpu_num, struct card_info *gpu, int compact) {
|
||||||
if (compact) {
|
if (compact) {
|
||||||
/* One line per GPU */
|
/* One line per GPU */
|
||||||
printf("#%d ", gpu_num);
|
printf("%s#%d FAN%s", header_start, gpu_num, header_end);
|
||||||
print_icx3_fans_oneline(gpu);
|
print_icx3_fans_oneline(gpu);
|
||||||
printf(" GPU");
|
printf("%s GPU%s", header_start, header_end);
|
||||||
|
|
||||||
#ifdef USE_NVML
|
#ifdef USE_NVML
|
||||||
print_nvml_temp(1, gpu);
|
printf(" %3d", get_nvml_temp(gpu));
|
||||||
#endif
|
#endif
|
||||||
print_icx3_temps_oneline(gpu);
|
|
||||||
printf("°C");
|
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++) {
|
||||||
|
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 ");
|
||||||
|
|
||||||
#ifdef USE_NVML
|
#ifdef USE_NVML
|
||||||
|
printf("%s MEM %s", header_start, header_end);
|
||||||
|
printf("%3d%%", get_nvml_mem_util(gpu));
|
||||||
|
printf("%s CLK %s", header_start, header_end);
|
||||||
print_nvml_clock_reason(1, gpu);
|
print_nvml_clock_reason(1, gpu);
|
||||||
#endif
|
#endif
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* One line per GPU sensor */
|
/* One line per GPU sensor */
|
||||||
printf("#%d: %s (%s) @ %s\n", gpu_num, gpu->card_name, gpu->i2c_dev_path, gpu->pci_id);
|
printf("#%d: %s (%s) @ %s\n", gpu_num, gpu->card_name, gpu->i2c_dev_path, gpu->pci_id);
|
||||||
print_icx3_fans(gpu);
|
print_icx3_fans(gpu);
|
||||||
|
|
||||||
#ifdef USE_NVML
|
#ifdef USE_NVML
|
||||||
print_nvml_temp(0, gpu);
|
printf("GPU1: %+d°C\n", get_nvml_temp(gpu));
|
||||||
#endif
|
#endif
|
||||||
print_icx3_temps(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
|
#ifdef USE_NVML
|
||||||
|
printf("Mem util: %d%%\n", get_nvml_mem_util(gpu));
|
||||||
|
printf("Clock reasons: ");
|
||||||
print_nvml_clock_reason(0, gpu);
|
print_nvml_clock_reason(0, gpu);
|
||||||
#endif
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#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)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_vram_temp(struct card_info *card)
|
||||||
|
{
|
||||||
|
float temp = 0.0;
|
||||||
|
|
||||||
|
if(card->vram_addr == NULL)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
int read_result = *((unsigned int *) card->vram_addr);
|
||||||
|
temp = ((read_result & 0x00000fff) / 0x20);
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_hotspot_temp(struct card_info *card)
|
||||||
|
{
|
||||||
|
float temp = 0.0;
|
||||||
|
|
||||||
|
if(card->hotspot_addr == NULL)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
int read_result = *((unsigned int *) card->hotspot_addr);
|
||||||
|
temp = (read_result >> 8) & 0xff;
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "evga-card.h"
|
||||||
|
|
||||||
|
struct device_offset {
|
||||||
|
unsigned short device_id;
|
||||||
|
int vram_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);
|
||||||
@@ -62,40 +62,12 @@ void print_icx3_fans_oneline(struct card_info *card)
|
|||||||
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
struct icx3_fan_control fans[ICX3_MAX_FANS];
|
||||||
get_fan_status(fans, card);
|
get_fan_status(fans, card);
|
||||||
|
|
||||||
printf("FAN");
|
|
||||||
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
for (int i=0; i < ICX3_MAX_FANS; i++) {
|
||||||
printf(" %3d", fans[i].duty_status);
|
printf(" %3d", fans[i].duty_status);
|
||||||
}
|
}
|
||||||
printf("%%");
|
printf("%%");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_icx3_temps(struct card_info *card)
|
|
||||||
{
|
|
||||||
float temps[ICX3_NUM_TEMP_SENSORS];
|
|
||||||
|
|
||||||
get_temp_sensors(temps, card);
|
|
||||||
|
|
||||||
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
|
||||||
printf("%s: %+.1f°C\n",
|
|
||||||
icx3_temp_sensor_names[i],
|
|
||||||
temps[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_icx3_temps_oneline(struct card_info *card)
|
|
||||||
{
|
|
||||||
float temps[ICX3_NUM_TEMP_SENSORS];
|
|
||||||
|
|
||||||
get_temp_sensors(temps, card);
|
|
||||||
|
|
||||||
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
|
|
||||||
/* If this math seems a little jank, it's so we can optionally inject the NVML and vram temps into the oneline */
|
|
||||||
if (i > 0 && strncmp(icx3_temp_sensor_names[i], icx3_temp_sensor_names[i-1], 3))
|
|
||||||
printf(" %.3s", icx3_temp_sensor_names[i]);
|
|
||||||
printf(" %3.0f", temps[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_available_fans(char *fans_avail, struct card_info *card)
|
void get_available_fans(char *fans_avail, struct card_info *card)
|
||||||
{
|
{
|
||||||
int product_id = card->product_id;
|
int product_id = card->product_id;
|
||||||
@@ -265,6 +237,6 @@ void set_fan(int fan, char *setting, struct card_info *card)
|
|||||||
if (fan_readback.fanmode != fan_control.fanmode ||
|
if (fan_readback.fanmode != fan_control.fanmode ||
|
||||||
fan_readback.rpm_offset != fan_control.rpm_offset ||
|
fan_readback.rpm_offset != fan_control.rpm_offset ||
|
||||||
fan_readback.duty != fan_control.duty)
|
fan_readback.duty != fan_control.duty)
|
||||||
printf("Error setting fan %d on %s\n", fan, card->i2c_fd);
|
printf("Error setting fan %d on %s\n", fan, card->i2c_dev_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ static char *icx3_temp_sensor_names[] = {
|
|||||||
int icx3_init(struct card_info *card);
|
int icx3_init(struct card_info *card);
|
||||||
void print_icx3_fans(struct card_info *card);
|
void print_icx3_fans(struct card_info *card);
|
||||||
void print_icx3_fans_oneline(struct card_info *card);
|
void print_icx3_fans_oneline(struct card_info *card);
|
||||||
void print_icx3_temps(struct card_info *card);
|
|
||||||
void print_icx3_temps_oneline(struct card_info *card);
|
void print_icx3_temps_oneline(struct card_info *card);
|
||||||
void get_available_fans(char *fans_avail, struct card_info *card);
|
void get_available_fans(char *fans_avail, struct card_info *card);
|
||||||
void get_fan_status(struct icx3_fan_control *fans, struct card_info *card);
|
void get_fan_status(struct icx3_fan_control *fans, struct card_info *card);
|
||||||
|
|||||||
+29
-29
@@ -2,22 +2,22 @@
|
|||||||
|
|
||||||
#include "nvidia-sensors.h"
|
#include "nvidia-sensors.h"
|
||||||
|
|
||||||
int init_nvml()
|
void init_nvml()
|
||||||
{
|
{
|
||||||
nvmlReturn_t result;
|
nvmlReturn_t result;
|
||||||
result = nvmlInit_v2();
|
result = nvmlInit_v2();
|
||||||
if (result != NVML_SUCCESS) {
|
if (result != NVML_SUCCESS)
|
||||||
printf("Could not init NVML: %s\n", nvmlErrorString(result));
|
printf("Could not init NVML: %s\n", nvmlErrorString(result));
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_nvml_temp(int compact, struct card_info *card)
|
void get_nvml_handle(struct card_info *card)
|
||||||
{
|
{
|
||||||
if (compact)
|
nvmlReturn_t result;
|
||||||
printf(" %3d", get_nvml_temp(card));
|
result = nvmlDeviceGetHandleByPciBusId_v2(card->pci_id, card->nvml_device);
|
||||||
else
|
if (result != NVML_SUCCESS) {
|
||||||
printf("GPU1: %+d°C\n", get_nvml_temp(card));
|
printf("Failed to get NVML device handle for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
||||||
|
card->nvml_device = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_nvml_clock_reason(int compact, struct card_info *card)
|
void print_nvml_clock_reason(int compact, struct card_info *card)
|
||||||
@@ -25,11 +25,6 @@ void print_nvml_clock_reason(int compact, struct card_info *card)
|
|||||||
unsigned long long reasons = get_nvml_clock_reasons(card);
|
unsigned long long reasons = get_nvml_clock_reasons(card);
|
||||||
int single_reason = 1;
|
int single_reason = 1;
|
||||||
|
|
||||||
if (compact)
|
|
||||||
printf(" CLK ");
|
|
||||||
else
|
|
||||||
printf("Clock reasons: ");
|
|
||||||
|
|
||||||
for (int i = 0; i < (sizeof(clock_reason_names) / sizeof(struct clock_reason)); i++) {
|
for (int i = 0; i < (sizeof(clock_reason_names) / sizeof(struct clock_reason)); i++) {
|
||||||
if (reasons & clock_reason_names[i].mask) {
|
if (reasons & clock_reason_names[i].mask) {
|
||||||
if (!single_reason) {
|
if (!single_reason) {
|
||||||
@@ -51,21 +46,16 @@ void print_nvml_clock_reason(int compact, struct card_info *card)
|
|||||||
printf("None");
|
printf("None");
|
||||||
|
|
||||||
if (!compact)
|
if (!compact)
|
||||||
printf(" (0x%llx)\n", reasons);
|
printf(" (0x%llx)", reasons);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_nvml_temp(struct card_info *card)
|
unsigned int get_nvml_temp(struct card_info *card)
|
||||||
{
|
{
|
||||||
nvmlReturn_t result;
|
if (card->nvml_device == NULL)
|
||||||
nvmlDevice_t nvml_device;
|
|
||||||
result = nvmlDeviceGetHandleByPciBusId_v2(card->pci_id, &nvml_device);
|
|
||||||
if (result != NVML_SUCCESS) {
|
|
||||||
printf("Failed to get device handle for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int temp;
|
unsigned int temp;
|
||||||
result = nvmlDeviceGetTemperature(nvml_device, NVML_TEMPERATURE_GPU, &temp);
|
nvmlReturn_t result = nvmlDeviceGetTemperature(*(nvmlDevice_t*)(card->nvml_device), NVML_TEMPERATURE_GPU, &temp);
|
||||||
if (result != NVML_SUCCESS) {
|
if (result != NVML_SUCCESS) {
|
||||||
printf("Failed to get temperature for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
printf("Failed to get temperature for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -75,16 +65,11 @@ unsigned int get_nvml_temp(struct card_info *card)
|
|||||||
|
|
||||||
unsigned long long get_nvml_clock_reasons(struct card_info *card)
|
unsigned long long get_nvml_clock_reasons(struct card_info *card)
|
||||||
{
|
{
|
||||||
nvmlReturn_t result;
|
if (card->nvml_device == NULL)
|
||||||
nvmlDevice_t nvml_device;
|
|
||||||
result = nvmlDeviceGetHandleByPciBusId_v2(card->pci_id, &nvml_device);
|
|
||||||
if (result != NVML_SUCCESS) {
|
|
||||||
printf("Failed to get device handle for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long reasons;
|
unsigned long long reasons;
|
||||||
result = nvmlDeviceGetCurrentClocksEventReasons(nvml_device, &reasons) ;
|
nvmlReturn_t result = nvmlDeviceGetCurrentClocksEventReasons(*(nvmlDevice_t*)(card->nvml_device), &reasons) ;
|
||||||
if (result != NVML_SUCCESS) {
|
if (result != NVML_SUCCESS) {
|
||||||
printf("Failed to get clock reasons for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
printf("Failed to get clock reasons for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -93,3 +78,18 @@ unsigned long long get_nvml_clock_reasons(struct card_info *card)
|
|||||||
return reasons;
|
return reasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int get_nvml_mem_util(struct card_info *card)
|
||||||
|
{
|
||||||
|
if (card->nvml_device == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nvmlUtilization_t util;
|
||||||
|
nvmlReturn_t result = nvmlDeviceGetUtilizationRates(*(nvmlDevice_t*)(card->nvml_device), &util);
|
||||||
|
if (result != NVML_SUCCESS) {
|
||||||
|
printf("Failed to get clock reasons for card at %s: %s\n", card->pci_id, nvmlErrorString(result));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -21,8 +21,9 @@ static struct clock_reason clock_reason_names[] =
|
|||||||
{nvmlClocksEventReasonDisplayClockSetting, "DispClk", "Display clock"}
|
{nvmlClocksEventReasonDisplayClockSetting, "DispClk", "Display clock"}
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_nvml();
|
void init_nvml();
|
||||||
void print_nvml_temp(int compact, struct card_info *card);
|
void get_nvml_handle(struct card_info *card);
|
||||||
void print_nvml_clock_reason(int compact, struct card_info *card);
|
void print_nvml_clock_reason(int compact, struct card_info *card);
|
||||||
unsigned int get_nvml_temp(struct card_info *card);
|
unsigned int get_nvml_temp(struct card_info *card);
|
||||||
unsigned long long get_nvml_clock_reasons(struct card_info *card);
|
unsigned long long get_nvml_clock_reasons(struct card_info *card);
|
||||||
|
unsigned int get_nvml_mem_util(struct card_info *card);
|
||||||
Reference in New Issue
Block a user