#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"
/////////////////////////////////////////////////////////////////////////////////////////
+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()
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;
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() )
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();
}
}
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);