diff --git a/README.md b/README.md index 46e9543..1213c46 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ cd gddr6 sudo gddr6 ``` +## Running +``` +sudo gddr6 # for human-readable monitoring +sudo gddr6 -j # for one-time JSON output +``` + ## Supported GPUs - RTX 4090 (AD102) - RTX 4080 Super (AD103) diff --git a/app/src/app.c b/app/src/app.c index 2292301..5da76e7 100644 --- a/app/src/app.c +++ b/app/src/app.c @@ -3,6 +3,7 @@ #include #include #include +#include void register_signal_handlers(void) { @@ -24,12 +25,20 @@ int main(int argc, char **argv) if (num_devs == 0) { - printf("No compatible GPU found.\n"); + fprintf(stderr, "No compatible GPU found.\n"); return 1; } gddr6_memory_map(); - gddr6_monitor_temperatures(); + + if (argc >= 2 && !strcmp(argv[1], "-j")) + { + gddr6_print_temperatures_json(); + } + else + { + gddr6_monitor_temperatures(); + } return 0; } diff --git a/lib/include/gddr6.h b/lib/include/gddr6.h index 957d71b..d93c6cc 100644 --- a/lib/include/gddr6.h +++ b/lib/include/gddr6.h @@ -22,12 +22,16 @@ struct gddr6_ctx { struct device *devices; int num_devices; int fd; + uint32_t *temperatures; }; void gddr6_init(void); void gddr6_memory_map(void); +void gddr6_print_memory_map(void); void gddr6_cleanup(int signal); +void gddr6_get_temperatures(void); void gddr6_monitor_temperatures(void); +void gddr6_print_temperatures_json(void); int gddr6_detect_compatible_gpus(void); #endif // GDDR6_H diff --git a/lib/src/gddr6.c b/lib/src/gddr6.c index d6974f6..be91722 100644 --- a/lib/src/gddr6.c +++ b/lib/src/gddr6.c @@ -53,7 +53,8 @@ struct device dev_table[] = void gddr6_init(void) { ctx.fd = open("/dev/mem", O_RDONLY); - if (ctx.fd == -1) { + if (ctx.fd == -1) + { PRINT_ERROR(); } } @@ -73,33 +74,38 @@ int gddr6_detect_compatible_gpus(void) for (pci_dev = pacc->devices; pci_dev != NULL; pci_dev = pci_dev->next) { - pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); - for (uint32_t i = 0; i < dev_table_size; ++i) - { - if (pci_dev->device_id == dev_table[i].dev_id) - { - struct device *new_devices = realloc(ctx.devices, (ctx.num_devices + 1) * sizeof(struct device)); - if (new_devices == NULL) - { - fprintf(stderr, "Memory allocation failed\n"); - pci_cleanup(pacc); - free(ctx.devices); - ctx.devices = NULL; - return 0; - } - ctx.devices = new_devices; - - ctx.devices[ctx.num_devices] = dev_table[i]; - ctx.devices[ctx.num_devices].bar0 = (pci_dev->base_addr[0] & 0xffffffff); - ctx.devices[ctx.num_devices].bus = pci_dev->bus; - ctx.devices[ctx.num_devices].dev = pci_dev->dev; - ctx.devices[ctx.num_devices].func = pci_dev->func; - ctx.num_devices++; - } - } - } + pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); + for (uint32_t i = 0; i < dev_table_size; ++i) + { + if (pci_dev->device_id == dev_table[i].dev_id) + { + struct device *new_devices = realloc(ctx.devices, (ctx.num_devices + 1) * sizeof(struct device)); + if (new_devices == NULL) + { + fprintf(stderr, "Memory allocation failed\n"); + exit(EXIT_FAILURE); + } + ctx.devices = new_devices; + + ctx.devices[ctx.num_devices] = dev_table[i]; + ctx.devices[ctx.num_devices].bar0 = (pci_dev->base_addr[0] & 0xffffffff); + ctx.devices[ctx.num_devices].bus = pci_dev->bus; + ctx.devices[ctx.num_devices].dev = pci_dev->dev; + ctx.devices[ctx.num_devices].func = pci_dev->func; + ctx.num_devices++; + } + } + } pci_cleanup(pacc); + + ctx.temperatures = malloc(ctx.num_devices * sizeof(uint32_t)); + if (ctx.temperatures == NULL) + { + fprintf(stderr, "Memory allocation failed\n"); + exit(EXIT_FAILURE); + } + return ctx.num_devices; } @@ -114,36 +120,82 @@ void gddr6_memory_map(void) if (ctx.devices[i].mapped_addr == MAP_FAILED) { ctx.devices[i].mapped_addr = NULL; - fprintf(stderr, "Memory mapping failed for pci=%x:%x:%x\n", ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); + fprintf(stderr, "Memory mapping failed for pci=%02X:%02X.%X\n", ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); fprintf(stderr, "Did you enable iomem=relaxed? Are you r00t?\n"); exit(EXIT_FAILURE); - } else { - printf("Device: %s %s (%s / 0x%04x) pci=%x:%x:%x\n", ctx.devices[i].name, ctx.devices[i].vram, - ctx.devices[i].arch, ctx.devices[i].dev_id, ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); } } } -void gddr6_monitor_temperatures(void) +void gddr6_print_memory_map(void) { - while (1) { - printf("\rVRAM Temps: |"); - for (uint32_t i = 0; i < ctx.num_devices; i++) - { - if (ctx.devices[i].mapped_addr == NULL || ctx.devices[i].mapped_addr == MAP_FAILED) - { - continue; - } + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + if (ctx.devices[i].mapped_addr == NULL || ctx.devices[i].mapped_addr == MAP_FAILED) { + continue; + } + printf("Device: %s %s (%s / 0x%04x) pci=%02X:%02X.%X\n", ctx.devices[i].name, ctx.devices[i].vram, + ctx.devices[i].arch, ctx.devices[i].dev_id, ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); + } +} + +void gddr6_get_temperatures(void) +{ + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + if (ctx.devices[i].mapped_addr == NULL || ctx.devices[i].mapped_addr == MAP_FAILED) + { + ctx.temperatures[i] = 0; + } + else + { void *virt_addr = (uint8_t *) ctx.devices[i].mapped_addr + (ctx.devices[i].phys_addr - ctx.devices[i].base_offset); uint32_t read_result = *((uint32_t *)virt_addr); uint32_t temp = ((read_result & 0x00000fff) / 0x20); + ctx.temperatures[i] = temp; + } + } +} - printf(" %3u°C |", temp); +void gddr6_monitor_temperatures(void) +{ + gddr6_print_memory_map(); + + while (1) + { + gddr6_get_temperatures(); + printf("\rVRAM Temps: |"); + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + printf(" %3u°C |", ctx.temperatures[i]); } fflush(stdout); sleep(1); - } + } +} + +void gddr6_print_temperatures_json(void) +{ + if (ctx.num_devices == 0) + { + printf("[]\n"); + return; + } + + gddr6_get_temperatures(); + + printf("[\n"); + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + char *delimiter = i < ctx.num_devices - 1 ? "," : ""; + printf( + " {\"name\": \"%s\", \"vram\": \"%s\", \"arch\": \"%s\", \"dev_id\": \"0x%04x\", \"pci_id\": \"%02X:%02X.%X\", \"temp\": %d}%s\n", + ctx.devices[i].name, ctx.devices[i].vram, ctx.devices[i].arch, ctx.devices[i].dev_id, ctx.devices[i].bus, ctx.devices[i].dev, + ctx.devices[i].func, ctx.temperatures[i], delimiter + ); + } + printf("]\n"); } void gddr6_cleanup(int signal)