ocl: added OpenCL device selection via OPENCV_OPENCL_DEVICE environment variable

This commit is contained in:
Alexander Alekhin 2013-09-30 19:07:37 +04:00
parent dd9ff587dc
commit 16adbda4d3
3 changed files with 321 additions and 102 deletions

View File

@ -51,6 +51,8 @@ const char * impls[] =
#endif
};
using namespace cv::ocl;
int main(int argc, char ** argv)
{
const char * keys =
@ -59,42 +61,49 @@ int main(int argc, char ** argv)
"{ p | platform | -1 | set platform id }"
"{ d | device | 0 | set device id }";
CommandLineParser cmd(argc, argv, keys);
if (cmd.get<bool>("help"))
if (getenv("OPENCV_OPENCL_DEVICE") == NULL) // TODO Remove this after buildbot updates
{
cout << "Available options besides google test option:" << endl;
cmd.printParams();
return 0;
CommandLineParser cmd(argc, argv, keys);
if (cmd.get<bool>("help"))
{
cout << "Available options besides google test option:" << endl;
cmd.printParams();
return 0;
}
string type = cmd.get<string>("type");
int pid = cmd.get<int>("platform");
int device = cmd.get<int>("device");
int flag = type == "cpu" ? cv::ocl::CVCL_DEVICE_TYPE_CPU :
cv::ocl::CVCL_DEVICE_TYPE_GPU;
cv::ocl::PlatformsInfo platformsInfo;
cv::ocl::getOpenCLPlatforms(platformsInfo);
if (pid >= (int)platformsInfo.size())
{
std::cout << "platform is invalid\n";
return 1;
}
cv::ocl::DevicesInfo devicesInfo;
int devnums = cv::ocl::getOpenCLDevices(devicesInfo, flag, (pid < 0) ? NULL : platformsInfo[pid]);
if (device < 0 || device >= devnums)
{
std::cout << "device/platform invalid\n";
return 1;
}
cv::ocl::setDevice(devicesInfo[device]);
}
string type = cmd.get<string>("type");
int pid = cmd.get<int>("platform");
int device = cmd.get<int>("device");
const DeviceInfo& deviceInfo = cv::ocl::Context::getContext()->getDeviceInfo();
int flag = type == "cpu" ? cv::ocl::CVCL_DEVICE_TYPE_CPU :
cv::ocl::CVCL_DEVICE_TYPE_GPU;
cv::ocl::PlatformsInfo platformsInfo;
cv::ocl::getOpenCLPlatforms(platformsInfo);
if (pid >= (int)platformsInfo.size())
{
std::cout << "platform is invalid\n";
return 1;
}
cv::ocl::DevicesInfo devicesInfo;
int devnums = cv::ocl::getOpenCLDevices(devicesInfo, flag, (pid < 0) ? NULL : platformsInfo[pid]);
if (device < 0 || device >= devnums)
{
std::cout << "device/platform invalid\n";
return 1;
}
cv::ocl::setDevice(devicesInfo[device]);
cout << "Device type:" << type << endl
<< "Platform name:" << devicesInfo[device]->platform->platformName << endl
<< "Device name:" << devicesInfo[device]->deviceName << endl;
cout << "Device type: " << (deviceInfo.deviceType == CVCL_DEVICE_TYPE_CPU ?
"CPU" :
(deviceInfo.deviceType == CVCL_DEVICE_TYPE_GPU ? "GPU" : "unknown")) << endl
<< "Platform name: " << deviceInfo.platform->platformName << endl
<< "Device name: " << deviceInfo.deviceName << endl;
CV_PERF_TEST_MAIN_INTERNALS(ocl, impls)
}

View File

@ -51,7 +51,7 @@
#include "cl_programcache.hpp"
#if defined _MSC_VER && _MSC_VER >= 1200
# pragma warning( disable: 4100 4101 4127 4244 4267 4510 4512 4610)
#pragma warning( disable: 4100 4101 4127 4244 4267 4510 4512 4610)
#endif
#undef __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
@ -118,8 +118,211 @@ static bool parseOpenCLVersion(const std::string& versionStr, int& major, int& m
return true;
}
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 bool __deviceSelected = false;
static bool selectOpenCLDevice()
{
__deviceSelected = true;
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 false;
}
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);
}
}
const PlatformInfo* platformInfo = NULL;
if (platform.length() > 0)
{
PlatformsInfo platforms;
getOpenCLPlatforms(platforms);
for (size_t i = 0; i < platforms.size(); i++)
{
if (platforms[i]->platformName.find(platform) != std::string::npos)
{
platformInfo = platforms[i];
break;
}
}
if (platformInfo == NULL)
{
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 = CVCL_DEVICE_TYPE_GPU;
}
else if (deviceTypes[t] == "CPU")
{
deviceType = CVCL_DEVICE_TYPE_CPU;
}
else if (deviceTypes[t] == "ACCELERATOR")
{
deviceType = CVCL_DEVICE_TYPE_ACCELERATOR;
}
else if (deviceTypes[t] == "ALL")
{
deviceType = CVCL_DEVICE_TYPE_ALL;
}
else
{
std::cerr << "ERROR: Unsupported device type for OpenCL device (GPU, CPU, ACCELERATOR): " << deviceTypes[t] << std::endl;
goto not_found;
}
DevicesInfo devices;
getOpenCLDevices(devices, deviceType, platformInfo);
for (size_t i = (isID ? deviceID : 0);
(isID ? (i == (size_t)deviceID) : true) && (i < devices.size());
i++)
{
if (isID || devices[i]->deviceName.find(deviceName) != std::string::npos)
{
// check for OpenCL 1.1
if (devices[i]->deviceVersionMajor < 1 ||
(devices[i]->deviceVersionMajor == 1 && devices[i]->deviceVersionMinor < 1))
{
std::cerr << "Skip unsupported version of OpenCL device: " << devices[i]->deviceName
<< "(" << devices[i]->platform->platformName << ")" << std::endl;
continue; // unsupported version of device, skip it
}
try
{
setDevice(devices[i]);
}
catch (...)
{
std::cerr << "ERROR: Can't select OpenCL device: " << devices[i]->deviceName
<< "(" << devices[i]->platform->platformName << ")" << std::endl;
goto not_found;
}
return true;
}
}
}
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 false;
}
static cv::Mutex __initializedMutex;
static bool __initialized = false;
static int initializeOpenCLDevices()
{
assert(!__initialized);
__initialized = true;
assert(global_devices.size() == 0);
std::vector<cl::Platform> platforms;
@ -284,8 +487,6 @@ protected:
}
~ContextImpl();
public:
static ContextImpl* getContext();
static void setContext(const DeviceInfo* deviceInfo);
bool supportsFeature(FEATURE_TYPE featureType) const;
@ -298,6 +499,28 @@ static ContextImpl* currentContext = NULL;
Context* Context::getContext()
{
if (currentContext == NULL)
{
if (!__initialized || !__deviceSelected)
{
cv::AutoLock lock(__initializedMutex);
if (!__initialized)
{
if (initializeOpenCLDevices() == 0)
{
CV_Error(CV_GpuNotSupported, "OpenCL not available");
}
}
if (!__deviceSelected)
{
if (!selectOpenCLDevice())
{
CV_Error(CV_GpuNotSupported, "Can't select OpenCL device");
}
}
}
CV_Assert(currentContext != NULL);
}
return currentContext;
}
@ -422,13 +645,11 @@ void ContextImpl::setContext(const DeviceInfo* deviceInfo)
}
}
ContextImpl* ContextImpl::getContext()
{
return currentContext;
}
int getOpenCLPlatforms(PlatformsInfo& platforms)
{
if (!__initialized)
initializeOpenCLDevices();
platforms.clear();
for (size_t id = 0; id < global_platforms.size(); ++id)
@ -442,6 +663,9 @@ int getOpenCLPlatforms(PlatformsInfo& platforms)
int getOpenCLDevices(std::vector<const DeviceInfo*> &devices, int deviceType, const PlatformInfo* platform)
{
if (!__initialized)
initializeOpenCLDevices();
devices.clear();
switch(deviceType)
@ -461,7 +685,7 @@ int getOpenCLDevices(std::vector<const DeviceInfo*> &devices, int deviceType, co
for (size_t id = 0; id < global_devices.size(); ++id)
{
DeviceInfoImpl& deviceInfo = global_devices[id];
if (((int)deviceInfo.info.deviceType & deviceType) == deviceType)
if (((int)deviceInfo.info.deviceType & deviceType) != 0)
{
devices.push_back(&deviceInfo.info);
}
@ -479,35 +703,14 @@ int getOpenCLDevices(std::vector<const DeviceInfo*> &devices, int deviceType, co
}
}
if (currentContext == NULL)
{
// select default device
const DeviceInfo* selectedDevice = NULL;
for (size_t i = 0; i < devices.size(); i++)
{
const DeviceInfo* dev = devices[i];
if (dev->deviceType == CL_DEVICE_TYPE_GPU)
{
selectedDevice = dev;
break;
}
else if (dev->deviceType == CL_DEVICE_TYPE_CPU && (selectedDevice == NULL))
{
selectedDevice = dev;
}
}
if (selectedDevice)
{
setDevice(selectedDevice);
}
}
return (int)devices.size();
}
void setDevice(const DeviceInfo* info)
{
if (!__deviceSelected)
__deviceSelected = true;
ContextImpl::setContext(info);
}
@ -518,14 +721,14 @@ bool supportsFeature(FEATURE_TYPE featureType)
struct __Module
{
__Module() { initializeOpenCLDevices(); }
__Module() { /* moved to Context::getContext(): initializeOpenCLDevices(); */ }
~__Module() { ContextImpl::cleanupContext(); }
};
static __Module __module;
}//namespace ocl
}//namespace cv
} // namespace ocl
} // namespace cv
#if defined(WIN32) && defined(CVAPI_EXPORTS)

View File

@ -83,45 +83,52 @@ int main(int argc, char **argv)
"{ p | platform | -1 | set platform id }"
"{ d | device | 0 | set device id }";
CommandLineParser cmd(argc, argv, keys);
if (cmd.get<bool>("help"))
if (getenv("OPENCV_OPENCL_DEVICE") == NULL) // TODO Remove this after buildbot updates
{
cout << "Available options besides google test option:" << endl;
cmd.printParams();
return 0;
}
string type = cmd.get<string>("type");
int pid = cmd.get<int>("platform");
int device = cmd.get<int>("device");
CommandLineParser cmd(argc, argv, keys);
if (cmd.get<bool>("help"))
{
cout << "Available options besides google test option:" << endl;
cmd.printParams();
return 0;
}
string type = cmd.get<string>("type");
int pid = cmd.get<int>("platform");
int device = cmd.get<int>("device");
print_info();
int flag = CVCL_DEVICE_TYPE_GPU;
if(type == "cpu")
{
flag = CVCL_DEVICE_TYPE_CPU;
print_info();
int flag = CVCL_DEVICE_TYPE_GPU;
if(type == "cpu")
{
flag = CVCL_DEVICE_TYPE_CPU;
}
cv::ocl::PlatformsInfo platformsInfo;
cv::ocl::getOpenCLPlatforms(platformsInfo);
if (pid >= (int)platformsInfo.size())
{
std::cout << "platform is invalid\n";
return 1;
}
cv::ocl::DevicesInfo devicesInfo;
int devnums = cv::ocl::getOpenCLDevices(devicesInfo, flag, (pid < 0) ? NULL : platformsInfo[pid]);
if (device < 0 || device >= devnums)
{
std::cout << "device/platform invalid\n";
return 1;
}
cv::ocl::setDevice(devicesInfo[device]);
}
cv::ocl::PlatformsInfo platformsInfo;
cv::ocl::getOpenCLPlatforms(platformsInfo);
if (pid >= (int)platformsInfo.size())
{
std::cout << "platform is invalid\n";
return 1;
}
const DeviceInfo& deviceInfo = cv::ocl::Context::getContext()->getDeviceInfo();
cv::ocl::DevicesInfo devicesInfo;
int devnums = cv::ocl::getOpenCLDevices(devicesInfo, flag, (pid < 0) ? NULL : platformsInfo[pid]);
if (device < 0 || device >= devnums)
{
std::cout << "device/platform invalid\n";
return 1;
}
cv::ocl::setDevice(devicesInfo[device]);
cout << "Device type: " << type << endl
<< "Platform name: " << devicesInfo[device]->platform->platformName << endl
<< "Device name: " << devicesInfo[device]->deviceName << endl;
cout << "Device type: " << (deviceInfo.deviceType == CVCL_DEVICE_TYPE_CPU ?
"CPU" :
(deviceInfo.deviceType == CVCL_DEVICE_TYPE_GPU ? "GPU" : "unknown")) << endl
<< "Platform name: " << deviceInfo.platform->platformName << endl
<< "Device name: " << deviceInfo.deviceName << endl;
return RUN_ALL_TESTS();
}