Files
fastfetch/src/detection/gpu/gpu_nvidia.c
T

331 lines
12 KiB
C
Raw Normal View History

#include "gpu_driver_specific.h"
2023-10-26 23:28:43 +08:00
2026-01-06 09:48:38 +08:00
#include "common/library.h"
#include "nvml.h"
2023-10-26 23:28:43 +08:00
struct FFNvmlData {
FF_LIBRARY_SYMBOL(nvmlDeviceGetCount_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByIndex_v2)
2023-10-27 21:05:03 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByPciBusId_v2)
2023-10-26 23:28:43 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetPciInfo_v3)
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperatureV)
2023-10-28 13:12:04 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo)
2023-10-28 13:12:04 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxClockInfo)
2024-07-31 23:40:25 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetUtilizationRates)
2026-06-13 15:20:40 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkGeneration)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkWidth)
2026-06-14 17:36:54 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkGeneration)
FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkWidth)
2024-01-04 18:50:38 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand)
2024-09-19 15:22:09 +08:00
FF_LIBRARY_SYMBOL(nvmlDeviceGetIndex)
FF_LIBRARY_SYMBOL(nvmlDeviceGetName)
2023-10-26 23:28:43 +08:00
bool inited;
} nvmlData;
#if defined(_WIN32) && !defined(FF_DISABLE_DLOPEN)
#include "nvapi.h"
struct FFNvapiData {
FF_LIBRARY_SYMBOL(nvapi_Unload)
FF_LIBRARY_SYMBOL(nvapi_EnumPhysicalGPUs)
FF_LIBRARY_SYMBOL(nvapi_GPU_GetRamType)
2025-07-09 00:11:31 +08:00
FF_LIBRARY_SYMBOL(nvapi_GPU_GetGPUType)
bool inited;
} nvapiData;
2026-03-29 09:28:49 +08:00
static const char* detectMoreByNvapi(FFGpuDriverResult* result) {
if (!nvapiData.inited) {
nvapiData.inited = true;
FF_LIBRARY_LOAD_MESSAGE(libnvapi,
#ifdef _WIN64
"nvapi64.dll"
#else
"nvapi.dll"
#endif
2026-03-29 09:28:49 +08:00
,
1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libnvapi, nvapi_QueryInterface)
#define FF_NVAPI_INTERFACE(iName, iOffset) \
2026-07-11 00:10:40 +08:00
typeof(&iName) ff##iName = ffnvapi_QueryInterface(iOffset); \
2026-07-10 18:08:04 +08:00
if (ff##iName == nullptr) return "nvapi_QueryInterface " #iName " failed";
FF_NVAPI_INTERFACE(nvapi_Initialize, NVAPI_INTERFACE_OFFSET_INITIALIZE)
FF_NVAPI_INTERFACE(nvapi_Unload, NVAPI_INTERFACE_OFFSET_UNLOAD)
FF_NVAPI_INTERFACE(nvapi_EnumPhysicalGPUs, NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS)
FF_NVAPI_INTERFACE(nvapi_GPU_GetRamType, NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE)
2025-07-09 00:11:31 +08:00
FF_NVAPI_INTERFACE(nvapi_GPU_GetGPUType, NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE)
#undef FF_NVAPI_INTERFACE
2026-03-29 09:28:49 +08:00
if (ffnvapi_Initialize() < 0) {
return "NvAPI_Initialize() failed";
2026-03-29 09:28:49 +08:00
}
nvapiData.ffnvapi_EnumPhysicalGPUs = ffnvapi_EnumPhysicalGPUs;
nvapiData.ffnvapi_GPU_GetRamType = ffnvapi_GPU_GetRamType;
2025-07-09 00:11:31 +08:00
nvapiData.ffnvapi_GPU_GetGPUType = ffnvapi_GPU_GetGPUType;
nvapiData.ffnvapi_Unload = ffnvapi_Unload;
atexit((void*) ffnvapi_Unload);
2026-07-10 18:08:04 +08:00
libnvapi = nullptr; // don't close nvapi
}
2026-07-10 18:08:04 +08:00
if (nvapiData.ffnvapi_EnumPhysicalGPUs == nullptr) {
return "loading nvapi library failed";
2026-03-29 09:28:49 +08:00
}
NvPhysicalGpuHandle handles[32];
int gpuCount = 0;
2026-03-29 09:28:49 +08:00
if (nvapiData.ffnvapi_EnumPhysicalGPUs(handles, &gpuCount) < 0) {
return "NvAPI_EnumPhysicalGPUs() failed";
2026-03-29 09:28:49 +08:00
}
uint32_t gpuIndex = *result->index;
2026-03-29 09:28:49 +08:00
if (gpuIndex >= (uint32_t) gpuCount) {
return "GPU index out of range";
2026-03-29 09:28:49 +08:00
}
2025-03-25 00:14:03 +08:00
// Not very sure. Need to check in multi-GPU system
NvPhysicalGpuHandle gpuHandle = handles[gpuIndex];
NvApiGPUMemoryType memType;
2026-03-29 09:28:49 +08:00
if (result->memoryType && nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) == 0) {
switch (memType) {
#define FF_NVAPI_MEMORY_TYPE(type) \
2026-03-29 09:28:49 +08:00
case NVAPI_GPU_MEMORY_TYPE_##type: \
ffStrbufSetStatic(result->memoryType, #type); \
break;
2025-07-09 00:11:31 +08:00
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
FF_NVAPI_MEMORY_TYPE(SDRAM)
FF_NVAPI_MEMORY_TYPE(DDR1)
FF_NVAPI_MEMORY_TYPE(DDR2)
FF_NVAPI_MEMORY_TYPE(GDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR3)
FF_NVAPI_MEMORY_TYPE(GDDR4)
FF_NVAPI_MEMORY_TYPE(DDR3)
FF_NVAPI_MEMORY_TYPE(GDDR5)
FF_NVAPI_MEMORY_TYPE(LPDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR5X)
FF_NVAPI_MEMORY_TYPE(LPDDR3)
FF_NVAPI_MEMORY_TYPE(LPDDR4)
FF_NVAPI_MEMORY_TYPE(LPDDR5)
FF_NVAPI_MEMORY_TYPE(GDDR6)
FF_NVAPI_MEMORY_TYPE(GDDR6X)
FF_NVAPI_MEMORY_TYPE(GDDR7)
#undef FF_NVAPI_MEMORY_TYPE
2025-07-09 00:11:31 +08:00
default:
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
break;
}
}
2025-07-09 00:11:31 +08:00
NvApiGPUType gpuType;
2026-03-29 09:28:49 +08:00
if (result->type && nvapiData.ffnvapi_GPU_GetGPUType(gpuHandle, &gpuType) == 0) {
switch (gpuType) {
2025-07-09 00:11:31 +08:00
case NV_SYSTEM_TYPE_IGPU:
*result->type = FF_GPU_TYPE_INTEGRATED;
break;
2025-07-09 00:11:31 +08:00
case NV_SYSTEM_TYPE_DGPU:
*result->type = FF_GPU_TYPE_DISCRETE;
break;
default:
*result->type = FF_GPU_TYPE_UNKNOWN;
break;
}
}
2026-07-10 18:08:04 +08:00
return nullptr;
}
#endif
2026-03-29 09:28:49 +08:00
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName) {
#ifndef FF_DISABLE_DLOPEN
2026-03-29 09:28:49 +08:00
if (!nvmlData.inited) {
2023-10-26 23:28:43 +08:00
nvmlData.inited = true;
2026-03-29 09:28:49 +08:00
FF_LIBRARY_LOAD(libnvml, "dlopen nvml failed", soName, 1);
2023-10-26 23:28:43 +08:00
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libnvml, nvmlInit_v2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libnvml, nvmlShutdown)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCount_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByIndex_v2)
2023-10-27 21:05:03 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByPciBusId_v2)
2023-10-26 23:28:43 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetPciInfo_v3)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperatureV)
2023-10-28 13:12:04 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo)
2023-10-28 13:12:04 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxClockInfo)
2026-06-13 15:20:40 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkGeneration)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkWidth)
2026-06-14 17:36:54 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkGeneration)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkWidth)
2024-07-31 23:40:25 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetUtilizationRates)
2024-01-04 18:50:38 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand)
2024-09-19 15:22:09 +08:00
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetIndex)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetName)
2023-10-26 23:28:43 +08:00
2026-03-29 09:28:49 +08:00
if (ffnvmlInit_v2() != NVML_SUCCESS) {
2026-07-10 18:08:04 +08:00
nvmlData.ffnvmlDeviceGetNumGpuCores = nullptr;
2023-10-26 23:28:43 +08:00
return "nvmlInit_v2() failed";
}
atexit((void*) ffnvmlShutdown);
2026-07-10 18:08:04 +08:00
libnvml = nullptr; // don't close nvml
2023-10-26 23:28:43 +08:00
}
2026-07-10 18:08:04 +08:00
if (nvmlData.ffnvmlDeviceGetNumGpuCores == nullptr) {
2023-10-26 23:28:43 +08:00
return "loading nvml library failed";
2026-03-29 09:28:49 +08:00
}
2023-10-26 23:28:43 +08:00
2026-07-10 18:08:04 +08:00
nvmlDevice_t device = nullptr;
2026-03-29 09:28:49 +08:00
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID) {
char pciBusIdStr[32];
2025-03-25 00:14:03 +08:00
snprintf(pciBusIdStr, ARRAY_SIZE(pciBusIdStr), "%04x:%02x:%02x.%d", cond->pciBusId.domain, cond->pciBusId.bus, cond->pciBusId.device, cond->pciBusId.func);
nvmlReturn_t ret = nvmlData.ffnvmlDeviceGetHandleByPciBusId_v2(pciBusIdStr, &device);
2026-03-29 09:28:49 +08:00
if (ret != NVML_SUCCESS) {
2023-10-27 21:05:03 +08:00
return "nvmlDeviceGetHandleByPciBusId_v2() failed";
2026-03-29 09:28:49 +08:00
}
} else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID) {
2023-10-27 21:05:03 +08:00
uint32_t count;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetCount_v2(&count) != NVML_SUCCESS) {
2023-10-27 21:05:03 +08:00
return "nvmlDeviceGetCount_v2() failed";
2026-03-29 09:28:49 +08:00
}
2023-10-26 23:28:43 +08:00
2026-07-10 18:08:04 +08:00
for (uint32_t i = 0; i < count; i++, device = nullptr) {
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetHandleByIndex_v2(i, &device) != NVML_SUCCESS) {
2023-10-27 21:05:03 +08:00
continue;
2026-03-29 09:28:49 +08:00
}
2023-10-26 23:28:43 +08:00
2023-10-27 21:05:03 +08:00
nvmlPciInfo_t pciInfo;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetPciInfo_v3(device, &pciInfo) != NVML_SUCCESS) {
2023-10-27 21:05:03 +08:00
continue;
2026-03-29 09:28:49 +08:00
}
2023-10-26 23:28:43 +08:00
if (pciInfo.pciDeviceId != ((cond->pciDeviceId.deviceId << 16u) | cond->pciDeviceId.vendorId) ||
2026-03-29 09:28:49 +08:00
pciInfo.pciSubSystemId != cond->pciDeviceId.subSystemId) {
2023-10-27 21:05:03 +08:00
continue;
2026-03-29 09:28:49 +08:00
}
2023-10-26 23:28:43 +08:00
2023-10-27 21:05:03 +08:00
break;
}
2023-10-26 23:28:43 +08:00
}
2026-03-29 09:28:49 +08:00
if (!device) {
return "Device not found";
}
2025-03-25 00:14:03 +08:00
2026-03-29 09:28:49 +08:00
if (result.type) {
2025-03-25 00:14:03 +08:00
nvmlBrandType_t brand;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetBrand(device, &brand) == NVML_SUCCESS) {
switch (brand) {
2025-03-25 00:14:03 +08:00
case NVML_BRAND_NVIDIA_RTX:
case NVML_BRAND_QUADRO_RTX:
case NVML_BRAND_GEFORCE:
case NVML_BRAND_TITAN:
case NVML_BRAND_TESLA:
case NVML_BRAND_QUADRO:
*result.type = FF_GPU_TYPE_DISCRETE;
break;
default:
break;
}
2024-01-04 18:50:38 +08:00
}
}
2026-03-29 09:28:49 +08:00
if (result.index) {
2024-09-19 15:22:09 +08:00
unsigned int value;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetIndex(device, &value) == NVML_SUCCESS) {
2024-09-19 15:38:43 +08:00
*result.index = value;
#ifdef _WIN32
2025-07-09 00:11:31 +08:00
// Don't bother loading nvapi for GPU type detection only
2026-03-29 09:28:49 +08:00
if (result.memoryType) {
2025-07-09 00:11:31 +08:00
detectMoreByNvapi(&result);
2026-03-29 09:28:49 +08:00
}
#endif
}
2024-09-19 15:22:09 +08:00
}
2024-09-19 15:38:43 +08:00
2026-03-29 09:28:49 +08:00
if (result.temp) {
nvmlTemperature_v1_t temp = {
.version = nvmlTemperature_v1,
.sensorType = NVML_TEMPERATURE_GPU,
};
if (nvmlData.ffnvmlDeviceGetTemperatureV(device, &temp) == NVML_SUCCESS) {
*result.temp = temp.temperature;
2026-03-29 09:28:49 +08:00
}
2023-10-28 13:12:04 +08:00
}
2026-03-29 09:28:49 +08:00
if (result.memory) {
2026-03-30 10:27:23 +08:00
nvmlMemory_v2_t memory = { .version = nvmlMemory_v2 };
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetMemoryInfo_v2(device, &memory) == NVML_SUCCESS) {
2023-10-28 13:12:04 +08:00
result.memory->total = memory.used + memory.free;
result.memory->used = memory.used;
2026-03-29 09:28:49 +08:00
} else {
nvmlMemory_t memory_v1;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetMemoryInfo(device, &memory_v1) == NVML_SUCCESS) {
result.memory->total = memory_v1.total;
result.memory->used = memory_v1.used;
}
}
2023-10-28 13:12:04 +08:00
}
2026-03-29 09:28:49 +08:00
if (result.coreCount) {
2023-10-28 13:12:04 +08:00
nvmlData.ffnvmlDeviceGetNumGpuCores(device, result.coreCount);
2026-03-29 09:28:49 +08:00
}
2023-10-27 21:05:03 +08:00
2026-03-29 09:28:49 +08:00
if (result.frequency) {
2024-07-17 14:52:35 +08:00
nvmlData.ffnvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_GRAPHICS, result.frequency);
2026-03-29 09:28:49 +08:00
}
2026-03-29 09:28:49 +08:00
if (result.coreUsage) {
2024-08-01 13:54:03 +08:00
nvmlUtilization_t utilization;
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetUtilizationRates(device, &utilization) == NVML_SUCCESS) {
2024-08-01 13:54:03 +08:00
*result.coreUsage = utilization.gpu;
2026-03-29 09:28:49 +08:00
}
2024-07-31 23:40:25 +08:00
}
2026-03-29 09:28:49 +08:00
if (result.name) {
char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE];
2026-03-29 09:28:49 +08:00
if (nvmlData.ffnvmlDeviceGetName(device, name, ARRAY_SIZE(name)) == NVML_SUCCESS) {
ffStrbufSetS(result.name, name);
2026-03-29 09:28:49 +08:00
}
}
2026-06-14 17:36:54 +08:00
if (result.psMax) {
2026-06-13 15:20:40 +08:00
unsigned int value;
if (nvmlData.ffnvmlDeviceGetMaxPcieLinkGeneration(device, &value) == NVML_SUCCESS) {
2026-06-14 17:36:54 +08:00
result.psMax->gen = (uint16_t) value;
}
if (nvmlData.ffnvmlDeviceGetMaxPcieLinkWidth(device, &value) == NVML_SUCCESS) {
result.psMax->lanes = (uint16_t) value;
2026-06-13 15:20:40 +08:00
}
}
2026-06-14 17:36:54 +08:00
if (result.psCurr) {
2026-06-13 15:20:40 +08:00
unsigned int value;
2026-06-14 17:36:54 +08:00
if (nvmlData.ffnvmlDeviceGetCurrPcieLinkGeneration(device, &value) == NVML_SUCCESS) {
result.psCurr->gen = (uint16_t) value;
}
if (nvmlData.ffnvmlDeviceGetCurrPcieLinkWidth(device, &value) == NVML_SUCCESS) {
result.psCurr->lanes = (uint16_t) value;
2026-06-13 15:20:40 +08:00
}
}
2026-07-10 18:08:04 +08:00
return nullptr;
#else
FF_UNUSED(cond, result, soName);
return "dlopen is disabled";
#endif
2023-10-26 23:28:43 +08:00
}