8
$\begingroup$

I am trying to submit a render job via slurm on our cluster with blender 2.8, that is, completely command-line based with no way to start the GUI on the computing nodes.

I have assigned 38 CPU to the task (so that the resources are assigned on a single machine) and plenty of RAM. Unfortunately, Blender uses only about 5 CPUs and the whole thing is disappointingly slow, with 5s/frame. (We are not only rendering the scene but are especially saving the motion vectors and depth map, which seems to take it's time). On a local machine with 2 Geforce 1080 Ti, I got it running with 1.5s/frame.

We also have nodes with 20 CPUs and 2 Geforce 2080 Ti each. How do I configure CUDA on such a job?

$\endgroup$
3
  • $\begingroup$ The following answer should help, you will need to include the CPUs though (get rid of the if statement that excludes CPUs) and enable GPU rendering as well (as shown in the add-on). blender.stackexchange.com/questions/154510/… $\endgroup$ Commented Oct 26, 2019 at 14:22
  • $\begingroup$ Thanks, I seem to have gotten it running by copying the enable_gpu function and calling it with "CUDA", then pass the script with -P. Do you want to make that an answer so I can mark it as a solution? I have not enables CPUs yet, because during initial, local tests with the GUI, having CPUs and GPUs ticked for CUDA led to GPUs not be utilized. No time to check further now, the new gpu job array will get the job done in time $\endgroup$
    – mcandril
    Commented Oct 27, 2019 at 9:36
  • $\begingroup$ I'm currently at the Blender Conference in Amsterdam. I'll add an answer within the next days when I'm back home. $\endgroup$ Commented Oct 27, 2019 at 10:35

3 Answers 3

13
$\begingroup$

The following script allows you to enable all GPUs and optionally all CPUs as well.

import bpy


def enable_gpus(device_type, use_cpus=False):
    preferences = bpy.context.preferences
    cycles_preferences = preferences.addons["cycles"].preferences
    cuda_devices, opencl_devices = cycles_preferences.get_devices()

    if device_type == "CUDA":
        devices = cuda_devices
    elif device_type == "OPENCL":
        devices = opencl_devices
    else:
        raise RuntimeError("Unsupported device type")

    activated_gpus = []

    for device in devices:
        if device.type == "CPU":
            device.use = use_cpus
        else:
            device.use = True
            activated_gpus.append(device.name)

    cycles_preferences.compute_device_type = device_type
    bpy.context.scene.cycles.device = "GPU"

    return activated_gpus


enable_gpus("CUDA")

The script can be called from the command line by starting Blender with the -Por --python flag followed by the path and name of the script.

$\endgroup$
3
  • 1
    $\begingroup$ Thanks again! Marked as solution. $\endgroup$
    – mcandril
    Commented Oct 29, 2019 at 10:21
  • $\begingroup$ Unfortunately this doesn't really work with the more recent blender versions (tested with 4.1.1). On the other hand Rafa_br34's script (in their answer) works like a charm! $\endgroup$
    – Entrusc
    Commented 2 days ago
  • $\begingroup$ @Entrusc Yeah, sorry about that. I haven't updated the script since the answer was originally posted. $\endgroup$ Commented 22 hours ago
5
$\begingroup$

After updating to Blender 3.1.0 the script that Robert posted stopped working for me and threw the error IndexError: bpy_prop_collection[index]: index 0 out of range, size 0 after this line cuda_devices = cycles_preferences.devices[0]

This answer helped fix the error Rendering on command-line with GPU?

It seems that cycles_preferences.get_devices() has been deprecated.

Here's my current working script

import bpy

def enable_gpus(device_type, use_cpus=False):
    preferences = bpy.context.preferences
    cycles_preferences = preferences.addons["cycles"].preferences
    cycles_preferences.refresh_devices()
    devices = cycles_preferences.devices

    if not devices:
        raise RuntimeError("Unsupported device type")

    activated_gpus = []
    for device in devices:
        if device.type == "CPU":
            device.use = use_cpus
        else:
            device.use = True
            activated_gpus.append(device.name)
            print('activated gpu', device.name)

    cycles_preferences.compute_device_type = device_type
    bpy.context.scene.cycles.device = "GPU"

    return activated_gpus


enable_gpus("CUDA")

$\endgroup$
2
  • $\begingroup$ Worked on 3.2, thank you! $\endgroup$
    – ofekp
    Commented Nov 14, 2022 at 1:59
  • $\begingroup$ Can confirm this also works on Blender LTS 3.6. Thank you for this valuable contribution! $\endgroup$
    – Ivo Filot
    Commented Dec 26, 2023 at 9:42
1
$\begingroup$

Based on Josh's answer I have written this which allows the user to select what devices to use interactively.

import cycles
import bpy
import sys

# blender -b file.blend -o output_folder/frame_ -P Devices.py

preferences = bpy.context.preferences
cycles_preferences = preferences.addons["cycles"].preferences
cycles_preferences.refresh_devices()

devices = cycles_preferences.devices

def list_enum(enum):
    return [opt[0] for opt in enum]


def print_devices():
    print("Devices:")
    for device in devices:
        print(f"   [{device.id}]<{device.type}> \"{device.name}\" Using: {device.use}")

    print(f"Compute device type: {cycles_preferences.compute_device_type}")
    print(f"Cycles device: {bpy.context.scene.cycles.device}")


def select_devices():
    if not devices:
        raise RuntimeError("Unsupported device type")

    for device in devices:
        if "y" in input(f"[{device.id}]<{device.type}> \"{device.name}\" Use device? (y/N): ").lower():
            device.use = True
        else:
            device.use = False

    
    cycles_preferences.compute_device_type = input(f"Select the preferred compute device [{', '.join(list_enum(cycles.properties.enum_device_type))}]: ").upper()
    bpy.context.scene.cycles.device = input(f"Select the compute device type [{', '.join(list_enum(cycles.properties.enum_devices))}]: ").upper()


def main():
    assert sys.stdin, "sys.stdin should be available (is the script running using the --python/-P argument?)"

    select_devices()
    print_devices()


if __name__ == "__main__":
    main()

And here's the gist.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .