diff --git a/src/main/java/com/sheepit/client/hardware/gpu/GPUDevice.java b/src/main/java/com/sheepit/client/hardware/gpu/GPUDevice.java index 53fe557..a94b176 100644 --- a/src/main/java/com/sheepit/client/hardware/gpu/GPUDevice.java +++ b/src/main/java/com/sheepit/client/hardware/gpu/GPUDevice.java @@ -28,6 +28,8 @@ public class GPUDevice { private String oldId; // for backward compatibility + private String driverVersion; + public GPUDevice(String type, String model, long ram, String id) { this.type = type; this.model = model; @@ -80,7 +82,34 @@ public class GPUDevice { this.oldId = id; } + public String getDriverVersion() { + return this.driverVersion; + } + + public void setDriverVersion(String driverVersion) { + this.driverVersion = driverVersion; + } + @Override public String toString() { - return "GPUDevice [type=" + type + ", model='" + model + "', memory=" + memory + ", id=" + id + "]"; + return "GPUDevice [type=" + type + ", model='" + model + "', memory=" + memory + ", id=" + id + ", driverVersion=" + driverVersion + "]"; + } + + public static int compareVersions(String version1, String version2) { + int comparisonResult = 0; + + String[] version1Splits = version1.split("\\."); + String[] version2Splits = version2.split("\\."); + int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length); + + for (int i = 0; i < maxLengthOfVersionSplits; i++){ + Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0; + Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0; + int compare = v1.compareTo(v2); + if (compare != 0) { + comparisonResult = compare; + break; + } + } + return comparisonResult; } } diff --git a/src/main/java/com/sheepit/client/hardware/gpu/hip/HIP.java b/src/main/java/com/sheepit/client/hardware/gpu/hip/HIP.java index 629a808..42068ff 100644 --- a/src/main/java/com/sheepit/client/hardware/gpu/hip/HIP.java +++ b/src/main/java/com/sheepit/client/hardware/gpu/hip/HIP.java @@ -187,7 +187,7 @@ public class HIP implements GPULister { return null; } - boolean driverTooOld = compareVersions(driverVersion, MINIMAL_WINDOWS_DRIVER_VERSION) < 0; + boolean driverTooOld = GPUDevice.compareVersions(driverVersion, MINIMAL_WINDOWS_DRIVER_VERSION) < 0; if (driverTooOld) { System.out.println("HIP::getGpus AMD driver too old"); @@ -207,29 +207,11 @@ public class HIP implements GPULister { String deviceIdentifier = getIdentifier(i); String oldID = TYPE + "_" + numberedID; GPUDevice device = new GPUDevice(TYPE, deviceName, vram, deviceIdentifier, oldID); + device.setDriverVersion(driverVersion); gpuDevices.add(device); numberedID++; } return gpuDevices; } - - private int compareVersions(String version1, String version2) { - int comparisonResult = 0; - - String[] version1Splits = version1.split("\\."); - String[] version2Splits = version2.split("\\."); - int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length); - - for (int i = 0; i < maxLengthOfVersionSplits; i++){ - Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0; - Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0; - int compare = v1.compareTo(v2); - if (compare != 0) { - comparisonResult = compare; - break; - } - } - return comparisonResult; - } } diff --git a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/CUDA.java b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/CUDA.java index 38129f1..e3062a4 100644 --- a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/CUDA.java +++ b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/CUDA.java @@ -25,20 +25,23 @@ import com.sun.jna.ptr.LongByReference; public interface CUDA extends Library { public int cuInit(int flags); - + /* * @return: CUDA_SUCCESS, CUDA_ERROR_DEINITIALIZED, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT, CUDA_ERROR_INVALID_VALUE */ public int cuDeviceGetCount(IntByReference count); - + public int cuDeviceGetName(byte[] name, int len, int dev); - + public int cuDeviceGet(IntByReference device, int ordinal); - + public int cuDeviceGetAttribute(IntByReference pi, int attrib, int dev); - + public int cuDeviceTotalMem_v2(LongByReference bytes, int dev); - + public int cuDeviceTotalMem(LongByReference bytes, int dev); + public int cudaRuntimeGetVersion(IntByReference version); + public int cudaDriverGetVersion(IntByReference version); + } diff --git a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVML.java b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVML.java new file mode 100644 index 0000000..0075c64 --- /dev/null +++ b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVML.java @@ -0,0 +1,14 @@ +package com.sheepit.client.hardware.gpu.nvidia; + +import com.sun.jna.Library; +import com.sun.jna.ptr.IntByReference; + +//https://docs.nvidia.com/deploy/nvml-api/group__nvmlSystemQueries.html#group__nvmlSystemQueries + +public interface NVML extends Library { + + public int nvmlInit_v2(); + public int nvmlShutdown (); + public int nvmlSystemGetDriverVersion(byte[] version, int length); + +} diff --git a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVMLResult.java b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVMLResult.java new file mode 100644 index 0000000..a789f88 --- /dev/null +++ b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/NVMLResult.java @@ -0,0 +1,9 @@ +package com.sheepit.client.hardware.gpu.nvidia; + +//https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceEnumvs.html +public class NVMLResult { + public static final int NVML_SUCCESS = 0; + public static final int NVML_ERROR_UNITIALIZED = 1; //NVML was not initialized with nvmlInit() + public static final int NVML_ERROR_INVALID_ARGUMENT = 2; + public static final int NVML_ERROR_INSUFFICIENT_SIZE = 7; +} diff --git a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/Nvidia.java b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/Nvidia.java index e6866e1..fce6ce1 100644 --- a/src/main/java/com/sheepit/client/hardware/gpu/nvidia/Nvidia.java +++ b/src/main/java/com/sheepit/client/hardware/gpu/nvidia/Nvidia.java @@ -6,6 +6,7 @@ import java.util.List; import com.sheepit.client.hardware.gpu.GPUDevice; import com.sheepit.client.hardware.gpu.GPULister; import com.sheepit.client.os.OS; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; @@ -13,6 +14,9 @@ import com.sun.jna.ptr.LongByReference; public class Nvidia implements GPULister { public static String TYPE = "OPTIX"; + //https://docs.blender.org/manual/en/3.3/render/cycles/gpu_rendering.html#optix-nvidia + private static final String MINIMUM_DRIVER_VERSION = "470"; + @Override public List getGpus() { OS os = OS.getOS(); String path = os.getCUDALib(); @@ -127,9 +131,44 @@ public class Nvidia implements GPULister { return null; } + NVML nvml = null; + try { + nvml = Native.load(os.getNVMLLib(), NVML.class); + } + catch (UnsatisfiedLinkError e) { + System.out.println("Nvidia::getGpus failed to load NVML library"); + return null; + } + + result = nvml.nvmlInit_v2(); + if (result != NVMLResult.NVML_SUCCESS) { + System.out.println("Nvidia::getGpus failed to nvmlInit failed. Returned " + result); + return null; + } + + short stringLength = 80; + byte[] driverStringBuffer = new byte[stringLength]; + result = nvml.nvmlSystemGetDriverVersion(driverStringBuffer, stringLength); //The returned char* will never exceed 80 characters according to the docs + + if (result != NVMLResult.NVML_SUCCESS) { + System.out.println("Nvidia::getGpus failed to retrieve driver version"); + nvml.nvmlShutdown(); + return null; + } + + nvml.nvmlShutdown(); + + String driverVersion = new String(driverStringBuffer); + boolean driverTooOld = GPUDevice.compareVersions(driverVersion, MINIMUM_DRIVER_VERSION) < 0; + if (driverTooOld) { + System.out.println("Nvidia::getGpus driver version too old: " + driverVersion); + return null; + } + String blenderId = String .format("CUDA_%s_%04x:%02x:%02x_OptiX", new String(name).trim(), pciDomainId.getValue(), pciBusId.getValue(), pciDeviceId.getValue()); GPUDevice gpu = new GPUDevice(TYPE, new String(name).trim(), ram.getValue(), blenderId); + gpu.setDriverVersion(driverVersion); // for backward compatibility generate a CUDA_N id gpu.setOldId(TYPE + "_" + num); devices.add(gpu); diff --git a/src/main/java/com/sheepit/client/os/Linux.java b/src/main/java/com/sheepit/client/os/Linux.java index d8dc433..7a165b2 100644 --- a/src/main/java/com/sheepit/client/os/Linux.java +++ b/src/main/java/com/sheepit/client/os/Linux.java @@ -49,6 +49,10 @@ public class Linux extends OS { return "cuda"; } + @Override public String getNVMLLib() { + return "nvidia-ml"; + } + @Override public Process exec(List command, Map env_overight) throws IOException { Map new_env = new HashMap(); new_env.putAll(java.lang.System.getenv()); // clone the env diff --git a/src/main/java/com/sheepit/client/os/OS.java b/src/main/java/com/sheepit/client/os/OS.java index d0eed93..2a4a4bf 100644 --- a/src/main/java/com/sheepit/client/os/OS.java +++ b/src/main/java/com/sheepit/client/os/OS.java @@ -63,6 +63,11 @@ public abstract class OS { return null; } + //path to NVIDIA NVML lib + public String getNVMLLib() { + return null; + } + public abstract boolean getSupportHighPriority(); public abstract boolean checkNiceAvailability(); diff --git a/src/main/java/com/sheepit/client/os/Windows.java b/src/main/java/com/sheepit/client/os/Windows.java index c75908c..71ab8ce 100644 --- a/src/main/java/com/sheepit/client/os/Windows.java +++ b/src/main/java/com/sheepit/client/os/Windows.java @@ -42,6 +42,9 @@ public class Windows extends OS { @Override public String getCUDALib() { return "nvcuda"; } + @Override public String getNVMLLib() { + return "nvml"; + } @Override public Process exec(List command, Map env) throws IOException { // disable a popup because the renderer might crash (seg fault)