From: Alexander Alekhin Date: Wed, 25 Dec 2013 10:39:21 +0000 (+0400) Subject: core/ocl: temporary move device selection from ocl module X-Git-Tag: submit/tizen_ivi/20141117.190038~2^2~763^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e49065b1dcef46fdaf9f1ae79fddccfbb706a8b1;p=profile%2Fivi%2Fopencv.git core/ocl: temporary move device selection from ocl module --- diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp index 7caf4c2..3112766 100644 --- a/modules/core/include/opencv2/core/ocl.hpp +++ b/modules/core/include/opencv2/core/ocl.hpp @@ -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; diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 67e5423..92c9ffb 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -41,6 +41,9 @@ #include "precomp.hpp" #include +#include +#include +#include // 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 +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 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 &elems) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } +} + +static std::vector split(const std::string &s, char delim) { + std::vector elems; + split(s, delim, elems); + return elems; +} + +// Layout: :: +// Sample: AMD:GPU: +// Sample: AMD:GPU:Tahiti +// Sample: :GPU|CPU: = '' = ':' = '::' +static bool parseOpenCLDeviceConfiguration(const std::string& configurationStr, + std::string& platform, std::vector& 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 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 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 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(); } } diff --git a/modules/ocl/perf/main.cpp b/modules/ocl/perf/main.cpp index c3b2f36..b537ec1 100644 --- a/modules/ocl/perf/main.cpp +++ b/modules/ocl/perf/main.cpp @@ -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()) } diff --git a/modules/ocl/perf/perf_precomp.hpp b/modules/ocl/perf/perf_precomp.hpp index 01626d5..366329c 100644 --- a/modules/ocl/perf/perf_precomp.hpp +++ b/modules/ocl/perf/perf_precomp.hpp @@ -59,6 +59,8 @@ # endif #endif +#define CV_BUILD_OCL_MODULE + #include #include #include diff --git a/modules/ocl/test/main.cpp b/modules/ocl/test/main.cpp index 0d51461..d284fcf 100644 --- a/modules/ocl/test/main.cpp +++ b/modules/ocl/test/main.cpp @@ -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)) diff --git a/modules/ocl/test/test_precomp.hpp b/modules/ocl/test/test_precomp.hpp index af467f5..f1887db 100644 --- a/modules/ocl/test/test_precomp.hpp +++ b/modules/ocl/test/test_precomp.hpp @@ -50,6 +50,8 @@ #ifndef __OPENCV_TEST_PRECOMP_HPP__ #define __OPENCV_TEST_PRECOMP_HPP__ +#define CV_BUILD_OCL_MODULE + #include #include #include diff --git a/modules/ts/include/opencv2/ts.hpp b/modules/ts/include/opencv2/ts.hpp index 8e898af..72a7ae6 100644 --- a/modules/ts/include/opencv2/ts.hpp +++ b/modules/ts/include/opencv2/ts.hpp @@ -4,6 +4,8 @@ #include "opencv2/core/cvdef.h" #include // 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(); \ } diff --git a/modules/ts/src/ocl_test.cpp b/modules/ts/src/ocl_test.cpp index d2ee771..201c5f4 100644 --- a/modules/ts/src/ocl_test.cpp +++ b/modules/ts/src/ocl_test.cpp @@ -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);