node-gpuinfo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +336 -0
  3. package/binding.gyp +69 -0
  4. package/build/Release/gpu.exp +0 -0
  5. package/build/Release/gpu.lib +0 -0
  6. package/build/Release/gpu.node +0 -0
  7. package/build/Release/gpu.pdb +0 -0
  8. package/build/binding.sln +19 -0
  9. package/build/gpu.vcxproj +175 -0
  10. package/build/gpu.vcxproj.filters +169 -0
  11. package/example.js +69 -0
  12. package/index.js +33 -0
  13. package/package.json +68 -0
  14. package/src/binding.cpp +201 -0
  15. package/src/gpu_info.c +130 -0
  16. package/src/gpu_info.h +86 -0
  17. package/src/includes/adlx/ADLX.h +367 -0
  18. package/src/includes/adlx/ADLXDefines.h +1345 -0
  19. package/src/includes/adlx/ADLXHelper/ADLXHelper.c +175 -0
  20. package/src/includes/adlx/ADLXHelper/ADLXHelper.h +245 -0
  21. package/src/includes/adlx/ADLXHelper/WinAPIS.c +64 -0
  22. package/src/includes/adlx/ADLXStructures.h +206 -0
  23. package/src/includes/adlx/ADLXVersion.h +18 -0
  24. package/src/includes/adlx/I3DSettings.h +3476 -0
  25. package/src/includes/adlx/I3DSettings1.h +292 -0
  26. package/src/includes/adlx/I3DSettings2.h +317 -0
  27. package/src/includes/adlx/IApplications.h +397 -0
  28. package/src/includes/adlx/IChangedEvent.h +71 -0
  29. package/src/includes/adlx/ICollections.h +325 -0
  30. package/src/includes/adlx/IDesktops.h +918 -0
  31. package/src/includes/adlx/IDisplay3DLUT.h +663 -0
  32. package/src/includes/adlx/IDisplayGamma.h +683 -0
  33. package/src/includes/adlx/IDisplayGamut.h +760 -0
  34. package/src/includes/adlx/IDisplaySettings.h +3476 -0
  35. package/src/includes/adlx/IDisplays.h +2676 -0
  36. package/src/includes/adlx/IDisplays1.h +191 -0
  37. package/src/includes/adlx/IDisplays2.h +188 -0
  38. package/src/includes/adlx/IDisplays3.h +256 -0
  39. package/src/includes/adlx/IGPUAutoTuning.h +460 -0
  40. package/src/includes/adlx/IGPUManualFanTuning.h +1007 -0
  41. package/src/includes/adlx/IGPUManualGFXTuning.h +607 -0
  42. package/src/includes/adlx/IGPUManualPowerTuning.h +340 -0
  43. package/src/includes/adlx/IGPUManualVRAMTuning.h +576 -0
  44. package/src/includes/adlx/IGPUPresetTuning.h +469 -0
  45. package/src/includes/adlx/IGPUTuning.h +1239 -0
  46. package/src/includes/adlx/IGPUTuning1.h +197 -0
  47. package/src/includes/adlx/II2C.h +198 -0
  48. package/src/includes/adlx/ILog.h +72 -0
  49. package/src/includes/adlx/IMultiMedia.h +578 -0
  50. package/src/includes/adlx/IPerformanceMonitoring.h +2520 -0
  51. package/src/includes/adlx/IPerformanceMonitoring1.h +134 -0
  52. package/src/includes/adlx/IPerformanceMonitoring2.h +341 -0
  53. package/src/includes/adlx/IPerformanceMonitoring3.h +199 -0
  54. package/src/includes/adlx/IPowerTuning.h +473 -0
  55. package/src/includes/adlx/IPowerTuning1.h +515 -0
  56. package/src/includes/adlx/ISmartAccessMemory.h +114 -0
  57. package/src/includes/adlx/ISystem.h +1557 -0
  58. package/src/includes/adlx/ISystem1.h +237 -0
  59. package/src/includes/adlx/ISystem2.h +643 -0
  60. package/src/linux/amd_linux.c +269 -0
  61. package/src/linux/intel_linux.c +20 -0
  62. package/src/linux/nvidia_linux.c +257 -0
  63. package/src/macos/amd_mac.c +131 -0
  64. package/src/macos/intel_mac.c +131 -0
  65. package/src/macos/nvidia_mac.c +21 -0
  66. package/src/vendor/amd.c +37 -0
  67. package/src/vendor/intel.c +37 -0
  68. package/src/vendor/nvidia.c +37 -0
  69. package/src/windows/amd_windows.c +468 -0
  70. package/src/windows/intel_windows.c +157 -0
  71. package/src/windows/nvidia_windows.c +252 -0
@@ -0,0 +1,269 @@
1
+ #include "../gpu_info.h"
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ #include <dirent.h>
6
+ #include <unistd.h>
7
+
8
+ static int is_amd_device(const char* card_path) {
9
+ char vendor_path[512];
10
+ snprintf(vendor_path, sizeof(vendor_path), "%s/device/vendor", card_path);
11
+
12
+ FILE* f = fopen(vendor_path, "r");
13
+ if (!f) return 0;
14
+
15
+ unsigned int vendor;
16
+ int result = fscanf(f, "%x", &vendor);
17
+ fclose(f);
18
+
19
+ // AMD vendor ID is 0x1002
20
+ return (result == 1 && vendor == 0x1002);
21
+ }
22
+
23
+ gpu_error_t amd_linux_get_gpu_count(int32_t* count) {
24
+ if (!count) return GPU_ERROR_INVALID_PARAM;
25
+
26
+ DIR* dir;
27
+ struct dirent* entry;
28
+ int amd_count = 0;
29
+
30
+ dir = opendir("/sys/class/drm");
31
+ if (!dir) {
32
+ *count = 0;
33
+ return GPU_ERROR_API_FAILED;
34
+ }
35
+
36
+ while ((entry = readdir(dir)) != NULL) {
37
+ // Look for card* directories
38
+ if (strncmp(entry->d_name, "card", 4) == 0 &&
39
+ strlen(entry->d_name) == 5 &&
40
+ entry->d_name[4] >= '0' && entry->d_name[4] <= '9') {
41
+
42
+ char card_path[512];
43
+ snprintf(card_path, sizeof(card_path), "/sys/class/drm/%s", entry->d_name);
44
+
45
+ if (is_amd_device(card_path)) {
46
+ amd_count++;
47
+ }
48
+ }
49
+ }
50
+
51
+ closedir(dir);
52
+ *count = amd_count;
53
+ return GPU_SUCCESS;
54
+ }
55
+
56
+ static int read_sysfs_string(const char* path, char* buffer, size_t size) {
57
+ FILE* f = fopen(path, "r");
58
+ if (!f) return 0;
59
+
60
+ if (fgets(buffer, size, f)) {
61
+ // Remove trailing newline
62
+ size_t len = strlen(buffer);
63
+ if (len > 0 && buffer[len-1] == '\n') {
64
+ buffer[len-1] = '\0';
65
+ }
66
+ fclose(f);
67
+ return 1;
68
+ }
69
+
70
+ fclose(f);
71
+ return 0;
72
+ }
73
+
74
+ static long read_sysfs_long(const char* path) {
75
+ FILE* f = fopen(path, "r");
76
+ if (!f) return -1;
77
+
78
+ long value;
79
+ int result = fscanf(f, "%ld", &value);
80
+ fclose(f);
81
+
82
+ return (result == 1) ? value : -1;
83
+ }
84
+
85
+ gpu_error_t amd_linux_get_gpu_info(int32_t index, gpu_info_t* info) {
86
+ if (!info) return GPU_ERROR_INVALID_PARAM;
87
+
88
+ // Find the correct card device
89
+ DIR* dir = opendir("/sys/class/drm");
90
+ if (!dir) return GPU_ERROR_API_FAILED;
91
+
92
+ struct dirent* entry;
93
+ int current_index = 0;
94
+ char card_path[512] = {0};
95
+ int found = 0;
96
+
97
+ while ((entry = readdir(dir)) != NULL) {
98
+ if (strncmp(entry->d_name, "card", 4) == 0 &&
99
+ strlen(entry->d_name) == 5 &&
100
+ entry->d_name[4] >= '0' && entry->d_name[4] <= '9') {
101
+
102
+ char temp_path[512];
103
+ snprintf(temp_path, sizeof(temp_path), "/sys/class/drm/%s", entry->d_name);
104
+
105
+ if (is_amd_device(temp_path)) {
106
+ if (current_index == index) {
107
+ strncpy(card_path, temp_path, sizeof(card_path) - 1);
108
+ found = 1;
109
+ break;
110
+ }
111
+ current_index++;
112
+ }
113
+ }
114
+ }
115
+
116
+ closedir(dir);
117
+
118
+ if (!found) return GPU_ERROR_INVALID_PARAM;
119
+
120
+ // Initialize structure
121
+ memset(info, 0, sizeof(gpu_info_t));
122
+ info->index = index;
123
+ info->vendor = GPU_VENDOR_AMD;
124
+
125
+ // Read GPU name from device
126
+ char name_path[512];
127
+ snprintf(name_path, sizeof(name_path), "%s/device/product_name", card_path);
128
+ if (!read_sysfs_string(name_path, info->name, sizeof(info->name))) {
129
+ // Fallback: try model or just use generic name
130
+ snprintf(name_path, sizeof(name_path), "%s/device/model", card_path);
131
+ if (!read_sysfs_string(name_path, info->name, sizeof(info->name))) {
132
+ snprintf(info->name, sizeof(info->name), "AMD GPU %d", index);
133
+ }
134
+ }
135
+
136
+ // Read device ID for UUID
137
+ char device_path[512];
138
+ snprintf(device_path, sizeof(device_path), "%s/device/device", card_path);
139
+ unsigned int device_id = 0;
140
+ FILE* f = fopen(device_path, "r");
141
+ if (f) {
142
+ fscanf(f, "%x", &device_id);
143
+ fclose(f);
144
+ }
145
+ snprintf(info->uuid, sizeof(info->uuid), "AMD-Linux-0x%04X-%d", device_id, index);
146
+
147
+ // Read PCI bus ID
148
+ char pci_path[512];
149
+ snprintf(pci_path, sizeof(pci_path), "%s/device/uevent", card_path);
150
+ f = fopen(pci_path, "r");
151
+ if (f) {
152
+ char line[256];
153
+ while (fgets(line, sizeof(line), f)) {
154
+ if (strncmp(line, "PCI_SLOT_NAME=", 14) == 0) {
155
+ strncpy(info->pci_bus_id, line + 14, sizeof(info->pci_bus_id) - 1);
156
+ // Remove newline
157
+ size_t len = strlen(info->pci_bus_id);
158
+ if (len > 0 && info->pci_bus_id[len-1] == '\n') {
159
+ info->pci_bus_id[len-1] = '\0';
160
+ }
161
+ break;
162
+ }
163
+ }
164
+ fclose(f);
165
+ }
166
+ if (info->pci_bus_id[0] == '\0') {
167
+ snprintf(info->pci_bus_id, sizeof(info->pci_bus_id), "PCI:%d", index);
168
+ }
169
+
170
+ // Read memory information (in bytes, convert to MB)
171
+ char mem_path[512];
172
+ snprintf(mem_path, sizeof(mem_path), "%s/device/mem_info_vram_total", card_path);
173
+ long mem_total = read_sysfs_long(mem_path);
174
+ if (mem_total > 0) {
175
+ info->memory_total = (int32_t)(mem_total / (1024 * 1024));
176
+ }
177
+
178
+ snprintf(mem_path, sizeof(mem_path), "%s/device/mem_info_vram_used", card_path);
179
+ long mem_used = read_sysfs_long(mem_path);
180
+ if (mem_used > 0) {
181
+ info->memory_used = (int32_t)(mem_used / (1024 * 1024));
182
+ if (info->memory_total > 0) {
183
+ info->memory_free = info->memory_total - info->memory_used;
184
+ info->memory_utilization = (float)info->memory_used / info->memory_total * 100.0f;
185
+ }
186
+ }
187
+
188
+ // Read GPU utilization
189
+ char util_path[512];
190
+ snprintf(util_path, sizeof(util_path), "%s/device/gpu_busy_percent", card_path);
191
+ long gpu_util = read_sysfs_long(util_path);
192
+ if (gpu_util >= 0) {
193
+ info->gpu_utilization = (float)gpu_util;
194
+ }
195
+
196
+ // Read temperature (in millidegrees, convert to Celsius)
197
+ char temp_path[512];
198
+ snprintf(temp_path, sizeof(temp_path), "%s/device/hwmon/hwmon*/temp1_input", card_path);
199
+ // Note: This glob pattern won't work directly, we'd need to enumerate hwmon directories
200
+ // For now, try hwmon0 and hwmon1
201
+ for (int hwmon = 0; hwmon < 4; hwmon++) {
202
+ snprintf(temp_path, sizeof(temp_path), "%s/device/hwmon/hwmon%d/temp1_input", card_path, hwmon);
203
+ long temp = read_sysfs_long(temp_path);
204
+ if (temp > 0) {
205
+ info->temperature = temp / 1000.0f;
206
+ break;
207
+ }
208
+ }
209
+
210
+ // Read power usage (in microwatts, convert to watts)
211
+ char power_path[512];
212
+ for (int hwmon = 0; hwmon < 4; hwmon++) {
213
+ snprintf(power_path, sizeof(power_path), "%s/device/hwmon/hwmon%d/power1_average", card_path, hwmon);
214
+ long power = read_sysfs_long(power_path);
215
+ if (power > 0) {
216
+ info->power_usage = power / 1000000.0f;
217
+ break;
218
+ }
219
+ }
220
+
221
+ // Read clock speeds (in Hz, convert to MHz)
222
+ char clock_path[512];
223
+ snprintf(clock_path, sizeof(clock_path), "%s/device/pp_dpm_sclk", card_path);
224
+ f = fopen(clock_path, "r");
225
+ if (f) {
226
+ char line[256];
227
+ // Find the line with asterisk (current clock)
228
+ while (fgets(line, sizeof(line), f)) {
229
+ if (strchr(line, '*')) {
230
+ unsigned int clock_mhz;
231
+ if (sscanf(line, "%*d: %uMhz", &clock_mhz) == 1) {
232
+ info->core_clock = clock_mhz;
233
+ break;
234
+ }
235
+ }
236
+ }
237
+ fclose(f);
238
+ }
239
+
240
+ snprintf(clock_path, sizeof(clock_path), "%s/device/pp_dpm_mclk", card_path);
241
+ f = fopen(clock_path, "r");
242
+ if (f) {
243
+ char line[256];
244
+ while (fgets(line, sizeof(line), f)) {
245
+ if (strchr(line, '*')) {
246
+ unsigned int clock_mhz;
247
+ if (sscanf(line, "%*d: %uMhz", &clock_mhz) == 1) {
248
+ info->memory_clock = clock_mhz;
249
+ break;
250
+ }
251
+ }
252
+ }
253
+ fclose(f);
254
+ }
255
+
256
+ // Read fan speed (percentage)
257
+ char fan_path[512];
258
+ for (int hwmon = 0; hwmon < 4; hwmon++) {
259
+ snprintf(fan_path, sizeof(fan_path), "%s/device/hwmon/hwmon%d/pwm1", card_path, hwmon);
260
+ long fan_pwm = read_sysfs_long(fan_path);
261
+ if (fan_pwm >= 0) {
262
+ // PWM is typically 0-255
263
+ info->fan_speed = (fan_pwm / 255.0f) * 100.0f;
264
+ break;
265
+ }
266
+ }
267
+
268
+ return GPU_SUCCESS;
269
+ }
@@ -0,0 +1,20 @@
1
+ #include "../gpu_info.h"
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ // Intel GPU detection on Linux is not yet implemented
6
+ // Would require i915 sysfs interface or similar
7
+
8
+ gpu_error_t intel_linux_get_gpu_count(int32_t* count) {
9
+ if (!count) return GPU_ERROR_INVALID_PARAM;
10
+
11
+ // Not yet implemented
12
+ *count = 0;
13
+ return GPU_SUCCESS;
14
+ }
15
+
16
+ gpu_error_t intel_linux_get_gpu_info(int32_t index, gpu_info_t* info) {
17
+ if (!info) return GPU_ERROR_INVALID_PARAM;
18
+
19
+ return GPU_ERROR_NOT_SUPPORTED;
20
+ }
@@ -0,0 +1,257 @@
1
+ #include "../gpu_info.h"
2
+ #include <dlfcn.h>
3
+ #include <stdio.h>
4
+ #include <string.h>
5
+ #include <stdlib.h>
6
+
7
+ static void* nvml_library = NULL;
8
+ static int nvml_initialized = 0;
9
+
10
+ // NVML structures (same as Windows)
11
+ typedef struct {
12
+ unsigned long long total;
13
+ unsigned long long free;
14
+ unsigned long long used;
15
+ } nvmlMemory_t;
16
+
17
+ typedef struct {
18
+ unsigned int gpu;
19
+ unsigned int memory;
20
+ } nvmlUtilization_t;
21
+
22
+ // PCI info structure (same as Windows)
23
+ typedef struct {
24
+ char busId[16]; // PCI bus ID in format: "0000:00:00.0"
25
+ unsigned int domain;
26
+ unsigned int bus;
27
+ unsigned int device;
28
+ unsigned int pciDeviceId;
29
+ unsigned int pciSubSystemId;
30
+ } nvmlPciInfo_t;
31
+
32
+ // Function pointers (same as Windows)
33
+ static int (*nvmlInit_v2)(void) = NULL;
34
+ static int (*nvmlShutdown)(void) = NULL;
35
+ static int (*nvmlDeviceGetCount_v2)(unsigned int*) = NULL;
36
+ static int (*nvmlDeviceGetHandleByIndex)(unsigned int, void**) = NULL;
37
+ static int (*nvmlDeviceGetName)(void*, char*, unsigned int) = NULL;
38
+ static int (*nvmlDeviceGetUUID)(void*, char*, unsigned int) = NULL;
39
+ static int (*nvmlDeviceGetMemoryInfo)(void*, nvmlMemory_t*) = NULL;
40
+ static int (*nvmlDeviceGetUtilizationRates)(void*, nvmlUtilization_t*) = NULL;
41
+ static int (*nvmlDeviceGetTemperature)(void*, int, unsigned int*) = NULL;
42
+ static int (*nvmlDeviceGetPowerUsage)(void*, unsigned int*) = NULL;
43
+ static int (*nvmlDeviceGetClockInfo)(void*, int, unsigned int*) = NULL;
44
+ static int (*nvmlDeviceGetFanSpeed)(void*, unsigned int*) = NULL;
45
+ static int (*nvmlDeviceGetPciInfo)(void*, nvmlPciInfo_t*) = NULL;
46
+
47
+ static gpu_error_t load_nvml_linux(void) {
48
+ if (nvml_initialized) return GPU_SUCCESS;
49
+
50
+ // Try to load NVML library from common locations
51
+ nvml_library = dlopen("libnvidia-ml.so", RTLD_LAZY);
52
+ if (!nvml_library) {
53
+ nvml_library = dlopen("libnvidia-ml.so.1", RTLD_LAZY);
54
+ }
55
+ if (!nvml_library) {
56
+ return GPU_ERROR_NOT_SUPPORTED;
57
+ }
58
+
59
+ // Load all NVML functions
60
+ nvmlInit_v2 = (int(*)(void))dlsym(nvml_library, "nvmlInit_v2");
61
+ nvmlShutdown = (int(*)(void))dlsym(nvml_library, "nvmlShutdown");
62
+ nvmlDeviceGetCount_v2 = (int(*)(unsigned int*))dlsym(nvml_library, "nvmlDeviceGetCount_v2");
63
+ nvmlDeviceGetHandleByIndex = (int(*)(unsigned int, void**))dlsym(nvml_library, "nvmlDeviceGetHandleByIndex");
64
+ nvmlDeviceGetName = (int(*)(void*, char*, unsigned int))dlsym(nvml_library, "nvmlDeviceGetName");
65
+ nvmlDeviceGetUUID = (int(*)(void*, char*, unsigned int))dlsym(nvml_library, "nvmlDeviceGetUUID");
66
+ nvmlDeviceGetMemoryInfo = (int(*)(void*, nvmlMemory_t*))dlsym(nvml_library, "nvmlDeviceGetMemoryInfo");
67
+ nvmlDeviceGetUtilizationRates = (int(*)(void*, nvmlUtilization_t*))dlsym(nvml_library, "nvmlDeviceGetUtilizationRates");
68
+ nvmlDeviceGetTemperature = (int(*)(void*, int, unsigned int*))dlsym(nvml_library, "nvmlDeviceGetTemperature");
69
+ nvmlDeviceGetPowerUsage = (int(*)(void*, unsigned int*))dlsym(nvml_library, "nvmlDeviceGetPowerUsage");
70
+ nvmlDeviceGetClockInfo = (int(*)(void*, int, unsigned int*))dlsym(nvml_library, "nvmlDeviceGetClockInfo");
71
+ nvmlDeviceGetFanSpeed = (int(*)(void*, unsigned int*))dlsym(nvml_library, "nvmlDeviceGetFanSpeed");
72
+ nvmlDeviceGetPciInfo = (int(*)(void*, nvmlPciInfo_t*))dlsym(nvml_library, "nvmlDeviceGetPciInfo");
73
+
74
+ // Check for essential functions
75
+ if (!nvmlInit_v2 || !nvmlDeviceGetCount_v2 || !nvmlDeviceGetHandleByIndex) {
76
+ dlclose(nvml_library);
77
+ nvml_library = NULL;
78
+ return GPU_ERROR_NOT_SUPPORTED;
79
+ }
80
+
81
+ if (nvmlInit_v2() != 0) {
82
+ dlclose(nvml_library);
83
+ nvml_library = NULL;
84
+ return GPU_ERROR_NOT_SUPPORTED;
85
+ }
86
+
87
+ nvml_initialized = 1;
88
+ return GPU_SUCCESS;
89
+ }
90
+
91
+ gpu_error_t nvidia_linux_get_gpu_count(int32_t* count) {
92
+ if (!count) return GPU_ERROR_INVALID_PARAM;
93
+
94
+ gpu_error_t result = load_nvml_linux();
95
+ if (result != GPU_SUCCESS) {
96
+ *count = 0;
97
+ return GPU_SUCCESS;
98
+ }
99
+
100
+ unsigned int nv_count = 0;
101
+ if (nvmlDeviceGetCount_v2(&nv_count) != 0) {
102
+ *count = 0;
103
+ return GPU_ERROR_API_FAILED;
104
+ }
105
+
106
+ *count = (int32_t)nv_count;
107
+ return GPU_SUCCESS;
108
+ }
109
+
110
+ gpu_error_t nvidia_linux_get_gpu_info(int32_t index, gpu_info_t* info) {
111
+ if (!info) return GPU_ERROR_INVALID_PARAM;
112
+
113
+ gpu_error_t result = load_nvml_linux();
114
+ if (result != GPU_SUCCESS) {
115
+ return result;
116
+ }
117
+
118
+ void* device;
119
+ if (nvmlDeviceGetHandleByIndex((unsigned int)index, &device) != 0) {
120
+ return GPU_ERROR_API_FAILED;
121
+ }
122
+
123
+ memset(info, 0, sizeof(gpu_info_t));
124
+ info->index = index;
125
+ info->vendor = GPU_VENDOR_NVIDIA;
126
+
127
+ // Get GPU name
128
+ char name[256];
129
+ if (nvmlDeviceGetName && nvmlDeviceGetName(device, name, sizeof(name)) == 0) {
130
+ strncpy(info->name, name, sizeof(info->name) - 1);
131
+ } else {
132
+ strncpy(info->name, "NVIDIA GPU", sizeof(info->name) - 1);
133
+ }
134
+
135
+ // Get UUID
136
+ char uuid[64];
137
+ if (nvmlDeviceGetUUID && nvmlDeviceGetUUID(device, uuid, sizeof(uuid)) == 0) {
138
+ strncpy(info->uuid, uuid, sizeof(info->uuid) - 1);
139
+ } else {
140
+ snprintf(info->uuid, sizeof(info->uuid), "NVIDIA-%d", index);
141
+ }
142
+
143
+ // Get PCI bus information
144
+ if (nvmlDeviceGetPciInfo) {
145
+ nvmlPciInfo_t pciInfo;
146
+ if (nvmlDeviceGetPciInfo(device, &pciInfo) == 0) {
147
+ // Use the actual PCI bus ID from NVML
148
+ strncpy(info->pci_bus_id, pciInfo.busId, sizeof(info->pci_bus_id) - 1);
149
+
150
+ // Debug output to see all PCI information (optional)
151
+ /*printf("GPU %d PCI Info:\n", index);
152
+ printf(" Bus ID: %s\n", pciInfo.busId);
153
+ printf(" Domain: 0x%04X\n", pciInfo.domain);
154
+ printf(" Bus: 0x%02X\n", pciInfo.bus);
155
+ printf(" Device: 0x%02X\n", pciInfo.device);
156
+ printf(" Device ID: 0x%04X\n", pciInfo.pciDeviceId);
157
+ printf(" Subsystem ID: 0x%04X\n", pciInfo.pciSubSystemId);*/
158
+ } else {
159
+ // Fallback: generate from index
160
+ snprintf(info->pci_bus_id, sizeof(info->pci_bus_id), "PCI:%d", index);
161
+ }
162
+ } else {
163
+ // Fallback: generate from index
164
+ snprintf(info->pci_bus_id, sizeof(info->pci_bus_id), "PCI:%d", index);
165
+ }
166
+
167
+ // Get memory info
168
+ nvmlMemory_t memory;
169
+ if (nvmlDeviceGetMemoryInfo && nvmlDeviceGetMemoryInfo(device, &memory) == 0) {
170
+ info->memory_total = memory.total / (1024 * 1024); // Convert to MB
171
+ info->memory_used = memory.used / (1024 * 1024);
172
+ info->memory_free = memory.free / (1024 * 1024);
173
+
174
+ // Calculate memory capacity utilization (for reference)
175
+ float capacity_utilization = 0.0f;
176
+ if (memory.total > 0) {
177
+ capacity_utilization = (float)memory.used / memory.total * 100.0f;
178
+ }
179
+
180
+ // Debug output (optional)
181
+ /*printf("GPU %d Memory: %llu/%llu MB (%.1f%% capacity)\n",
182
+ index, memory.used / (1024 * 1024), memory.total / (1024 * 1024),
183
+ capacity_utilization);*/
184
+ } else {
185
+ // Fallback values
186
+ info->memory_total = 8 * 1024;
187
+ info->memory_used = 0;
188
+ info->memory_free = 8 * 1024;
189
+ }
190
+
191
+ // Get utilization rates
192
+ nvmlUtilization_t utilization;
193
+ if (nvmlDeviceGetUtilizationRates && nvmlDeviceGetUtilizationRates(device, &utilization) == 0) {
194
+ info->gpu_utilization = (float)utilization.gpu;
195
+ info->memory_utilization = (float)utilization.memory; // Memory bandwidth utilization
196
+
197
+ // Debug output (optional)
198
+ /*printf("GPU %d Utilization: GPU=%u%%, Memory=%u%%\n",
199
+ index, utilization.gpu, utilization.memory);*/
200
+ } else {
201
+ info->gpu_utilization = 0.0f;
202
+ info->memory_utilization = 0.0f;
203
+ }
204
+
205
+ // Get temperature (GPU core)
206
+ unsigned int temperature;
207
+ if (nvmlDeviceGetTemperature && nvmlDeviceGetTemperature(device, 0, &temperature) == 0) {
208
+ info->temperature = (float)temperature;
209
+ } else {
210
+ info->temperature = 0.0f;
211
+ }
212
+
213
+ // Get power usage (in milliwatts)
214
+ unsigned int power;
215
+ if (nvmlDeviceGetPowerUsage && nvmlDeviceGetPowerUsage(device, &power) == 0) {
216
+ info->power_usage = (float)power / 1000.0f; // Convert to watts
217
+ } else {
218
+ info->power_usage = 0.0f;
219
+ }
220
+
221
+ // Get core clock (graphics clock)
222
+ unsigned int clock;
223
+ if (nvmlDeviceGetClockInfo && nvmlDeviceGetClockInfo(device, 0, &clock) == 0) {
224
+ info->core_clock = clock;
225
+ } else {
226
+ info->core_clock = 0;
227
+ }
228
+
229
+ // Get memory clock
230
+ if (nvmlDeviceGetClockInfo && nvmlDeviceGetClockInfo(device, 1, &clock) == 0) {
231
+ info->memory_clock = clock;
232
+ } else {
233
+ info->memory_clock = 0;
234
+ }
235
+
236
+ // Get fan speed
237
+ unsigned int fan_speed;
238
+ if (nvmlDeviceGetFanSpeed && nvmlDeviceGetFanSpeed(device, &fan_speed) == 0) {
239
+ info->fan_speed = (float)fan_speed;
240
+ } else {
241
+ info->fan_speed = 0.0f;
242
+ }
243
+
244
+ return GPU_SUCCESS;
245
+ }
246
+
247
+ // Cleanup function
248
+ void nvidia_linux_cleanup(void) {
249
+ if (nvml_initialized && nvmlShutdown) {
250
+ nvmlShutdown();
251
+ }
252
+ if (nvml_library) {
253
+ dlclose(nvml_library);
254
+ nvml_library = NULL;
255
+ }
256
+ nvml_initialized = 0;
257
+ }
@@ -0,0 +1,131 @@
1
+ #include "../gpu_info.h"
2
+ #include <CoreFoundation/CoreFoundation.h>
3
+ #include <IOKit/IOKitLib.h>
4
+ #include <IOKit/graphics/IOGraphicsLib.h>
5
+ #include <stdio.h>
6
+ #include <string.h>
7
+
8
+ gpu_error_t amd_macos_get_gpu_count(int32_t* count) {
9
+ if (!count) return GPU_ERROR_INVALID_PARAM;
10
+
11
+ int amd_count = 0;
12
+ io_iterator_t iterator;
13
+
14
+ // Get list of all GPUs
15
+ kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault,
16
+ IOServiceMatching("IOPCIDevice"),
17
+ &iterator);
18
+
19
+ if (kr != KERN_SUCCESS) {
20
+ *count = 0;
21
+ return GPU_ERROR_API_FAILED;
22
+ }
23
+
24
+ io_object_t service;
25
+ while ((service = IOIteratorNext(iterator))) {
26
+ // Check if it's a display device
27
+ CFTypeRef vendorID = IORegistryEntryCreateCFProperty(service, CFSTR("vendor-id"),
28
+ kCFAllocatorDefault, 0);
29
+
30
+ if (vendorID) {
31
+ UInt32 vendor = 0;
32
+ CFDataGetBytes(vendorID, CFRangeMake(0, sizeof(UInt32)), (UInt8*)&vendor);
33
+ CFRelease(vendorID);
34
+
35
+ // AMD vendor ID is 0x1002
36
+ if (vendor == 0x1002) {
37
+ amd_count++;
38
+ }
39
+ }
40
+
41
+ IOObjectRelease(service);
42
+ }
43
+
44
+ IOObjectRelease(iterator);
45
+ *count = amd_count;
46
+ return GPU_SUCCESS;
47
+ }
48
+
49
+ gpu_error_t amd_macos_get_gpu_info(int32_t index, gpu_info_t* info) {
50
+ if (!info) return GPU_ERROR_INVALID_PARAM;
51
+
52
+ int current_index = 0;
53
+ io_iterator_t iterator;
54
+
55
+ kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault,
56
+ IOServiceMatching("IOPCIDevice"),
57
+ &iterator);
58
+
59
+ if (kr != KERN_SUCCESS) {
60
+ return GPU_ERROR_API_FAILED;
61
+ }
62
+
63
+ io_object_t service;
64
+ int found = 0;
65
+
66
+ while ((service = IOIteratorNext(iterator))) {
67
+ CFTypeRef vendorID = IORegistryEntryCreateCFProperty(service, CFSTR("vendor-id"),
68
+ kCFAllocatorDefault, 0);
69
+
70
+ if (vendorID) {
71
+ UInt32 vendor = 0;
72
+ CFDataGetBytes(vendorID, CFRangeMake(0, sizeof(UInt32)), (UInt8*)&vendor);
73
+ CFRelease(vendorID);
74
+
75
+ if (vendor == 0x1002) { // AMD
76
+ if (current_index == index) {
77
+ found = 1;
78
+
79
+ memset(info, 0, sizeof(gpu_info_t));
80
+ info->index = index;
81
+ info->vendor = GPU_VENDOR_AMD;
82
+
83
+ // Get model name
84
+ CFTypeRef model = IORegistryEntryCreateCFProperty(service, CFSTR("model"),
85
+ kCFAllocatorDefault, 0);
86
+ if (model && CFGetTypeID(model) == CFDataGetTypeID()) {
87
+ const char* modelStr = (const char*)CFDataGetBytePtr(model);
88
+ snprintf(info->name, sizeof(info->name), "%s", modelStr);
89
+ CFRelease(model);
90
+ } else {
91
+ snprintf(info->name, sizeof(info->name), "AMD GPU %d", index);
92
+ }
93
+
94
+ // Get device ID for UUID
95
+ CFTypeRef deviceID = IORegistryEntryCreateCFProperty(service, CFSTR("device-id"),
96
+ kCFAllocatorDefault, 0);
97
+ if (deviceID) {
98
+ UInt32 devID = 0;
99
+ CFDataGetBytes(deviceID, CFRangeMake(0, sizeof(UInt32)), (UInt8*)&devID);
100
+ snprintf(info->uuid, sizeof(info->uuid), "AMD-macOS-0x%04X", devID);
101
+ CFRelease(deviceID);
102
+ }
103
+
104
+ snprintf(info->pci_bus_id, sizeof(info->pci_bus_id), "PCI:%d", index);
105
+
106
+ // macOS does not provide detailed GPU monitoring APIs
107
+ // Metal framework and IOKit have limited metrics access
108
+ info->memory_total = 0;
109
+ info->memory_used = 0;
110
+ info->memory_free = 0;
111
+ info->gpu_utilization = 0.0f;
112
+ info->memory_utilization = 0.0f;
113
+ info->temperature = 0.0f;
114
+ info->power_usage = 0.0f;
115
+ info->core_clock = 0;
116
+ info->memory_clock = 0;
117
+ info->fan_speed = 0.0f;
118
+
119
+ IOObjectRelease(service);
120
+ break;
121
+ }
122
+ current_index++;
123
+ }
124
+ }
125
+
126
+ IOObjectRelease(service);
127
+ }
128
+
129
+ IOObjectRelease(iterator);
130
+ return found ? GPU_SUCCESS : GPU_ERROR_API_FAILED;
131
+ }