desktop: validate OpenCL drivers before use.
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 Reviewed-on: https://gerrit.libreoffice.org/27131 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
This commit is contained in:
parent
9c711f05fa
commit
c44726c482
12 changed files with 213 additions and 12 deletions
|
@ -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,\
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
173
desktop/source/app/opencl.cxx
Normal file
173
desktop/source/app/opencl.cxx
Normal file
|
@ -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: */
|
|
@ -16,6 +16,9 @@ namespace opencl {
|
|||
|
||||
ds_device getDeviceSelection(OUString const & pFileName, bool bForceSelection = false);
|
||||
|
||||
struct GPUEnv;
|
||||
void releaseOpenCLEnv( GPUEnv *gpuInfo );
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,\
|
||||
|
|
16
sc/Package_opencl.mk
Normal file
16
sc/Package_opencl.mk
Normal file
|
@ -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:
|
BIN
sc/source/core/opencl/cl-test.ods
Normal file
BIN
sc/source/core/opencl/cl-test.ods
Normal file
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue