mirror of
https://github.com/opencv/opencv.git
synced 2024-11-29 05:29:54 +08:00
core/ocl: temporary move device selection from ocl module
This commit is contained in:
parent
0966e5ffa1
commit
e49065b1dc
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,5 +72,5 @@ int main(int argc, char ** argv)
|
||||
{
|
||||
::perf::TestBase::setModulePerformanceStrategy(::perf::PERF_STRATEGY_SIMPLE);
|
||||
|
||||
CV_PERF_TEST_MAIN_INTERNALS(ocl, impls, dumpOpenCLDevice())
|
||||
CV_PERF_TEST_MAIN_INTERNALS(ocl, impls, ::dumpOpenCLDevice())
|
||||
}
|
||||
|
@ -59,6 +59,8 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define CV_BUILD_OCL_MODULE
|
||||
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
@ -76,5 +76,5 @@ void readLoopTimes(int argc, char ** argv)
|
||||
CV_Assert(LOOP_TIMES > 0);
|
||||
}
|
||||
|
||||
CV_TEST_MAIN(".", dumpOpenCLDevice(),
|
||||
CV_TEST_MAIN(".", ::dumpOpenCLDevice(),
|
||||
readLoopTimes(argc, argv))
|
||||
|
@ -50,6 +50,8 @@
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__
|
||||
#define __OPENCV_TEST_PRECOMP_HPP__
|
||||
|
||||
#define CV_BUILD_OCL_MODULE
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "opencv2/core/cvdef.h"
|
||||
#include <stdarg.h> // for va_list
|
||||
|
||||
#include "cvconfig.h"
|
||||
|
||||
#ifdef HAVE_WINRT
|
||||
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
||||
#endif
|
||||
@ -548,6 +550,15 @@ CV_EXPORTS void printVersionInfo(bool useStdOut = true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_OPENCL) && !defined(CV_BUILD_OCL_MODULE)
|
||||
namespace cvtest { namespace ocl {
|
||||
void dumpOpenCLDevice();
|
||||
}}
|
||||
#define TEST_DUMP_OCL_INFO cvtest::ocl::dumpOpenCLDevice();
|
||||
#else
|
||||
#define TEST_DUMP_OCL_INFO
|
||||
#endif
|
||||
|
||||
#define CV_TEST_MAIN(resourcesubdir, ...) \
|
||||
int main(int argc, char **argv) \
|
||||
{ \
|
||||
@ -555,6 +566,7 @@ int main(int argc, char **argv) \
|
||||
::testing::InitGoogleTest(&argc, argv); \
|
||||
cvtest::printVersionInfo(); \
|
||||
__CV_TEST_EXEC_ARGS(__VA_ARGS__) \
|
||||
TEST_DUMP_OCL_INFO \
|
||||
return RUN_ALL_TESTS(); \
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,146 @@ using namespace cv;
|
||||
|
||||
int test_loop_times = 1; // TODO Read from command line / environment
|
||||
|
||||
|
||||
#define DUMP_PROPERTY_XML(propertyName, propertyValue) \
|
||||
do { \
|
||||
std::stringstream ssName, ssValue;\
|
||||
ssName << propertyName;\
|
||||
ssValue << (propertyValue); \
|
||||
::testing::Test::RecordProperty(ssName.str(), ssValue.str()); \
|
||||
} while (false)
|
||||
|
||||
#define DUMP_MESSAGE_STDOUT(msg) \
|
||||
do { \
|
||||
std::cout << msg << std::endl; \
|
||||
} while (false)
|
||||
|
||||
static std::string bytesToStringRepr(size_t value)
|
||||
{
|
||||
size_t b = value % 1024;
|
||||
value /= 1024;
|
||||
|
||||
size_t kb = value % 1024;
|
||||
value /= 1024;
|
||||
|
||||
size_t mb = value % 1024;
|
||||
value /= 1024;
|
||||
|
||||
size_t gb = value;
|
||||
|
||||
std::ostringstream stream;
|
||||
|
||||
if (gb > 0)
|
||||
stream << gb << " GB ";
|
||||
if (mb > 0)
|
||||
stream << mb << " MB ";
|
||||
if (kb > 0)
|
||||
stream << kb << " kB ";
|
||||
if (b > 0)
|
||||
stream << b << " B";
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
void dumpOpenCLDevice()
|
||||
{
|
||||
using namespace cv::ocl;
|
||||
try
|
||||
{
|
||||
#if 0
|
||||
Platforms platforms;
|
||||
getOpenCLPlatforms(platforms);
|
||||
if (platforms.size() > 0)
|
||||
{
|
||||
DUMP_MESSAGE_STDOUT("OpenCL Platforms: ");
|
||||
for (size_t i = 0; i < platforms.size(); i++)
|
||||
{
|
||||
const Platform* platform = platforms.at(i);
|
||||
DUMP_MESSAGE_STDOUT(" " << platform->name().c_str());
|
||||
const Devices& devices = platform->devices();
|
||||
for (size_t j = 0; j < devices.size(); j++)
|
||||
{
|
||||
const Device& current_device = *devices.at(j);
|
||||
const char* deviceTypeStr = current_device.type() == Device::TYPE_CPU
|
||||
? ("CPU") : (current_device.type() == Device::TYPE_GPU ? "GPU" : "unknown");
|
||||
DUMP_MESSAGE_STDOUT( " " << deviceTypeStr << ": " << current_device.name().c_str() << " (" << current_device.version().c_str() << ")");
|
||||
DUMP_PROPERTY_XML(cv::format("cv_ocl_platform_%d_device_%d", (int)i, (int)j),
|
||||
"(Platform=" << current_device.getPlatform().name().c_str()
|
||||
<< ")(Type=" << deviceTypeStr
|
||||
<< ")(Name=" << current_device.name().c_str()
|
||||
<< ")(Version=" << current_device.version().c_str() << ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DUMP_MESSAGE_STDOUT("OpenCL is not available");
|
||||
DUMP_PROPERTY_XML("cv_ocl", "not available");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
DUMP_MESSAGE_STDOUT("Current OpenCL device: ");
|
||||
|
||||
const Device& device = Device::getDefault();
|
||||
|
||||
#if 0
|
||||
DUMP_MESSAGE_STDOUT(" Platform = "<< device.getPlatform().name());
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_platformName", device.getPlatform().name());
|
||||
#endif
|
||||
|
||||
const char* deviceTypeStr = device.type() == Device::TYPE_CPU
|
||||
? "CPU" : (device.type() == Device::TYPE_GPU ? "GPU" : "unknown");
|
||||
DUMP_MESSAGE_STDOUT(" Type = "<< deviceTypeStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_deviceType", deviceTypeStr);
|
||||
|
||||
DUMP_MESSAGE_STDOUT(" Name = "<< device.name());
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_deviceName", device.name());
|
||||
|
||||
#if 0
|
||||
DUMP_MESSAGE_STDOUT(" Version = " << device.version());
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_deviceVersion", device.version());
|
||||
#endif
|
||||
|
||||
DUMP_MESSAGE_STDOUT(" Compute units = "<< device.maxComputeUnits());
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_maxComputeUnits", device.maxComputeUnits());
|
||||
|
||||
DUMP_MESSAGE_STDOUT(" Max work group size = "<< device.maxWorkGroupSize());
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_maxWorkGroupSize", device.maxWorkGroupSize());
|
||||
|
||||
std::string localMemorySizeStr = bytesToStringRepr(device.localMemSize());
|
||||
DUMP_MESSAGE_STDOUT(" Local memory size = " << localMemorySizeStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_localMemSize", device.localMemSize());
|
||||
|
||||
std::string maxMemAllocSizeStr = bytesToStringRepr(device.maxMemAllocSize());
|
||||
DUMP_MESSAGE_STDOUT(" Max memory allocation size = "<< maxMemAllocSizeStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_maxMemAllocSize", device.maxMemAllocSize());
|
||||
|
||||
#if 0
|
||||
const char* doubleSupportStr = device.haveDoubleSupport() ? "Yes" : "No";
|
||||
DUMP_MESSAGE_STDOUT(" Double support = "<< doubleSupportStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_haveDoubleSupport", device.haveDoubleSupport());
|
||||
#else
|
||||
const char* doubleSupportStr = device.doubleFPConfig() > 0 ? "Yes" : "No";
|
||||
DUMP_MESSAGE_STDOUT(" Double support = "<< doubleSupportStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_haveDoubleSupport", device.doubleFPConfig() > 0);
|
||||
|
||||
#endif
|
||||
|
||||
const char* isUnifiedMemoryStr = device.hostUnifiedMemory() ? "Yes" : "No";
|
||||
DUMP_MESSAGE_STDOUT(" Host unified memory = "<< isUnifiedMemoryStr);
|
||||
DUMP_PROPERTY_XML("cv_ocl_current_hostUnifiedMemory", device.hostUnifiedMemory());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
DUMP_MESSAGE_STDOUT("Exception. Can't dump OpenCL info");
|
||||
DUMP_MESSAGE_STDOUT("OpenCL device not available");
|
||||
DUMP_PROPERTY_XML("cv_ocl", "not available");
|
||||
}
|
||||
}
|
||||
#undef DUMP_MESSAGE_STDOUT
|
||||
#undef DUMP_PROPERTY_XML
|
||||
|
||||
|
||||
Mat TestUtils::readImage(const String &fileName, int flags)
|
||||
{
|
||||
return cv::imread(cvtest::TS::ptr()->get_data_path() + fileName, flags);
|
||||
|
Loading…
Reference in New Issue
Block a user