Skip to content

Commit 6bd3d2c

Browse files
committed
GPU (Linux): greatly improve detection for AMD cards
Completely untested
1 parent 29644ef commit 6bd3d2c

File tree

1 file changed

+87
-71
lines changed

1 file changed

+87
-71
lines changed

src/detection/gpu/gpu_linux.c

Lines changed: 87 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,6 @@
1515

1616
#include <inttypes.h>
1717

18-
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, uint32_t deviceClass)
19-
{
20-
const FFlist* tempsResult = ffDetectTemps();
21-
22-
FF_LIST_FOR_EACH(FFTempValue, tempValue, *tempsResult)
23-
{
24-
// https://www.kernel.org/doc/html/v5.10/gpu/amdgpu.html#hwmon-interfaces
25-
// FIXME: this code doesn't take multiGPUs into count
26-
// The kernel exposes the device class multiplied by 256 for some reason
27-
if(tempValue->deviceClass == deviceClass * 256)
28-
{
29-
gpu->temperature = tempValue->value;
30-
return;
31-
}
32-
}
33-
}
34-
3518
static void pciDetectDriver(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
3619
{
3720
ffStrbufAppendS(pciDir, "/driver");
@@ -56,33 +39,59 @@ static void pciDetectDriver(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer
5639
}
5740
}
5841

59-
static void pciDetectVmem(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
42+
static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
6043
{
61-
// Works for AMD GPUs
6244
// https://www.kernel.org/doc/html/v5.10/gpu/amdgpu.html#mem-info-vis-vram-total
63-
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
64-
uint64_t size = 0;
65-
if (ffReadFileBuffer(pciDir->chars, buffer) && (size = ffStrbufToUInt(buffer, 0)))
45+
const uint32_t pciDirLen = pciDir->length;
46+
47+
ffStrbufAppendS(pciDir, "/hwmon/");
48+
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
49+
struct dirent* entry = readdir(dirp);
50+
if (!entry) return;
51+
ffStrbufAppendS(pciDir, entry->d_name);
52+
ffStrbufAppendC(pciDir, '/');
53+
54+
const uint32_t hwmonLen = pciDir->length;
55+
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
56+
if (ffPathExists(pciDir->chars, FF_PATHTYPE_FILE))
57+
gpu->type = FF_GPU_TYPE_INTEGRATED;
58+
else
59+
gpu->type = FF_GPU_TYPE_DISCRETE;
60+
61+
uint64_t value = 0;
62+
if (options->temp)
63+
{
64+
ffStrbufSubstrBefore(pciDir, hwmonLen);
65+
ffStrbufAppendS(pciDir, "temp1_input"); // The on die GPU temperature in millidegrees Celsius
66+
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
67+
gpu->frequency = (double) value / 1000;
68+
}
69+
70+
ffStrbufSubstrBefore(pciDir, hwmonLen);
71+
ffStrbufAppendS(pciDir, "freq1_input"); // The gfx/compute clock in hertz
72+
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
73+
gpu->frequency = (double) value / (1000 * 1000 * 1000);
74+
75+
if (options->driverSpecific)
6676
{
67-
gpu->type = size > 1024UL * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
68-
if (gpu->type == FF_GPU_TYPE_DISCRETE)
69-
gpu->dedicated.total = size;
70-
else
71-
gpu->shared.total = size;
72-
73-
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
74-
ffStrbufAppendS(pciDir, "/mem_info_vram_used");
75-
if (ffReadFileBuffer(pciDir->chars, buffer) && (size = ffStrbufToUInt(buffer, 0)))
77+
ffStrbufSubstrBefore(pciDir, pciDirLen);
78+
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
79+
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
7680
{
77-
if (gpu->type == FF_GPU_TYPE_DISCRETE)
78-
gpu->dedicated.used = size;
79-
else
80-
gpu->shared.used = size;
81+
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
82+
ffStrbufAppendS(pciDir, "/mem_info_vram_used");
83+
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
84+
{
85+
if (gpu->type == FF_GPU_TYPE_DISCRETE)
86+
gpu->dedicated.used = value;
87+
else
88+
gpu->shared.used = value;
89+
}
8190
}
8291
}
8392
}
8493

85-
static void pciDetectVfreq(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
94+
static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
8695
{
8796
if (!ffStrbufEndsWithS(pciDir, "/device")) // Must be in `/sys/class/drm/cardN/device`
8897
return;
@@ -98,6 +107,10 @@ static void pciDetectVfreq(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
98107
str[len] = '\0';
99108
gpu->frequency = (double) strtoul(str, NULL, 10) / 1000.0;
100109
}
110+
111+
if (ffStrbufStartsWithS(&gpu->name, "Intel "))
112+
ffStrbufSubstrAfter(&gpu->name, (uint32_t) strlen("Intel "));
113+
gpu->type = ffStrbufStartsWithIgnCaseS(&gpu->name, "Arc ") ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
101114
}
102115

103116
static bool loadPciIds(FFstrbuf* pciids)
@@ -186,47 +199,50 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
186199
ffGPUParsePciIds(&pciids, subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
187200
}
188201

189-
// Temporarily disabled for now #816
190-
if (false)
191-
{
192-
pciDetectVmem(gpu, drmDir, buffer);
193-
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
194-
}
195-
196-
pciDetectVfreq(gpu, drmDir, buffer);
197-
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
198-
199202
pciDetectDriver(gpu, drmDir, buffer);
200203
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
201204

202-
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
203-
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
205+
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
204206
{
205-
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
206-
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
207-
.pciBusId = {
208-
.domain = pciDomain,
209-
.bus = pciBus,
210-
.device = pciDevice,
211-
.func = pciFunc,
212-
},
213-
}, (FFGpuDriverResult) {
214-
.temp = options->temp ? &gpu->temperature : NULL,
215-
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
216-
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
217-
.type = &gpu->type,
218-
.frequency = &gpu->frequency,
219-
}, "libnvidia-ml.so");
220-
221-
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
222-
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
207+
pciDetectAmdSpecific(options, gpu, drmDir, buffer);
208+
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
223209
}
224-
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
210+
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
211+
{
212+
pciDetectIntelSpecific(gpu, drmDir, buffer);
213+
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
214+
}
215+
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
216+
{
217+
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
218+
if (options->temp || options->driverSpecific)
219+
{
220+
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
221+
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
222+
.pciBusId = {
223+
.domain = pciDomain,
224+
.bus = pciBus,
225+
.device = pciDevice,
226+
.func = pciFunc,
227+
},
228+
}, (FFGpuDriverResult) {
229+
.temp = options->temp ? &gpu->temperature : NULL,
230+
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
231+
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
232+
.type = &gpu->type,
233+
.frequency = &gpu->frequency,
234+
}, "libnvidia-ml.so");
235+
}
236+
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
225237

226-
#ifdef __linux__
227-
if(options->temp && gpu->temperature != gpu->temperature)
228-
pciDetectTemp(gpu, ((uint32_t) classId << 8) + subclassId);
229-
#endif
238+
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
239+
{
240+
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
241+
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
242+
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
243+
gpu->type = FF_GPU_TYPE_DISCRETE;
244+
}
245+
}
230246

231247
return NULL;
232248
}

0 commit comments

Comments
 (0)