Pono
Pono

Reputation: 11776

How to pick the right Metal Device for GPU processing on a Mac Pro

When creating a new CIContext with Metal device one has to provide which device (a GPU) to use:

let context = CIContext(
    mtlDevice: device
)

On my MacBook Pro for the development purposes I always pick the device associated with the screen with MTLCreateSystemDefaultDevice() method:

guard
    let device:MTLDevice = MTLCreateSystemDefaultDevice()
else {
    exit(EXIT_FAILURE)
}

However on a Mac Pro which will be used in production in a headless mode there are two GPU cards that I can target. In order to get all available devices one can use MTLCopyAllDevices() method which gives the following output on my Mac Pro:

[
    <MTLDebugDevice: 0x103305450> -> <BronzeMtlDevice: 0x10480a200>
    name = AMD Radeon HD - FirePro D700

    <MTLDebugDevice: 0x103307730> -> <BronzeMtlDevice: 0x104814800>
    name = AMD Radeon HD - FirePro D700
]

This Mac Pro will be utilised heavily with hundreds of small tasks per second and every time the new task comes in I need to select a GPU device on which the task will be processed.

Now the question is - is picking a random device from the above array a good idea:

let devices = MTLCopyAllDevices() // get all available devices
let rand = Int(arc4random_uniform(UInt32(devices.count))) // random index
let device = devices[rand] // randomly selected GPU to use

let context = CIContext(
    mtlDevice: device
)

Since there are two equal GPU devices on a Mac Pro, targeting always one will be a waste of resources. Logic tells me that with the above code both GPUs will be utilised equally but maybe I'm wrong and MacOS offer some kind of abstraction layer that will intelligently pick the GPU which is less utilised at the time of execution?

Thank you in advance.

Upvotes: 2

Views: 855

Answers (1)

warrenm
warrenm

Reputation: 31782

Why not just alternate between them? Even if you're committing command buffers from multiple threads, the work should be spread roughly evenly:

device = devices[taskIndex % devices.count]

Also, make sure to avoid creating CIContexts for every operation; those are expensive, so you should keep a list of contexts (one per device) instead.

Note that if you're doing any of your own Metal work (as opposed to just Core Image filtering), you'll need to have a command queue for each device, and any resources you want to use will need to be allocated by their respective device (resources can't be shared by MTLDevices).

Upvotes: 1

Related Questions