Added the ability to read some CPU and other temperature sensors.

This commit is contained in:
moosecrap 2025-02-27 04:51:19 -08:00
parent 60caeaf0ef
commit edd575042e
5 changed files with 257 additions and 17 deletions

View File

@ -1,6 +1,6 @@
.PHONY : clean debug
OBJS = evga-icx.o evga-card.o icx3.o
OBJS = evga-icx.o evga-card.o icx3.o board-sensors.o
LDLIBS = -li2c
CFLAGS = -MD
@ -18,7 +18,7 @@ endif
evga-icx : $(OBJS)
debug : CFLAGS += -g -O0
debug : CFLAGS += -g -Og
debug : evga-icx
clean :

View File

@ -55,7 +55,7 @@ Available options:
--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
--no-reasons : Do not query NVML for clocks reasons (can cause stuttering)
--no-reasons : Do not query NVML for clock reasons (can cause stuttering)
```
### Examples:

122
board-sensors.c Normal file
View File

@ -0,0 +1,122 @@
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include "board-sensors.h"
int find_board_sensors(struct hwmon_avail_sensor *board_sensors, int max_sensors)
{
const char *hwmon_path = "/sys/class/hwmon/";
char device_path[NAME_MAX];
char sensor_path[NAME_MAX];
char driver_name[256];
FILE *file;
DIR *dir;
struct dirent *ent;
int num_sensors = 0;
/* Start looking for hwmon devices in /sys/class/hwmon/ */
dir = opendir(hwmon_path);
/* make sure we can open the device directory */
if(dir == NULL)
return 0;
/* loop over all hwmon devices */
while((ent = readdir(dir)) != NULL)
{
/* Ignore any non-hwmon dirs */
if(strncmp(ent->d_name, "hwmon", 5) != 0)
continue;
strcpy(device_path, hwmon_path);
strcat(device_path, ent->d_name);
/* Read in the name of the device */
strcpy(sensor_path, device_path);
strcat(sensor_path, "/name");
file = fopen(sensor_path, "r");
if (file == NULL)
continue;
if (fgets(driver_name, sizeof(driver_name), file) == NULL) {
fclose(file);
continue;
}
fclose(file);
/* Driver names have a linebreak at the end so let's remove that for comparison*/
driver_name[strlen(driver_name) - 1] = '\0';
/* Loop through all supported sensors and see if any are present in this device */
for (int i = 0; i < (sizeof(hwmon_sensor_info) / sizeof(struct hwmon_sensor)); i++) {
if (strcmp(driver_name, hwmon_sensor_info[i].driver_name) == 0) {
/* We matched the driver name, try to open the files */
strcpy(sensor_path, device_path);
strcat(sensor_path, "/");
strcat(sensor_path, hwmon_sensor_info[i].sensor_file_name);
strcat(sensor_path, "_input");
file = fopen(sensor_path, "r");
if (file != NULL) {
fclose(file);
/* Good open of the sensor file */
board_sensors[num_sensors].file = calloc(NAME_MAX, sizeof(char));
strcpy(board_sensors[num_sensors].file, sensor_path);
board_sensors[num_sensors].sort_index = i;
board_sensors[num_sensors].sensor_info = &hwmon_sensor_info[i];
/* Read in the sensor name */
board_sensors[num_sensors].sensor_name = calloc(MAX_SENSOR_NAME_LENGTH, sizeof(char));
strcpy(sensor_path, device_path);
strcat(sensor_path, "/");
strcat(sensor_path, hwmon_sensor_info[i].sensor_file_name);
strcat(sensor_path, "_label");
file = fopen(sensor_path, "r");
if (file != NULL)
fgets(board_sensors[num_sensors].sensor_name, MAX_SENSOR_NAME_LENGTH, file);
/* Sensor name seems to always have a trailing newline we don't want */
size_t len_without_newline = strcspn(board_sensors[num_sensors].sensor_name, "\n");
board_sensors[num_sensors].sensor_name[len_without_newline] = '\0';
if (num_sensors == max_sensors)
return num_sensors;
num_sensors++;
}
}
}
}
return num_sensors;
}
/* Returns 0 on a bad read or missing sensor, 1 on OK */
int get_sensor_reading(struct hwmon_avail_sensor *sensor, float *reading) {
char buf[256] = {0};
long int raw;
FILE *file;
file = fopen(sensor->file, "r");
if (file == NULL)
return 0;
fgets(buf, 256, file);
raw = strtol(buf, NULL, 10);
fclose(file);
*reading = (float)raw / sensor->sensor_info->divisor;
if (*reading == sensor->sensor_info->bad_value)
return 0;
return 1;
}

45
board-sensors.h Normal file
View File

@ -0,0 +1,45 @@
#include <stdio.h>
#define MAX_SENSOR_NAME_LENGTH 256
struct hwmon_sensor {
char *driver_name; /* Contents of /sys/class/hwmon/hwmonX/name */
char *sensor_file_name; /* Sysfs file to read */
char *name_prefix; /* Prefix to attach to temp*_label for clarity */
char *short_name; /* 'Category' name when using compact mode */
char *units; /* Units string */
float divisor; /* Divisor to convert temp* to units */
float bad_value; /* Raw value that indicates a bad (missing) sensor TODO: verfiy most of these*/
};
/* 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 */
{"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 */
};
struct hwmon_avail_sensor {
char *sensor_name; /* Sensor name as read from the sysfs file */
int sort_index; /* Sort index for order to display in */
char *file; /* File to read from */
struct hwmon_sensor *sensor_info; /* Associated sensor info struct */
};
int find_board_sensors(struct hwmon_avail_sensor *board_sensors, int max_sensors);
int get_sensor_reading(struct hwmon_avail_sensor *sensor, float *reading);

View File

@ -15,8 +15,10 @@
#include "icx3.h"
#include "evga-card.h"
#include "board-sensors.h"
#define MAX_GPUS 16
#define MAX_BOARD_SENSORS 256
#define HEADER_COLOR_START "\x1b[36m"
#define HEADER_COLOR_END "\x1b[39m"
@ -38,21 +40,25 @@ static const char helpstring[] = "Available options:\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"
"--no-reasons : Do not query NVML for clocks reasons (can cause stuttering)\n";
"--no-reasons : Do not query NVML for clock reasons (can cause stuttering)\n"
"--board : Also print temperatures from the CPU, motherboard, and other sensors";
void print_gpu_info(int gpu_num, struct card_info gpus[], int compact, int no_reasons);
void print_board_info(struct hwmon_avail_sensor *board_sensors, int num_sensors, int compact);
int main (int argc, char **argv)
{
struct card_info gpus[MAX_GPUS];
int gpu_count;
struct hwmon_avail_sensor board_sensors[MAX_BOARD_SENSORS];
int gpu_count, board_sensor_count;
int print_info = 0;
int compact = 0;
int gpu_num = -1; /* Card to control */
int i2c_bus = -1;
int overwrite = 0;
int no_reasons = 0;
unsigned int watch = 0;
int compact = 0;
int gpu_num = -1; /* Card to control */
int i2c_bus = -1; /* Specific i2c bus to probe instead of all */
int overwrite = 0; /* Overwrite printed console info in compact mode */
int no_reasons = 0; /* Don't probe or display NVML clock reasons */
unsigned int watch = 0; /* Refresh display every this many seconds */
int print_board_sensors = 0; /* Print CPU/motherbord/other sensors as well */
char *fan_speed[ICX3_MAX_FANS] = {NULL};
/* Input parsing */
@ -114,6 +120,8 @@ int main (int argc, char **argv)
header_end = HEADER_COLOR_END;
} else if (strcmp(argv[i], "--no-reasons") == 0) {
no_reasons = 1;
} else if (strcmp(argv[i], "--board") == 0) {
print_board_sensors = 1;
} else {
printf(helpstring);
return 0;
@ -133,8 +141,10 @@ int main (int argc, char **argv)
if (overwrite && !compact)
overwrite = 0;
/* Scan for supported GPUs */
gpu_count = find_evga_gpu_i2cs(gpus, MAX_GPUS, i2c_bus);
/* Check for no GPUs found or other errors */
if (gpu_count == -1) {
printf("Error scanning I2C devices\n");
return -1;
@ -142,12 +152,15 @@ int main (int argc, char **argv)
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) {
printf("Invalid GPU number specified (%d, max %d)\n", gpu_num, gpu_count - 1);
return -1;
}
/* Scan for motherboard/CPU/other sensors */
if (print_board_sensors)
board_sensor_count = find_board_sensors(board_sensors, MAX_BOARD_SENSORS);
/* execute fan commands */
if (gpu_num == -1) {
@ -183,6 +196,9 @@ int main (int argc, char **argv)
if (overwrite)
printf("\x1b[K"); /* Clear current console line */
if (print_board_sensors)
print_board_info(board_sensors, board_sensor_count, compact);
if (gpu_num == -1) {
/* No GPU specified on command line, loop over all supported GPUs */
for (int i = 0; i < gpu_count; i++){
@ -199,8 +215,8 @@ int main (int argc, char **argv)
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 */
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 */
}
fflush(stdout);
@ -213,7 +229,64 @@ int main (int argc, char **argv)
#endif
}
void print_gpu_info(int gpu_num, struct card_info *gpu, int compact, int no_reasons) {
void print_board_info(struct hwmon_avail_sensor *board_sensors, int num_sensors, int compact)
{
int printed_sensors = 0;
int current_sort_index = 0;
float current_reading = 0.0;
int good_reading = 0;
/* These allow us to 'summarize' units and categories by only printing them when they change */
char *last_short_name = NULL;
char *last_units = NULL;
while (printed_sensors < num_sensors) {
for (int i=0; i < num_sensors; i++){
/* Loop over all sensors, but only output those with the current sort index so they come out sort of sorted
Duplicates (e.g.) multiple NVMe will come out in whatever sort of order the directory listing happened to */
if (board_sensors[i].sort_index == current_sort_index) {
printed_sensors++;
good_reading = get_sensor_reading(&board_sensors[i], &current_reading);
if (!good_reading)
continue;
if (compact) {
/* Print units if needed */
if (last_units != NULL && strcmp(board_sensors[i].sensor_info->units, last_units))
printf("%s", last_units);
/* Print new section header if needed */
if (last_short_name == NULL || strcmp(board_sensors[i].sensor_info->short_name, last_short_name)) {
if (last_short_name != NULL) /* Spacer for all headings not the first one */
printf(" ");
printf("%s%s%s", header_start, board_sensors[i].sensor_info->short_name, header_end);
}
printf(" %3.0f", current_reading);
last_short_name = board_sensors[i].sensor_info->short_name;
last_units = board_sensors[i].sensor_info->units;
} else {
printf("%s%s: %+.1f%s\n",
board_sensors[i].sensor_info->name_prefix,
board_sensors[i].sensor_name,
current_reading,
board_sensors[i].sensor_info->units);
}
}
}
current_sort_index++;
}
if (compact && last_units != NULL)
printf("%s", last_units);
printf("\n");
}
void print_gpu_info(int gpu_num, struct card_info *gpu, int compact, int no_reasons)
{
if (compact) {
/* One line per GPU */
printf("%s#%d FAN%s", header_start, gpu_num, header_end);
@ -268,8 +341,8 @@ void print_gpu_info(int gpu_num, struct card_info *gpu, int compact, int no_reas
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]);
icx3_temp_sensor_names[i],
icx_temp_sensors[i]);
}
#ifdef USE_LIBPCI