diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2016-07-08 22:16:27 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2016-07-11 06:52:31 +0000 |
commit | f41eb66302208f384a475fb20c98b6d1b0676cb6 (patch) | |
tree | 736e451e9da8f9cdeb1bf2075515e3aa0ebbacc3 /opencl | |
parent | b8c8b0d0c2bb2a1ce61e4d94d0a3e0636db658fa (diff) |
opencl: OpenCLZone, detect CL device change and disable CL on crash
Guard OpenCL calls with OpenCLZone, so if a OpenCL call crashes we
detect this and disable OpenCL so next time the user doesn't encounter
the crash at the same calculation because he has a broken OpenCL
drivers. Similar has been implemented for OpenGL with good results.
Additionaly we persistently remember a known good OpenCL device ID and
driver version so we can match this and perform calculation tests when
they change. This is to ensure that the selected OpenCL device performs
as we expect. In this commit the calculation tests aren't included yet.
Remove complex static initializer in opencl wrapper library.
Change-Id: I1a8b81ee31298731efcf63dc6a476955afc035e9
Reviewed-on: https://gerrit.libreoffice.org/27064
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'opencl')
-rw-r--r-- | opencl/Library_opencl.mk | 2 | ||||
-rw-r--r-- | opencl/inc/opencl_device_selection.h | 4 | ||||
-rw-r--r-- | opencl/source/OpenCLZone.cxx | 46 | ||||
-rw-r--r-- | opencl/source/opencl_device.cxx | 23 | ||||
-rw-r--r-- | opencl/source/openclwrapper.cxx | 107 |
5 files changed, 131 insertions, 51 deletions
diff --git a/opencl/Library_opencl.mk b/opencl/Library_opencl.mk index 501be304cfaf..039ec0125e53 100644 --- a/opencl/Library_opencl.mk +++ b/opencl/Library_opencl.mk @@ -38,6 +38,7 @@ $(eval $(call gb_Library_use_libraries,opencl,\ comphelper \ cppu \ sal \ + salhelper \ tl \ )) @@ -46,6 +47,7 @@ $(eval $(call gb_Library_add_exception_objects,opencl,\ opencl/source/openclwrapper \ opencl/source/opencl_device \ opencl/source/platforminfo \ + opencl/source/OpenCLZone \ )) ifeq ($(OS),LINUX) diff --git a/opencl/inc/opencl_device_selection.h b/opencl/inc/opencl_device_selection.h index 0522d768ba78..74d8d3767d97 100644 --- a/opencl/inc/opencl_device_selection.h +++ b/opencl/inc/opencl_device_selection.h @@ -24,6 +24,8 @@ #include <tools/stream.hxx> #include <rtl/math.hxx> +#include <opencl/OpenCLZone.hxx> + #include <vector> enum ds_status @@ -132,6 +134,8 @@ inline bool getDeviceInfoBool(cl_device_id aDeviceId, cl_device_info aDeviceInfo inline ds_status initDSProfile(std::unique_ptr<ds_profile>& rProfile, OString const & rVersion) { + OpenCLZone zone; + int numDevices; cl_uint numPlatforms; std::vector<cl_platform_id> platforms; diff --git a/opencl/source/OpenCLZone.cxx b/opencl/source/OpenCLZone.cxx new file mode 100644 index 000000000000..dc3a9522380b --- /dev/null +++ b/opencl/source/OpenCLZone.cxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <opencl/OpenCLZone.hxx> + +#include <memory> + +#include <officecfg/Office/Common.hxx> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> + +// FIXME: templatize me vs. OpenGLZone. + +sal_uInt64 volatile OpenCLZone::gnEnterCount = 0; +sal_uInt64 volatile OpenCLZone::gnLeaveCount = 0; + +/** + * Called from a signal handler if we get + * a crash or hang in some CL code. + */ +void OpenCLZone::hardDisable() +{ + // protect ourselves from double calling etc. + static bool bDisabled = false; + if (!bDisabled) + { + bDisabled = true; + + std::shared_ptr<comphelper::ConfigurationChanges> xChanges(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::UseOpenCL::set(false, xChanges); + xChanges->commit(); + + // Force synchronous config write + auto xConfProvider = css::configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()); + css::uno::Reference<css::util::XFlushable> xFlushable(xConfProvider, css::uno::UNO_QUERY_THROW); + xFlushable->flush(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/opencl/source/opencl_device.cxx b/opencl/source/opencl_device.cxx index 3dc9a29413ad..cfeb290645ea 100644 --- a/opencl/source/opencl_device.cxx +++ b/opencl/source/opencl_device.cxx @@ -31,6 +31,8 @@ #include <sal/log.hxx> #include <rtl/math.hxx> +#include <opencl/OpenCLZone.hxx> + #include "opencl_device.hxx" #define INPUTSIZE 15360 @@ -201,14 +203,21 @@ ds_status evaluateScoreForDevice(ds_device& rDevice, std::unique_ptr<LibreOffice /* Evaluating an OpenCL device */ SAL_INFO("opencl.device", "Device: \"" << rDevice.sDeviceName << "\" (OpenCL) evaluation..."); cl_int clStatus; + /* Check for 64-bit float extensions */ - size_t aDevExtInfoSize = 0; - clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize); - DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); + std::unique_ptr<char[]> aExtInfo; + { + size_t aDevExtInfoSize = 0; + + OpenCLZone zone; + clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize); + DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); + + aExtInfo.reset(new char[aDevExtInfoSize]); + clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr); + DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); + } - std::unique_ptr<char[]> aExtInfo(new char[aDevExtInfoSize]); - clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr); - DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); bool bKhrFp64Flag = false; bool bAmdFp64Flag = false; const char* buildOption = nullptr; @@ -245,6 +254,8 @@ ds_status evaluateScoreForDevice(ds_device& rDevice, std::unique_ptr<LibreOffice { /* 64-bit float support present */ + OpenCLZone zone; + /* Create context and command queue */ cl_context clContext = clCreateContext(nullptr, 1, &rDevice.aDeviceID, nullptr, nullptr, &clStatus); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateContext"); diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx index a54d86a70fc4..db6c7e51c09a 100644 --- a/opencl/source/openclwrapper.cxx +++ b/opencl/source/openclwrapper.cxx @@ -21,6 +21,7 @@ #include <rtl/ustring.hxx> #include <sal/config.h> #include <sal/log.hxx> +#include <opencl/OpenCLZone.hxx> #include <memory> #include <unicode/regex.h> @@ -81,15 +82,19 @@ OString generateMD5(const void* pData, size_t length) OString getCacheFolder() { - OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); - rtl::Bootstrap::expandMacros(url); + static OString aCacheFolder; - osl::Directory::create(url); + if (aCacheFolder.isEmpty()) + { + OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); + rtl::Bootstrap::expandMacros(url); - return rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8); -} + osl::Directory::create(url); -OString maCacheFolder = getCacheFolder(); + aCacheFolder = rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8); + } + return aCacheFolder; +} } @@ -131,8 +136,7 @@ OString createFileName(cl_device_id deviceId, const char* clFileName) OString aString = OString(deviceName) + driverVersion + platformVersion; OString aHash = generateMD5(aString.getStr(), aString.getLength()); - return maCacheFolder + fileName + "-" + - aHash + ".bin"; + return getCacheFolder() + fileName + "-" + aHash + ".bin"; } std::vector<std::shared_ptr<osl::File> > binaryGenerated( const char * clFileName, cl_context context ) @@ -266,6 +270,8 @@ bool initOpenCLAttr( OpenCLEnv * env ) void releaseOpenCLEnv( GPUEnv *gpuInfo ) { + OpenCLZone zone; + if ( !bIsInited ) { return; @@ -318,7 +324,7 @@ bool buildProgram(const char* buildOption, GPUEnv* gpuInfo, int idx) return false; } - OString aBuildLogFileURL = maCacheFolder + "kernel-build.log"; + OString aBuildLogFileURL = getCacheFolder() + "kernel-build.log"; osl::File aBuildLogFile(rtl::OStringToOUString(aBuildLogFileURL, RTL_TEXTENCODING_UTF8)); osl::FileBase::RC status = aBuildLogFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); @@ -409,6 +415,8 @@ namespace { void checkDeviceForDoubleSupport(cl_device_id deviceId, bool& bKhrFp64, bool& bAmdFp64) { + OpenCLZone zone; + bKhrFp64 = false; bAmdFp64 = false; @@ -441,6 +449,8 @@ void checkDeviceForDoubleSupport(cl_device_id deviceId, bool& bKhrFp64, bool& bA bool initOpenCLRunEnv( GPUEnv *gpuInfo ) { + OpenCLZone zone; + bool bKhrFp64 = false; bool bAmdFp64 = false; @@ -689,7 +699,7 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_ } -bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation) +bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation, OUString& rOutSelectedDeviceVersionIDString) { if(fillOpenCLInfo().empty()) return false; @@ -712,7 +722,6 @@ bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEv if ( aSelectedDevice.eType != DeviceType::OpenCLDevice) return false; pDeviceId = aSelectedDevice.aDeviceID; - } if(gpuEnv.mpDevID == pDeviceId) @@ -722,54 +731,62 @@ bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEv return pDeviceId != nullptr; } + cl_context context; cl_platform_id platformId; - cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM, - sizeof(platformId), &platformId, nullptr); - - cl_context_properties cps[3]; - cps[0] = CL_CONTEXT_PLATFORM; - cps[1] = reinterpret_cast<cl_context_properties>(platformId); - cps[2] = 0; - cl_context context = clCreateContext( cps, 1, &pDeviceId, nullptr, nullptr, &nState ); - if (nState != CL_SUCCESS) - SAL_WARN("opencl", "clCreateContext failed: " << errorString(nState)); + cl_command_queue command_queue[OPENCL_CMDQUEUE_SIZE]; - if(nState != CL_SUCCESS || context == nullptr) { - if(context != nullptr) - clReleaseContext(context); + OpenCLZone zone; + cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM, + sizeof(platformId), &platformId, nullptr); + + cl_context_properties cps[3]; + cps[0] = CL_CONTEXT_PLATFORM; + cps[1] = reinterpret_cast<cl_context_properties>(platformId); + cps[2] = 0; + context = clCreateContext( cps, 1, &pDeviceId, nullptr, nullptr, &nState ); + if (nState != CL_SUCCESS) + SAL_WARN("opencl", "clCreateContext failed: " << errorString(nState)); - SAL_WARN("opencl", "failed to set/switch opencl device"); - return false; - } - SAL_INFO("opencl", "Created context " << context << " for platform " << platformId << ", device " << pDeviceId); + if(nState != CL_SUCCESS || context == nullptr) + { + if(context != nullptr) + clReleaseContext(context); - cl_command_queue command_queue[OPENCL_CMDQUEUE_SIZE]; - for (int i = 0; i < OPENCL_CMDQUEUE_SIZE; ++i) - { - command_queue[i] = clCreateCommandQueue( - context, pDeviceId, 0, &nState); - if (nState != CL_SUCCESS) - SAL_WARN("opencl", "clCreateCommandQueue failed: " << errorString(nState)); + SAL_WARN("opencl", "failed to set/switch opencl device"); + return false; + } + SAL_INFO("opencl", "Created context " << context << " for platform " << platformId << ", device " << pDeviceId); - if (command_queue[i] == nullptr || nState != CL_SUCCESS) + for (int i = 0; i < OPENCL_CMDQUEUE_SIZE; ++i) { - // Release all command queues created so far. - for (int j = 0; j <= i; ++j) + command_queue[i] = clCreateCommandQueue( + context, pDeviceId, 0, &nState); + if (nState != CL_SUCCESS) + SAL_WARN("opencl", "clCreateCommandQueue failed: " << errorString(nState)); + + if (command_queue[i] == nullptr || nState != CL_SUCCESS) { - if (command_queue[j]) + // Release all command queues created so far. + for (int j = 0; j <= i; ++j) { - clReleaseCommandQueue(command_queue[j]); - command_queue[j] = nullptr; + if (command_queue[j]) + { + clReleaseCommandQueue(command_queue[j]); + command_queue[j] = nullptr; + } } + + clReleaseContext(context); + SAL_WARN("opencl", "failed to set/switch opencl device"); + return false; } - clReleaseContext(context); - SAL_WARN("opencl", "failed to set/switch opencl device"); - return false; + SAL_INFO("opencl", "Created command queue " << command_queue[i] << " for context " << context); } - SAL_INFO("opencl", "Created command queue " << command_queue[i] << " for context " << context); + OString sDeviceID = getDeviceInfoString(pDeviceId, CL_DEVICE_VENDOR) + " " + getDeviceInfoString(pDeviceId, CL_DRIVER_VERSION); + rOutSelectedDeviceVersionIDString = OStringToOUString(sDeviceID, RTL_TEXTENCODING_UTF8); } setOpenCLCmdQueuePosition(0); // Call this just to avoid the method being deleted from unused function deleter. |