# How to choose the OpenCL device to use?

OpenCLInformation tells me that my computer has three available OpenCL devices. How can I choose which one to use for computations? How can I verify that Mathematica is honouring this choice?

The rest of this post is about how I tried to do this and failed:

Here's what SystemInformation[] (as well as OpenCLInformation[]) gives me:

(I am using OS X 10.9.1)

I tried to control the device using $OpenCLDevice, like this: Load OpenCLLink: In[1]:= Needs["OpenCLLink"]  Check what device it would use: In[2]:= {$OpenCLPlatform, $OpenCLDevice} Out[2]= {Automatic, Automatic}  According to the docs, • Set to Automatic, the OpenCL computation is performed on the fastest device. • Changes to $OpenCLDevice performed after execution of an OpenCLLink function are ignored.
• If modified, then $OpenCLPlatform must be changed also. So as I understand, I must set both of these variables, and I must set them before running any computations. Let's do it now: In[3]:=$OpenCLPlatform = 1;
$OpenCLDevice = 2; In[5]:= {$OpenCLPlatform, $OpenCLDevice} Out[5]= {1, 2}  Now let's try a simple computation borrowed from the documentation: In[6]:= doubleFun = OpenCLFunctionLoad[" __kernel void doubleVec(__global mint * in, mint length) { int index = get_global_id(0); if (index < length) in[index] = 2*in[index]; }", "doubleVec", {{_Integer}, _Integer}, 256] Out[6]= OpenCLFunction["<>", "doubleVec", {{_Integer}, "Integer64"}] In[7]:= doubleFun[Range[20], 20] Out[7]= {{2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}}  It did work, but I wonder which device was used ... In[8]:=$OpenCLDevice
Out[8]= 3


It appears it was device 3, not device 2, which I wanted to use. How can I force the system to use device 2, which is supposed to be faster than device 3?

Device 2 on my machine is an NVIDIA GPU and it works correctly with CUDALink. The documentation says that if a device works with CUDALink, it should also work with OpenCLLink.

-
After spending a considerable time trying to figure this out, and failing, I found something right after posting this ... OpenCLFunctionLoad has "Platform" and "Device" options which are supposed to have values $OpenCLPlatform and $OpenCLDevice according to the docs. But in reality both have default value Automatic. Specifying these options explicitly does seem to work, but I am not yet 100% convinced that Mathematica is really using the selected devices. Now I'd like to be able to verify that it does indeed use the chosen device. –  Szabolcs Dec 20 '13 at 17:13

tl;dr To select platform 1, device 2 for all OpenCL calculations, load OpenCLLink like this:

Needs["OpenCLLink"]
OpenCLMersenneTwister[1, "Platform" -> 1, "Device" -> 2] (* first call any OpenCL function with the device you need *)


This will use the same choice of platform and device in all subsequent computations without having to specify it again.

I think I found a useful workaround. The problem is a very real and practical one on my computer because several of the example applications, such as OpenCLFractalRender3D, simply did not work with the device selected by default (integrated graphics) on my machine.

OpenCLFunctionLoad has two options "Device" and "Platform". The documentation claims that the default settings for these are $OpenCLDevice and $OpenCLPlatform but in reality the settings are Automatic. All other OpenCL-related functions have these options as well.

The workaround is to call some OpenCL function, specifying the correct device, right after loading OpenCLLink. For example,

Needs["OpenCLLink"]
OpenCLMersenneTwister[1, "Platform" -> 1, "Device" -> 2]


From now on, the device will be "stuck" on device 2 (as documented), no matter what device I specify in subsequent calls. This means that all subsequent calls to OpenCL functions will just use device 2, and I do not need to specify the device any more.

On my machine the only device which supports all included OpenCLLink examples is the discrete GPU. The integrated GPU only supports some, and the CPU device even fewer. Thus it was very important to be able to select the discrete GPU as the computation device.

-

Just a little additional information -

I find it slightly interesting in my particular case that "Automatic" doesn't really select the "best" device but rather the first one it finds that isn't the CPU.

If you browse the WGLPrivate.m package in GPUTools (this is the 'core' that the CUDA and OpenCL interfaces) there is some voodoo in InitializeWGL that does the device setting (making a call out to a WRI routine "cSetDevice", same for Platform). The decision over which to use is apparently carried out in there since a setting of "Automatic" causes -1 to be passed to the library command.

Moreso, the beginning of OpenCL.m gives us

If[$OpenCLPlatform === Unevaluated[$OpenCLPlatform],
$OpenCLPlatform = Automatic,$WGLPlatform = \$OpenCLPlatform]
`

which sets up the WGL experience. This happens when OpenCL.m gets executed initially, so the only hope here would seem to be to set it before it loads. Trying this, however, still results in the Platform and Device reverting to the default at runtime (unless you force the issue on the first call to the library, as shown above).

I will debug through the WGL stuff a little further to see if I can divine some cause and effect.

-