core/ocl: temporary move device selection from ocl module

This commit is contained in:
Alexander Alekhin
2013-12-25 14:39:21 +04:00
parent 0966e5ffa1
commit e49065b1dc
8 changed files with 443 additions and 13 deletions

View File

@@ -210,6 +210,7 @@ public:
Context2(const Context2& c);
Context2& operator = (const Context2& c);
bool create();
bool create(int dtype);
size_t ndevices() const;
const Device& device(size_t idx) const;

View File

@@ -41,6 +41,9 @@
#include "precomp.hpp"
#include <map>
#include <string>
#include <sstream>
#include <iostream> // std::cerr
#include "opencv2/core/opencl/runtime/opencl_clamdblas.hpp"
#include "opencv2/core/opencl/runtime/opencl_clamdfft.hpp"
@@ -1905,6 +1908,232 @@ const Device& Device::getDefault()
/////////////////////////////////////////////////////////////////////////////////////////
template <typename Functor, typename ObjectType>
inline cl_int getStringInfo(Functor f, ObjectType obj, cl_uint name, std::string& param)
{
::size_t required;
cl_int err = f(obj, name, 0, NULL, &required);
if (err != CL_SUCCESS)
return err;
param.clear();
if (required > 0)
{
std::vector<char> buf(required + 1, char(0));
err = f(obj, name, required, &buf[0], NULL);
if (err != CL_SUCCESS)
return err;
param = &buf[0];
}
return CL_SUCCESS;
};
static void split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
}
static std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
// Layout: <Platform>:<CPU|GPU|ACCELERATOR|nothing=GPU/CPU>:<deviceName>
// Sample: AMD:GPU:
// Sample: AMD:GPU:Tahiti
// Sample: :GPU|CPU: = '' = ':' = '::'
static bool parseOpenCLDeviceConfiguration(const std::string& configurationStr,
std::string& platform, std::vector<std::string>& deviceTypes, std::string& deviceNameOrID)
{
std::string deviceTypesStr;
size_t p0 = configurationStr.find(':');
if (p0 != std::string::npos)
{
size_t p1 = configurationStr.find(':', p0 + 1);
if (p1 != std::string::npos)
{
size_t p2 = configurationStr.find(':', p1 + 1);
if (p2 != std::string::npos)
{
std::cerr << "ERROR: Invalid configuration string for OpenCL device" << std::endl;
return false;
}
else
{
// assume platform + device types + device name/id
platform = configurationStr.substr(0, p0);
deviceTypesStr = configurationStr.substr(p0 + 1, p1 - (p0 + 1));
deviceNameOrID = configurationStr.substr(p1 + 1, configurationStr.length() - (p1 + 1));
}
}
else
{
// assume platform + device types
platform = configurationStr.substr(0, p0);
deviceTypesStr = configurationStr.substr(p0 + 1, configurationStr.length() - (p0 + 1));
}
}
else
{
// assume only platform
platform = configurationStr;
}
deviceTypes = split(deviceTypesStr, '|');
return true;
}
static cl_device_id selectOpenCLDevice()
{
std::string platform;
std::vector<std::string> deviceTypes;
std::string deviceName;
const char* configuration = getenv("OPENCV_OPENCL_DEVICE");
if (configuration)
{
if (!parseOpenCLDeviceConfiguration(std::string(configuration), platform, deviceTypes, deviceName))
return NULL;
}
bool isID = false;
int deviceID = -1;
if (deviceName.length() == 1)
// We limit ID range to 0..9, because we want to write:
// - '2500' to mean i5-2500
// - '8350' to mean AMD FX-8350
// - '650' to mean GeForce 650
// To extend ID range change condition to '> 0'
{
isID = true;
for (size_t i = 0; i < deviceName.length(); i++)
{
if (!isdigit(deviceName[i]))
{
isID = false;
break;
}
}
if (isID)
{
deviceID = atoi(deviceName.c_str());
CV_Assert(deviceID >= 0);
}
}
std::vector<cl_platform_id> platforms;
cl_uint numPlatforms = 0;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
CV_Assert(status == CL_SUCCESS);
if (numPlatforms == 0)
return NULL;
platforms.resize((size_t)numPlatforms);
status = clGetPlatformIDs(numPlatforms, &platforms[0], &numPlatforms);
CV_Assert(status == CL_SUCCESS);
int selectedPlatform = -1;
if (platform.length() > 0)
{
for (size_t i = 0; i < platforms.size(); i++)
{
std::string name;
status = getStringInfo(clGetPlatformInfo, platforms[i], CL_PLATFORM_NAME, name);
CV_Assert(status == CL_SUCCESS);
if (name.find(platform) != std::string::npos)
{
selectedPlatform = (int)i;
break;
}
}
if (selectedPlatform == -1)
{
std::cerr << "ERROR: Can't find OpenCL platform by name: " << platform << std::endl;
goto not_found;
}
}
if (deviceTypes.size() == 0)
{
if (!isID)
{
deviceTypes.push_back("GPU");
deviceTypes.push_back("CPU");
}
else
{
deviceTypes.push_back("ALL");
}
}
for (size_t t = 0; t < deviceTypes.size(); t++)
{
int deviceType = 0;
if (deviceTypes[t] == "GPU")
{
deviceType = Device::TYPE_GPU;
}
else if (deviceTypes[t] == "CPU")
{
deviceType = Device::TYPE_CPU;
}
else if (deviceTypes[t] == "ACCELERATOR")
{
deviceType = Device::TYPE_ACCELERATOR;
}
else if (deviceTypes[t] == "ALL")
{
deviceType = Device::TYPE_ALL;
}
else
{
std::cerr << "ERROR: Unsupported device type for OpenCL device (GPU, CPU, ACCELERATOR): " << deviceTypes[t] << std::endl;
goto not_found;
}
std::vector<cl_device_id> devices; // TODO Use clReleaseDevice to cleanup
for (int i = selectedPlatform >= 0 ? selectedPlatform : 0;
(selectedPlatform >= 0 ? i == selectedPlatform : true) && (i < (int)platforms.size());
i++)
{
cl_uint count = 0;
status = clGetDeviceIDs(platforms[i], deviceType, 0, NULL, &count);
CV_Assert(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND);
if (count == 0)
continue;
size_t base = devices.size();
devices.resize(base + count);
status = clGetDeviceIDs(platforms[i], deviceType, count, &devices[base], &count);
CV_Assert(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND);
}
for (size_t i = (isID ? deviceID : 0);
(isID ? (i == (size_t)deviceID) : true) && (i < devices.size());
i++)
{
std::string name;
status = getStringInfo(clGetDeviceInfo, devices[i], CL_DEVICE_NAME, name);
CV_Assert(status == CL_SUCCESS);
if (isID || name.find(deviceName) != std::string::npos)
{
// TODO check for OpenCL 1.1
return devices[i];
}
}
}
not_found:
std::cerr << "ERROR: Required OpenCL device not found, check configuration: " << (configuration == NULL ? "" : configuration) << std::endl
<< " Platform: " << (platform.length() == 0 ? "any" : platform) << std::endl
<< " Device types: ";
for (size_t t = 0; t < deviceTypes.size(); t++)
{
std::cerr << deviceTypes[t] << " ";
}
std::cerr << std::endl << " Device name: " << (deviceName.length() == 0 ? "any" : deviceName) << std::endl;
return NULL;
}
struct Context2::Impl
{
Impl()
@@ -1913,6 +2142,42 @@ struct Context2::Impl
handle = 0;
}
void setDefault()
{
CV_Assert(handle == NULL);
cl_device_id d = selectOpenCLDevice();
if (d == NULL)
return;
cl_platform_id pl = NULL;
cl_int status = clGetDeviceInfo(d, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &pl, NULL);
CV_Assert(status == CL_SUCCESS);
cl_context_properties prop[] =
{
CL_CONTEXT_PLATFORM, (cl_context_properties)pl,
0
};
// !!! in the current implementation force the number of devices to 1 !!!
int nd = 1;
handle = clCreateContext(prop, nd, &d, 0, 0, &status);
CV_Assert(status == CL_SUCCESS);
bool ok = handle != 0 && status >= 0;
if( ok )
{
devices.resize(nd);
devices[0].set(d);
}
else
{
handle = NULL;
}
}
Impl(int dtype0)
{
refcount = 1;
@@ -2022,6 +2287,21 @@ Context2::Context2(int dtype)
create(dtype);
}
bool Context2::create()
{
if( !haveOpenCL() )
return false;
if(p)
p->release();
p = new Impl();
if(!p->handle)
{
delete p;
p = 0;
}
return p != 0;
}
bool Context2::create(int dtype0)
{
if( !haveOpenCL() )
@@ -2081,23 +2361,16 @@ Context2& Context2::getDefault(bool initialize)
static Context2 ctx;
if(!ctx.p && haveOpenCL())
{
if (!ctx.p)
ctx.p = new Impl();
if (initialize)
{
// do not create new Context2 right away.
// First, try to retrieve existing context of the same type.
// In its turn, Platform::getContext() may call Context2::create()
// if there is no such context.
ctx.create(Device::TYPE_ACCELERATOR);
if(!ctx.p)
ctx.create(Device::TYPE_DGPU);
if(!ctx.p)
ctx.create(Device::TYPE_IGPU);
if(!ctx.p)
ctx.create(Device::TYPE_CPU);
}
else
{
ctx.p = new Impl();
if (ctx.p->handle == NULL)
ctx.p->setDefault();
}
}