evga-icx/evga-icx.c

255 lines
6.6 KiB
C

#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef USE_NVML
#include "nvidia-sensors.h"
#endif
#ifdef USE_LIBPCI
#include "gddr6.h"
#endif
#include "icx3.h"
#include "evga-card.h"
#define MAX_GPUS 16
static const char helpstring[] = "Available options:\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"
"--fanN SPEED : Set fan N (0-3) to SPEED\n"
" SPEED may be one of the following:\n"
" 'auto' to return the fan to its default control mode\n"
" N to set the fan to that manual % speed\n"
" [+/-]N to set that fan to an RPM offset from the GPU-controlled speed\n"
"--reset : Reset all fans to their default mode\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"
"--watch N : Keep printing output every N seconds\n"
"--overwrite : Overwrite previously displayed info with --watch and --compact instead of continuously logging\n";
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact);
int main (int argc, char **argv)
{
struct card_info gpus[MAX_GPUS];
int gpu_count;
int print_info = 0;
int compact = 0;
int gpu_num = -1; /* Card to control */
int overwrite = 0;
unsigned int watch = 0;
char *fan_speed[ICX3_MAX_FANS] = {NULL};
/* Input parsing */
for (int i = 1; i < argc; i++){
if (strcmp(argv[i], "--gpu") == 0) {
i++;
if (i < argc) {
gpu_num = atoi(argv[i]);
} else {
printf(helpstring);
return -1;
}
} else if (strcmp(argv[i], "--fan") == 0) {
i++;
if (i < argc) {
for (int j = 0; j < ICX3_MAX_FANS; j++)
fan_speed[j] = argv[i];
} else {
printf(helpstring);
return -1;
}
} else if (strncmp(argv[i], "--fan", 5) == 0) {
int fan_num = atoi(argv[i]+5);
i++;
if (i < argc) {
if (fan_num <= ICX3_MAX_FANS)
fan_speed[fan_num] = argv[i];
} else {
printf(helpstring);
return -1;
}
} else if (strcmp(argv[i], "--reset") == 0) {
for (int j = 0; j < ICX3_MAX_FANS; j++)
fan_speed[j] = "auto";
} else if (strcmp(argv[i], "--sensors") == 0) {
print_info = 1;
} else if (strcmp(argv[i], "--compact") == 0) {
compact = 1;
} else if (strcmp(argv[i], "--watch") == 0) {
i++;
if (i < argc) {
watch = atoi(argv[i]);
} else {
printf(helpstring);
return -1;
}
} else if (strcmp(argv[i], "--overwrite") == 0) {
overwrite = 1;
} else {
printf(helpstring);
return 0;
}
}
if (print_info == 0) {
/* Check for no fan commands given, so display info by default */
print_info = 1;
for (int i = 0; i < ICX3_MAX_FANS; i++) {
if (fan_speed[i] != NULL)
print_info = 0;
}
}
/* 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);
if (gpu_count == -1) {
printf("Error scanning I2C devices\n");
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;
}
if (gpu_num > gpu_count - 1) {
printf("Invalid GPU number specified (%d, max %d)\n", gpu_num, gpu_count - 1);
return -1;
}
/* execute fan commands */
if (gpu_num == -1) {
for (int i = 0; i < gpu_count; i++){
for (int j = 0; j < ICX3_MAX_FANS; j++) {
if (fan_speed[j] != NULL)
set_fan(j, fan_speed[j], &gpus[i]);
}
}
} else if (gpu_num <= gpu_count - 1) {
for (int j = 0; j < ICX3_MAX_FANS; j++) {
if (fan_speed[j] != NULL)
set_fan(gpu_num, fan_speed[j], &gpus[gpu_num]);
}
}
/* NVML init */
#ifdef USE_NVML
init_nvml();
#endif
/* PCI init for VRAM/hotspot temps */
#ifdef USE_LIBPCI
for (int i = 0; i < gpu_count; i++)
init_gddr6(&gpus[i]);
#endif
/* print sensor info */
if (print_info) {
do {
printf("\x1b[K"); /* Clear current console line (really just for overwrite mode) */
if (gpu_num == -1) {
/* No GPU specified on command line, loop over all supported GPUs */
for (int i = 0; i < gpu_count; i++){
if (i > 0)
printf("\n");
print_gpu_info(i, &gpus[i], compact);
}
} else if (gpu_num <= gpu_count - 1) {
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);
} while (watch > 0);
}
#ifdef USE_NVML
nvmlShutdown();
#endif
}
void print_gpu_info(int gpu_num, struct card_info *gpu, int compact) {
if (compact) {
/* One line per GPU */
printf("#%d ", gpu_num);
print_icx3_fans_oneline(gpu);
printf(" GPU");
#ifdef USE_NVML
printf(" %3d", get_nvml_temp(gpu));
#endif
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(" %.3s", icx3_temp_sensor_names[i]);
#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(" HOT %3.0f", get_hotspot_temp(gpu));
#endif
printf("°C ");
#ifdef USE_NVML
print_nvml_clock_reason(1, gpu);
#endif
} else {
/* One line per GPU sensor */
printf("#%d: %s (%s) @ %s\n", gpu_num, gpu->card_name, gpu->i2c_dev_path, gpu->pci_id);
print_icx3_fans(gpu);
#ifdef USE_NVML
printf("GPU1: %+d°C\n", get_nvml_temp(gpu));
#endif
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
print_nvml_clock_reason(0, gpu);
#endif
}
}