Kaydet (Commit) 12c95935 authored tarafından Luboš Luňák's avatar Luboš Luňák

$SC_FORCE_CALCULATION to force Calc use opencl/threads for everything

So that e.g. unit tests can be easily run with OpenCL forced. This forces
even single cells to be evaluated using the forced method (many correctness
tests are just a single cell which normally would not be used for grouped
calculation).

Change-Id: If5c6e77a6e0d8696d5416d760cf5e47b8acf3d27
Reviewed-on: https://gerrit.libreoffice.org/63188
Tested-by: Jenkins
Reviewed-by: 's avatarLuboš Luňák <l.lunak@collabora.com>
üst 7fb235b2
...@@ -761,6 +761,11 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_ ...@@ -761,6 +761,11 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_
bool canUseOpenCL() bool canUseOpenCL()
{ {
if( const char* env = getenv( "SC_FORCE_CALCULATION" ))
{
if( strcmp( env, "opencl" ) == 0 )
return true;
}
return !getenv("SAL_DISABLE_OPENCL") && officecfg::Office::Common::Misc::UseOpenCL::get(); return !getenv("SAL_DISABLE_OPENCL") && officecfg::Office::Common::Misc::UseOpenCL::get();
} }
......
...@@ -27,6 +27,16 @@ enum ScRecalcOptions ...@@ -27,6 +27,16 @@ enum ScRecalcOptions
RECALC_ASK, RECALC_ASK,
}; };
// Env.var. SC_FORCE_CALCULATION can be used to force all calculation
// to be done using OpenCL or group threading (even for single cells).
enum ForceCalculationType
{
ForceCalculationNone, // do not force anything
ForceCalculationCore, // "core", use only non-threaded normal code
ForceCalculationOpenCL, // "opencl", force OpenCL
ForceCalculationThreads // "threads", force threaded code
};
/** /**
* Configuration options for formula interpreter. * Configuration options for formula interpreter.
*/ */
...@@ -47,6 +57,7 @@ struct SC_DLLPUBLIC ScCalcConfig ...@@ -47,6 +57,7 @@ struct SC_DLLPUBLIC ScCalcConfig
static bool isOpenCLEnabled(); static bool isOpenCLEnabled();
static bool isThreadingEnabled(); static bool isThreadingEnabled();
static ForceCalculationType getForceCalculationType();
bool mbOpenCLSubsetOnly:1; bool mbOpenCLSubsetOnly:1;
bool mbOpenCLAutoSelect:1; bool mbOpenCLAutoSelect:1;
......
...@@ -59,6 +59,7 @@ class ScRecursionHelper ...@@ -59,6 +59,7 @@ class ScRecursionHelper
bool bDoingRecursion; bool bDoingRecursion;
bool bInIterationReturn; bool bInIterationReturn;
bool bConverging; bool bConverging;
std::vector< ScFormulaCell* > aTemporaryGroupCells;
void Init(); void Init();
void ResetIteration(); void ResetIteration();
...@@ -107,6 +108,9 @@ public: ...@@ -107,6 +108,9 @@ public:
bool PushFormulaGroup(ScFormulaCell* pCell); bool PushFormulaGroup(ScFormulaCell* pCell);
void PopFormulaGroup(); void PopFormulaGroup();
bool AnyParentFGInCycle(); bool AnyParentFGInCycle();
void AddTemporaryGroupCell(ScFormulaCell* cell);
void CleanTemporaryGroupCells();
}; };
/** A class to wrap ScRecursionHelper::PushFormulaGroup(), /** A class to wrap ScRecursionHelper::PushFormulaGroup(),
......
...@@ -207,7 +207,7 @@ void ScCopyPasteTest::testTdf84411() ...@@ -207,7 +207,7 @@ void ScCopyPasteTest::testTdf84411()
CPPUNIT_ASSERT(pModel != nullptr); CPPUNIT_ASSERT(pModel != nullptr);
bool bOpenCLState = ScCalcConfig::isOpenCLEnabled(); bool bOpenCLState = ScCalcConfig::isOpenCLEnabled();
pModel->enableOpenCL(false); pModel->enableOpenCL(false);
CPPUNIT_ASSERT(!ScCalcConfig::isOpenCLEnabled()); CPPUNIT_ASSERT(!ScCalcConfig::isOpenCLEnabled() || ScCalcConfig::getForceCalculationType() == ForceCalculationOpenCL);
pModel->enableAutomaticCalculation(true); pModel->enableAutomaticCalculation(true);
......
...@@ -1483,12 +1483,43 @@ public: ...@@ -1483,12 +1483,43 @@ public:
} }
} }
}; };
}
// Forced calculation: OpenCL and threads require formula groups, so force even single cells to be a "group".
// Remove the group again at the end, since there are some places throughout the code
// that do not handle well groups with just 1 cell. Remove the groups only when the recursion level
// reaches 0 again (groups contain some info such as disabling threading because of cycles, so removing
// a group immediately would remove the info), for this reason affected cells are stored in the recursion
// helper.
struct TemporaryCellGroupMaker
{
TemporaryCellGroupMaker( ScFormulaCell* cell, bool enable )
: mCell( cell )
, mEnabled( enable )
{
if( mEnabled && mCell->GetCellGroup() == nullptr )
{
mCell->CreateCellGroup( 1, false );
mCell->GetDocument()->GetRecursionHelper().AddTemporaryGroupCell( mCell );
}
}
~TemporaryCellGroupMaker()
{
if( mEnabled )
mCell->GetDocument()->GetRecursionHelper().CleanTemporaryGroupCells();
}
ScFormulaCell* mCell;
const bool mEnabled;
};
} // namespace
void ScFormulaCell::Interpret() void ScFormulaCell::Interpret()
{ {
ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper(); ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
static ForceCalculationType forceType = ScCalcConfig::getForceCalculationType();
TemporaryCellGroupMaker cellGroupMaker( this, forceType != ForceCalculationNone && forceType != ForceCalculationCore );
ScFormulaCell* pTopCell = mxGroup ? mxGroup->mpTopCell : this; ScFormulaCell* pTopCell = mxGroup ? mxGroup->mpTopCell : this;
if (pTopCell->mbSeenInPath && rRecursionHelper.GetDepComputeLevel()) if (pTopCell->mbSeenInPath && rRecursionHelper.GetDepComputeLevel())
...@@ -4473,9 +4504,12 @@ bool ScFormulaCell::InterpretFormulaGroup() ...@@ -4473,9 +4504,12 @@ bool ScFormulaCell::InterpretFormulaGroup()
return false; return false;
} }
// To temporarily use threading for sc unit tests regardless of the size of the formula group, // Use SC_TEST_CALCULATION=opencl/threads to force calculation e.g. for unittests
// add the condition !std::getenv("LO_TESTNAME") below (with &&) static ForceCalculationType forceType = ScCalcConfig::getForceCalculationType();
if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize) if (forceType == ForceCalculationCore
|| ( GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize
&& forceType != ForceCalculationOpenCL
&& forceType != ForceCalculationThreads))
{ {
mxGroup->meCalcState = sc::GroupCalcDisabled; mxGroup->meCalcState = sc::GroupCalcDisabled;
aScope.addGroupSizeThresholdMessage(*this); aScope.addGroupSizeThresholdMessage(*this);
...@@ -4802,7 +4836,8 @@ bool ScFormulaCell::InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& a ...@@ -4802,7 +4836,8 @@ bool ScFormulaCell::InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& a
if (pInterpreter == nullptr || if (pInterpreter == nullptr ||
!pInterpreter->interpret(*pDocument, xGroup->mpTopCell->aPos, xGroup, aCode)) !pInterpreter->interpret(*pDocument, xGroup->mpTopCell->aPos, xGroup, aCode))
{ {
SAL_INFO("sc.opencl", "interpreting group " << mxGroup << " (state " << static_cast<int>(mxGroup->meCalcState) << ") failed, disabling"); SAL_INFO("sc.opencl", "interpreting group " << mxGroup->mpTopCell->aPos
<< " (state " << static_cast<int>(mxGroup->meCalcState) << ") failed, disabling");
mxGroup->meCalcState = sc::GroupCalcDisabled; mxGroup->meCalcState = sc::GroupCalcDisabled;
// Undo the hack above // Undo the hack above
......
...@@ -3843,6 +3843,9 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, ...@@ -3843,6 +3843,9 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc,
genRPNTokens(rDoc, rTopPos, rCode); genRPNTokens(rDoc, rTopPos, rCode);
if( rCode.GetCodeLen() == 0 )
return false;
CLInterpreterContext aCxt = createCLInterpreterContext(maCalcConfig, xGroup, rCode); CLInterpreterContext aCxt = createCLInterpreterContext(maCalcConfig, xGroup, rCode);
if (!aCxt.isValid()) if (!aCxt.isValid())
return false; return false;
......
...@@ -43,10 +43,44 @@ static rtl::Reference<ConfigurationListener> const & getFormulaCalculationListen ...@@ -43,10 +43,44 @@ static rtl::Reference<ConfigurationListener> const & getFormulaCalculationListen
return xListener; return xListener;
} }
static ForceCalculationType forceCalculationTypeInit()
{
const char* env = getenv( "SC_FORCE_CALCULATION" );
if( env != nullptr )
{
if( strcmp( env, "opencl" ) == 0 )
{
SAL_INFO("sc.core.formulagroup", "Forcing calculations to use OpenCL");
return ForceCalculationOpenCL;
}
if( strcmp( env, "threads" ) == 0 )
{
SAL_INFO("sc.core.formulagroup", "Forcing calculations to use threads");
return ForceCalculationThreads;
}
if( strcmp( env, "core" ) == 0 )
{
SAL_INFO("sc.core.formulagroup", "Forcing calculations to use core");
return ForceCalculationCore;
}
SAL_WARN("sc.core.formulagroup", "Unrecognized value of SC_TEST_CALCULATION");
}
return ForceCalculationNone;
}
ForceCalculationType ScCalcConfig::getForceCalculationType()
{
static const ForceCalculationType type = forceCalculationTypeInit();
return type;
}
bool ScCalcConfig::isOpenCLEnabled() bool ScCalcConfig::isOpenCLEnabled()
{ {
if (utl::ConfigManager::IsFuzzing()) if (utl::ConfigManager::IsFuzzing())
return false; return false;
static ForceCalculationType force = getForceCalculationType();
if( force != ForceCalculationNone )
return force == ForceCalculationOpenCL;
static comphelper::ConfigurationListenerProperty<bool> gOpenCLEnabled(getMiscListener(), "UseOpenCL"); static comphelper::ConfigurationListenerProperty<bool> gOpenCLEnabled(getMiscListener(), "UseOpenCL");
return gOpenCLEnabled.get(); return gOpenCLEnabled.get();
} }
...@@ -55,6 +89,9 @@ bool ScCalcConfig::isThreadingEnabled() ...@@ -55,6 +89,9 @@ bool ScCalcConfig::isThreadingEnabled()
{ {
if (utl::ConfigManager::IsFuzzing()) if (utl::ConfigManager::IsFuzzing())
return false; return false;
static ForceCalculationType force = getForceCalculationType();
if( force != ForceCalculationNone )
return force == ForceCalculationThreads;
static comphelper::ConfigurationListenerProperty<bool> gThreadingEnabled(getFormulaCalculationListener(), "UseThreadedCalculationForFormulaGroups"); static comphelper::ConfigurationListenerProperty<bool> gThreadingEnabled(getFormulaCalculationListener(), "UseThreadedCalculationForFormulaGroups");
return gThreadingEnabled.get(); return gThreadingEnabled.get();
} }
......
...@@ -157,6 +157,21 @@ bool ScRecursionHelper::AnyParentFGInCycle() ...@@ -157,6 +157,21 @@ bool ScRecursionHelper::AnyParentFGInCycle()
return false; return false;
} }
void ScRecursionHelper::AddTemporaryGroupCell(ScFormulaCell* cell)
{
aTemporaryGroupCells.push_back( cell );
}
void ScRecursionHelper::CleanTemporaryGroupCells()
{
if( GetRecursionCount() == 0 )
{
for( ScFormulaCell* cell : aTemporaryGroupCells )
cell->SetCellGroup( nullptr );
aTemporaryGroupCells.clear();
}
}
ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper& rRecursionHelper, ScFormulaCell* pCell) : ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper& rRecursionHelper, ScFormulaCell* pCell) :
mrRecHelper(rRecursionHelper) mrRecHelper(rRecursionHelper)
{ {
......
...@@ -3125,13 +3125,15 @@ void ScModelObj::HandleCalculateEvents() ...@@ -3125,13 +3125,15 @@ void ScModelObj::HandleCalculateEvents()
sal_Bool ScModelObj::isOpenCLEnabled() sal_Bool ScModelObj::isOpenCLEnabled()
{ {
return officecfg::Office::Common::Misc::UseOpenCL::get(); return ScCalcConfig::isOpenCLEnabled();
} }
void ScModelObj::enableOpenCL(sal_Bool bEnable) void ScModelObj::enableOpenCL(sal_Bool bEnable)
{ {
if (ScCalcConfig::isOpenCLEnabled() == static_cast<bool>(bEnable)) if (ScCalcConfig::isOpenCLEnabled() == static_cast<bool>(bEnable))
return; return;
if (ScCalcConfig::getForceCalculationType() != ForceCalculationNone)
return;
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
officecfg::Office::Common::Misc::UseOpenCL::set(bEnable, batch); officecfg::Office::Common::Misc::UseOpenCL::set(bEnable, batch);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment