summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2016-07-11 15:12:38 +0100
committerMichael Meeks <michael.meeks@collabora.com>2016-07-12 01:40:56 +0100
commitc5caed66544c11596ba190722873ed0591d7d251 (patch)
treeab68c403990225994219609e7782c5b181b24c0a
parentFix --enable-mergelibs build. (diff)
downloadcore-private/kendy/testcl.tar.gz
core-private/kendy/testcl.zip
desktop: validate OpenCL drivers before use. private/kendy/testcl
OpenCL validation needs to happen before drivers are used in anger. This should isolate any crashes, and/or mis-behavior to We use app version, CL driver version and file time-stamp to trigger re-testing the device. If anything fails: hard disable OpenCL. We use an opencl validation sheet (cl-test.ods) and install it. It is a minimal CL set - it requires a very short formula group length, and combines several CL functions into few formulae to test more. The sheet structure, in particular the manual squaring / SQRT - is necessary to stick within the default CL subset, and ensure that formulae are CL enabled from the root of the dependency tree up. Change-Id: I18682dbdf9a8ba9c16d52bad4447e9acce97f0a3
-rw-r--r--Repository.mk1
-rw-r--r--desktop/Library_sofficeapp.mk3
-rw-r--r--desktop/inc/app.hxx1
-rw-r--r--desktop/source/app/app.cxx5
-rw-r--r--desktop/source/app/opencl.cxx173
-rw-r--r--opencl/inc/opencl_device.hxx3
-rw-r--r--opencl/source/OpenCLZone.cxx4
-rw-r--r--opencl/source/openclwrapper.cxx8
-rw-r--r--sc/Module_sc.mk1
-rw-r--r--sc/Package_opencl.mk16
-rw-r--r--sc/source/core/opencl/cl-test.odsbin0 -> 18186 bytes
-rw-r--r--sc/source/core/tool/formulagroup.cxx10
12 files changed, 213 insertions, 12 deletions
diff --git a/Repository.mk b/Repository.mk
index a07f75841e6d..4dcd930c95df 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -837,6 +837,7 @@ $(eval $(call gb_Helper_register_packages_for_install,ooo,\
Pyuno/mailmerge \
)) \
sfx2_classification \
+ $(if $(filter OPENCL,$(BUILD_TYPE)),sc_opencl_runtimetest) \
))
$(eval $(call gb_Helper_register_packages_for_install,ogltrans,\
diff --git a/desktop/Library_sofficeapp.mk b/desktop/Library_sofficeapp.mk
index 04bc4913a370..a5cf82b0de37 100644
--- a/desktop/Library_sofficeapp.mk
+++ b/desktop/Library_sofficeapp.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_Library_add_libs,sofficeapp,\
))
$(eval $(call gb_Library_use_externals,sofficeapp, \
+ $(if $(filter OPENCL,$(BUILD_TYPE)),clew) \
boost_headers \
dbus \
))
@@ -57,6 +58,7 @@ $(eval $(call gb_Library_use_libraries,sofficeapp,\
deploymentmisc \
editeng \
i18nlangtag \
+ $(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \
sal \
salhelper \
sb \
@@ -102,6 +104,7 @@ $(eval $(call gb_Library_add_exception_objects,sofficeapp,\
desktop/source/app/langselect \
desktop/source/app/lockfile2 \
desktop/source/app/officeipcthread \
+ desktop/source/app/opencl \
desktop/source/app/sofficemain \
desktop/source/app/userinstall \
desktop/source/migration/migration \
diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx
index 1905cf0c1d7c..c90bfdb0d7d7 100644
--- a/desktop/inc/app.hxx
+++ b/desktop/inc/app.hxx
@@ -84,6 +84,7 @@ class Desktop : public Application
static void OpenClients();
static void OpenDefault();
+ static void CheckOpenCLCompute(const css::uno::Reference<css::frame::XDesktop2> &);
DECL_STATIC_LINK_TYPED( Desktop, EnableAcceptors_Impl, void*, void);
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index fab48e100476..7628c7a04277 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1605,6 +1605,11 @@ int Desktop::Main()
FatalError( MakeStartupErrorMessage(e.Message) );
}
+ // FIXME: move this somewhere sensible.
+#if HAVE_FEATURE_OPENCL
+ CheckOpenCLCompute(xDesktop);
+#endif
+
// Release solar mutex just before we wait for our client to connect
{
SolarMutexReleaser aReleaser;
diff --git a/desktop/source/app/opencl.cxx b/desktop/source/app/opencl.cxx
new file mode 100644
index 000000000000..4c47767b8621
--- /dev/null
+++ b/desktop/source/app/opencl.cxx
@@ -0,0 +1,173 @@
+/* -*- 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/.
+ */
+/*
+ * This module exists to validate the OpenCL implementation,
+ * where necessary during startup; and before we load or
+ * calculate using OpenCL.
+ */
+
+#include "app.hxx"
+
+#include <config_version.h>
+#include <config_folders.h>
+
+#include <rtl/bootstrap.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <com/sun/star/table/XCell2.hpp>
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheets.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+
+#include <opencl/openclwrapper.hxx>
+#include <opencl/OpenCLZone.hxx>
+
+#include <osl/file.hxx>
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+namespace desktop {
+
+#if HAVE_FEATURE_OPENCL
+
+bool testOpenCLCompute(const Reference< XDesktop2 > &xDesktop, const OUString &rURL)
+{
+ bool bSuccess = false;
+ css::uno::Reference< css::lang::XComponent > xComponent;
+
+ SAL_INFO("opencl", "Starting CL test spreadsheet");
+
+ try {
+ css::uno::Reference< css::frame::XComponentLoader > xLoader(xDesktop, css::uno::UNO_QUERY_THROW);
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs(1);
+ aArgs[0].Name = "Hidden";
+ aArgs[0].Value = makeAny(true);
+
+ xComponent.set(xLoader->loadComponentFromURL(rURL, "_blank", 0, aArgs));
+
+ // What an unpleasant API to use.
+ css::uno::Reference< css::sheet::XCalculatable > xCalculatable( xComponent, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::sheet::XSpreadsheetDocument > xSpreadDoc( xComponent, css::uno::UNO_QUERY_THROW );
+ css::uno::Reference< css::sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), css::uno::UNO_QUERY_THROW );
+ css::uno::Reference< css::container::XIndexAccess > xIndex( xSheets, css::uno::UNO_QUERY_THROW );
+ css::uno::Reference< css::sheet::XSpreadsheet > xSheet( xIndex->getByIndex(0), css::uno::UNO_QUERY_THROW);
+
+ // So we insert our MAX call at the end on a named range.
+ css::uno::Reference< css::table::XCell2 > xThresh( xSheet->getCellByPosition(1,1), css::uno::UNO_QUERY_THROW ); // B2
+ double fThreshold = xThresh->getValue();
+
+ // We need pure OCL formulae all the way through the
+ // dependency chain, or we fall-back.
+ xCalculatable->calculateAll();
+
+ // So we insert our MAX call at the end on a named range.
+ css::uno::Reference< css::table::XCell2 > xCell( xSheet->getCellByPosition(1,0), css::uno::UNO_QUERY_THROW );
+ xCell->setFormula("=MAX(results)");
+ double fResult = xCell->getValue();
+
+ // Ensure the maximum variance is below our tolerance.
+ if (fResult > fThreshold)
+ {
+ SAL_WARN("opencl", "OpenCL results unstable - disabling; result: "
+ << fResult << " vs. " << fThreshold);
+ }
+ else
+ {
+ SAL_INFO("opencl", "calculating smoothly; result: " << fResult);
+ bSuccess = true;
+ }
+ }
+ catch (const css::uno::Exception &e)
+ {
+ (void)e;
+ SAL_WARN("opencl", "OpenCL testing failed - disabling: " << e.Message);
+ }
+
+ if (!bSuccess)
+ OpenCLZone::hardDisable();
+ if (xComponent.is())
+ xComponent->dispose();
+
+ return bSuccess;
+}
+
+void Desktop::CheckOpenCLCompute(const Reference< XDesktop2 > &xDesktop)
+{
+ if (getenv("SAL_DISABLE_OPENCL") ||
+ !officecfg::Office::Common::Misc::UseOpenCL::get())
+ return;
+
+ SAL_INFO("opencl", "Initiating test of OpenCL device");
+ OpenCLZone aZone;
+
+ OUString aDevice = officecfg::Office::Calc::Formula::Calculation::OpenCLDevice::get();
+ OUString aSelectedCLDeviceVersionID;
+ if (!opencl::switchOpenCLDevice(
+ &aDevice,
+ officecfg::Office::Calc::Formula::Calculation::OpenCLAutoSelect::get(),
+ false /* bForceEvaluation */,
+ aSelectedCLDeviceVersionID))
+ {
+ SAL_WARN("opencl", "Failed to initialize OpenCL for test");
+ OpenCLZone::hardDisable();
+ }
+
+ // Append our app version as well.
+ aSelectedCLDeviceVersionID += "--";
+ aSelectedCLDeviceVersionID += LIBO_VERSION_DOTTED;
+
+ // Append timestamp of the file.
+ OUString aURL("$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/opencl/cl-test.ods");
+ rtl::Bootstrap::expandMacros(aURL);
+
+ DirectoryItem aItem;
+ DirectoryItem::get( aURL, aItem );
+ FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime );
+ aItem.getFileStatus( aFileStatus );
+ TimeValue aTimeVal = aFileStatus.getModifyTime();
+ aSelectedCLDeviceVersionID += "--";
+ aSelectedCLDeviceVersionID += OUString::number(aTimeVal.Seconds);
+
+ if (aSelectedCLDeviceVersionID != officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::get())
+ {
+ // OpenCL device changed - sanity check it and disable if bad.
+
+ boost::optional<sal_Int32> nOrigMinimumSize = officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::get();
+ { // set the group size to something small for quick testing.
+ std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(3 /* small */, xBatch);
+ xBatch->commit();
+ }
+
+ bool bSucceeded = testOpenCLCompute(xDesktop, aURL);
+
+ // it passed -> save the device.
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(nOrigMinimumSize, xBatch);
+ // allow the user to subsequently manually enable it.
+ officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::set(aSelectedCLDeviceVersionID, xBatch);
+ xBatch->commit();
+ }
+
+ if (!bSucceeded)
+ OpenCLZone::hardDisable();
+ }
+}
+#endif // HAVE_FEATURE_OPENCL
+
+} // end namespace desktop
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/opencl/inc/opencl_device.hxx b/opencl/inc/opencl_device.hxx
index 0963304e8f99..216af72de849 100644
--- a/opencl/inc/opencl_device.hxx
+++ b/opencl/inc/opencl_device.hxx
@@ -16,6 +16,9 @@ namespace opencl {
ds_device getDeviceSelection(OUString const & pFileName, bool bForceSelection = false);
+struct GPUEnv;
+void releaseOpenCLEnv( GPUEnv *gpuInfo );
+
}
#endif
diff --git a/opencl/source/OpenCLZone.cxx b/opencl/source/OpenCLZone.cxx
index dc3a9522380b..03521a29c66f 100644
--- a/opencl/source/OpenCLZone.cxx
+++ b/opencl/source/OpenCLZone.cxx
@@ -7,7 +7,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#include <opencl/openclwrapper.hxx>
#include <opencl/OpenCLZone.hxx>
+#include "opencl_device.hxx"
#include <memory>
@@ -40,6 +42,8 @@ void OpenCLZone::hardDisable()
auto xConfProvider = css::configuration::theDefaultProvider::get(comphelper::getProcessComponentContext());
css::uno::Reference<css::util::XFlushable> xFlushable(xConfProvider, css::uno::UNO_QUERY_THROW);
xFlushable->flush();
+
+ releaseOpenCLEnv(&opencl::gpuEnv);
}
}
diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx
index db6c7e51c09a..2aecdde9338f 100644
--- a/opencl/source/openclwrapper.cxx
+++ b/opencl/source/openclwrapper.cxx
@@ -268,6 +268,8 @@ bool initOpenCLAttr( OpenCLEnv * env )
return false;
}
+}
+
void releaseOpenCLEnv( GPUEnv *gpuInfo )
{
OpenCLZone zone;
@@ -298,6 +300,8 @@ void releaseOpenCLEnv( GPUEnv *gpuInfo )
return;
}
+namespace {
+
bool buildProgram(const char* buildOption, GPUEnv* gpuInfo, int idx)
{
cl_int clStatus;
@@ -701,7 +705,7 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_
bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation, OUString& rOutSelectedDeviceVersionIDString)
{
- if(fillOpenCLInfo().empty())
+ if(fillOpenCLInfo().empty() || getenv("SAL_DISABLE_OPENCL"))
return false;
cl_device_id pDeviceId = nullptr;
@@ -884,7 +888,7 @@ const char* errorString(cl_int nError)
bool GPUEnv::isOpenCLEnabled()
{
- return gpuEnv.mpDevID;
+ return gpuEnv.mpDevID && gpuEnv.mpContext;
}
}
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index 9c331bbd85ee..392fbe096844 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -15,6 +15,7 @@ $(eval $(call gb_Module_add_targets,sc,\
Library_scd \
Library_scfilt \
$(call gb_Helper_optional,DESKTOP,Library_scui) \
+ $(call gb_Helper_optional,OPENCL,Package_opencl) \
))
$(eval $(call gb_Module_add_l10n_targets,sc,\
diff --git a/sc/Package_opencl.mk b/sc/Package_opencl.mk
new file mode 100644
index 000000000000..ef1579f52eb5
--- /dev/null
+++ b/sc/Package_opencl.mk
@@ -0,0 +1,16 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Package_Package,sc_opencl_runtimetest,$(SRCDIR)/sc/source/core/opencl))
+
+$(eval $(call gb_Package_add_files,sc_opencl_runtimetest,$(LIBO_ETC_FOLDER)/opencl,\
+ cl-test.ods \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/source/core/opencl/cl-test.ods b/sc/source/core/opencl/cl-test.ods
new file mode 100644
index 000000000000..8380e0b93a83
--- /dev/null
+++ b/sc/source/core/opencl/cl-test.ods
Binary files differ
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 49415042dd9c..15ce590bfc6c 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -336,16 +336,6 @@ bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool
delete msInstance;
msInstance = new sc::opencl::FormulaGroupInterpreterOpenCL();
- if (aSelectedCLDeviceVersionID != officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::get())
- {
- // perform OpenCL calculation tests
-
- // save the device
- std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
- officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::set(aSelectedCLDeviceVersionID, xBatch);
- xBatch->commit();
- }
-
return true;
}