Source code for mot.lib.cl_environments
import pyopencl as cl
from .utils import device_supports_double, device_type_from_string
__author__ = 'Robbert Harms'
__date__ = "2014-11-14"
__license__ = "LGPL v3"
__maintainer__ = "Robbert Harms"
__email__ = "robbert.harms@maastrichtuniversity.nl"
_context_cache = {}
[docs]class CLEnvironment:
def __init__(self, platform, device):
"""Storage unit for an OpenCL environment.
Args:
platform (pyopencl platform): An PyOpenCL platform.
device (pyopencl device): An PyOpenCL device
"""
self._platform = platform
self._device = device
if (self._platform, self._device) not in _context_cache:
context = cl.Context([device])
_context_cache[(self._platform, self._device)] = context
self._context = _context_cache[(self._platform, self._device)]
self._queue = cl.CommandQueue(self._context, device=device)
@property
def context(self):
"""Get a CL context containing this device.
Returns:
cl.Context: a PyOpenCL device context
"""
return self._context
@property
def queue(self):
"""Get a CL queue for this device and context.
Returns:
cl.Queue: a PyOpenCL queue
"""
return self._queue
@property
def supports_double(self):
"""Check if the device listed by this environment supports double
Returns:
boolean: True if the device supports double, false otherwise.
"""
return device_supports_double(self.device)
@property
def platform(self):
"""Get the platform associated with this environment.
Returns:
pyopencl platform: The platform associated with this environment.
"""
return self._platform
@property
def device(self):
"""Get the device associated with this environment.
Returns:
pyopencl device: The device associated with this environment.
"""
return self._device
@property
def is_gpu(self):
"""Check if the device associated with this environment is a GPU.
Returns:
boolean: True if the device is an GPU, false otherwise.
"""
return self._device.get_info(cl.device_info.TYPE) == cl.device_type.GPU
@property
def is_cpu(self):
"""Check if the device associated with this environment is a CPU.
Returns:
boolean: True if the device is an CPU, false otherwise.
"""
return self._device.get_info(cl.device_info.TYPE) == cl.device_type.CPU
@property
def device_type(self):
"""Get the device type of the device in this environment.
Returns:
the device type of this device.
"""
return self._device.get_info(cl.device_info.TYPE)
def __str__(self):
s = 'GPU' if self.is_gpu else 'CPU'
s += ' - ' + self.device.name + ' (' + self.platform.name + ')'
return s
def __repr__(self):
s = 75*"=" + "\n"
s += repr(self._platform) + "\n"
s += 75*"=" + "\n"
s += self._print_info(self._platform, cl.platform_info)
s += 75*"-" + "\n"
s += repr(self._device) + "\n"
s += 75*"-" + "\n"
s += self._print_info(self._device, cl.device_info)
return s
def _print_info(self, obj, info_cls):
s = ''
def format_title(title_str):
title_str = title_str.lower()
title_str = title_str.replace('_', ' ')
return title_str
for info_name in sorted(dir(info_cls)):
if not info_name.startswith("_") and info_name != "to_string":
info = getattr(info_cls, info_name)
try:
info_value = obj.get_info(info)
except cl.LogicError:
info_value = "<error>"
if info_cls == cl.device_info and info_name == "PARTITION_TYPES_EXT" and isinstance(info_value, list):
prop_value = [cl.device_partition_property_ext.to_string(v, "<unknown device "
"partition property %d>")
for v in info_value]
s += ("%s: %s" % (format_title(info_name), prop_value)) + "\n"
else:
try:
s += ("%s: %s" % (format_title(info_name), info_value)) + "\n"
except cl.LogicError:
s += ("%s: <error>" % info_name) + "\n"
s += "\n"
return s
def __eq__(self, other):
"""A device is equal to another if the platform and the device are equal."""
if isinstance(other, CLEnvironment):
return other.platform == self.platform and other.device == self.device
return False
[docs]class CLEnvironmentFactory:
[docs] @staticmethod
def single_device(cl_device_type='GPU', platform=None, fallback_to_any_device_type=False):
"""Get a list containing a single device environment, for a device of the given type on the given platform.
This will only fetch devices that support double (possibly only double with a pragma
defined, but still, it should support double).
Args:
cl_device_type (cl.device_type.* or string): The type of the device we want,
can be a opencl device type or a string matching 'GPU', 'CPU' or 'ALL'.
platform (opencl platform): The opencl platform to select the devices from
fallback_to_any_device_type (boolean): If True, try to fallback to any possible device in the system.
Returns:
list of CLEnvironment: List with one element, the CL runtime environment requested.
"""
if isinstance(cl_device_type, str):
cl_device_type = device_type_from_string(cl_device_type)
device = None
if platform is None:
platforms = cl.get_platforms()
else:
platforms = [platform]
for platform in platforms:
devices = platform.get_devices(device_type=cl_device_type)
for dev in devices:
if device_supports_double(dev):
try:
env = CLEnvironment(platform, dev)
return [env]
except cl.RuntimeError:
pass
if not device:
if fallback_to_any_device_type:
return cl.get_platforms()[0].get_devices()
else:
raise ValueError('No devices of the specified type ({}) found.'.format(
cl.device_type.to_string(cl_device_type)))
raise ValueError('No suitable OpenCL device found.')
[docs] @staticmethod
def all_devices(cl_device_type=None, platform=None):
"""Get multiple device environments, optionally only of the indicated type.
This will only fetch devices that support double point precision.
Args:
cl_device_type (cl.device_type.* or string): The type of the device we want,
can be a opencl device type or a string matching 'GPU' or 'CPU'.
platform (opencl platform): The opencl platform to select the devices from
Returns:
list of CLEnvironment: List with the CL device environments.
"""
if isinstance(cl_device_type, str):
cl_device_type = device_type_from_string(cl_device_type)
runtime_list = []
if platform is None:
platforms = cl.get_platforms()
else:
platforms = [platform]
for platform in platforms:
if cl_device_type:
devices = platform.get_devices(device_type=cl_device_type)
else:
devices = platform.get_devices()
for device in devices:
if device_supports_double(device):
env = CLEnvironment(platform, device)
runtime_list.append(env)
return runtime_list
[docs] @staticmethod
def smart_device_selection(preferred_device_type=None):
"""Get a list of device environments that is suitable for use in MOT.
Basically this gets the total list of devices using all_devices() and applies a filter on it.
This filter does the following:
1) if the 'AMD Accelerated Parallel Processing' is available remove all environments using the 'Clover'
platform.
More things may be implemented in the future.
Args:
preferred_device_type (str): the preferred device type, one of 'CPU', 'GPU' or 'APU'.
If no devices of this type can be found, we will use any other device available.
Returns:
list of CLEnvironment: List with the CL device environments.
"""
cl_environments = CLEnvironmentFactory.all_devices(cl_device_type=preferred_device_type)
platform_names = [env.platform.name for env in cl_environments]
has_amd_pro_platform = any('AMD Accelerated Parallel Processing' in name for name in platform_names)
if has_amd_pro_platform:
return list(filter(lambda env: 'Clover' not in env.platform.name, cl_environments))
if preferred_device_type is not None and not len(cl_environments):
return CLEnvironmentFactory.all_devices()
return cl_environments