include/tools/cpuid.hxx | 1 sal/rtl/alloc_global.cxx | 2 sc/inc/tokenarray.hxx | 1 sc/inc/types.hxx | 1 sc/source/core/data/formulacell.cxx | 27 ++- sc/source/core/tool/formulagroup.cxx | 299 ++++++++++++++++++++++++----------- sc/source/core/tool/token.cxx | 31 ++- tools/source/misc/cpuid.cxx | 11 + 8 files changed, 268 insertions(+), 105 deletions(-)
New commits: commit 8d76f0b2e9eb528101cf3221d13de69dd880c72f Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 15 17:09:08 2017 +0530 halve thread count if HT active for group interpreter too Change-Id: Iacc93122191152183127500a4172358a14e96c8b diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 1159814783d2..199996478302 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -49,6 +49,7 @@ #include <tokenarray.hxx> #include <comphelper/threadpool.hxx> +#include <tools/cpuid.hxx> #include <formula/errorcodes.hxx> #include <formula/vectortoken.hxx> #include <svl/intitem.hxx> @@ -4364,6 +4365,8 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } + static bool bHyperThreadingActive = tools::cpuid::hasHyperThreading(); + // Then do the threaded calculation class Executor : public comphelper::ThreadTask @@ -4411,6 +4414,9 @@ bool ScFormulaCell::InterpretFormulaGroup() comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool()); sal_Int32 nThreadCount = rThreadPool.getWorkerCount(); + if ( bHyperThreadingActive && nThreadCount >= 2 ) + nThreadCount /= 2; + SAL_INFO("sc.threaded", "Running " << nThreadCount << " threads"); { commit c0f596e5e0f9589e70052a95a90f88e8e2023532 Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 15 16:52:44 2017 +0530 Disable custom allocator This has big positive effect on software interpreter threading performance scaling. Change-Id: I8fbb6bf8f7ed410fd53278acee63bf65f13bac38 diff --git a/sal/rtl/alloc_global.cxx b/sal/rtl/alloc_global.cxx index 3d74287bc7e5..47643f3ea74a 100644 --- a/sal/rtl/alloc_global.cxx +++ b/sal/rtl/alloc_global.cxx @@ -35,7 +35,7 @@ AllocMode alloc_mode = AllocMode::UNSET; static void determine_alloc_mode() { assert(alloc_mode == AllocMode::UNSET); - alloc_mode = (getenv("G_SLICE") == nullptr ? AllocMode::CUSTOM : AllocMode::SYSTEM); + alloc_mode = AllocMode::SYSTEM; } static const sal_Size g_alloc_sizes[] = commit 02af02d4f576ead19633e52c83463f5bdea8ea9b Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 15 16:37:45 2017 +0530 halve the number of threads if HT is active added hasHyperThreading() function to tools::cpuid to detect hyperthreading. Change-Id: I13fab4b6c649e681c329b7e3f4c9f36bda879d84 diff --git a/include/tools/cpuid.hxx b/include/tools/cpuid.hxx index d7aa07d54258..419d05714ae4 100644 --- a/include/tools/cpuid.hxx +++ b/include/tools/cpuid.hxx @@ -25,6 +25,7 @@ namespace tools namespace cpuid { TOOLS_DLLPUBLIC bool hasSSE2(); + TOOLS_DLLPUBLIC bool hasHyperThreading(); } } diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 7be682322221..e77554d89805 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -19,6 +19,7 @@ #include <scmatrix.hxx> #include <globalnames.hxx> #include <comphelper/threadpool.hxx> +#include <tools/cpuid.hxx> #include <formula/vectortoken.hxx> #include <officecfg/Office/Common.hxx> @@ -299,6 +300,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres // The caller must ensure that the top position is the start position of // the group. + static bool bHyperThreadingActive = tools::cpuid::hasHyperThreading(); ScAddress aTmpPos = rTopPos; std::vector<formula::FormulaConstTokenRef> aResults(xGroup->mnLength); @@ -335,6 +337,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool()); sal_Int32 nThreadCount = rThreadPool.getWorkerCount(); + if ( bHyperThreadingActive && nThreadCount >= 2 ) + nThreadCount /= 2; + SCROW nLen = xGroup->mnLength; SCROW nBatchSize = nLen / nThreadCount; if (nLen < nThreadCount) diff --git a/tools/source/misc/cpuid.cxx b/tools/source/misc/cpuid.cxx index 1518dfc175c4..e3ba82dffda5 100644 --- a/tools/source/misc/cpuid.cxx +++ b/tools/source/misc/cpuid.cxx @@ -16,8 +16,6 @@ namespace tools namespace cpuid { -#if defined(LO_SSE2_AVAILABLE) - namespace { #if defined(_MSC_VER) @@ -35,6 +33,8 @@ void getCpuId(uint32_t array[4]) #endif } +#if defined(LO_SSE2_AVAILABLE) + bool hasSSE2() { uint32_t cpuInfoArray[] = {0, 0, 0, 0}; @@ -48,6 +48,13 @@ bool hasSSE2() { return false; } #endif +bool hasHyperThreading() +{ + uint32_t cpuInfoArray[] = {0, 0, 0, 0}; + getCpuId(cpuInfoArray); + return (cpuInfoArray[3] & (1 << 28)) != 0; +} + } } commit 198ebcdc33de035f3f1a5d8cec7e7c50e7ef6a1e Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 15 16:14:32 2017 +0530 Avoid ScTokenArray thrash Allocate ScTokenArray object only once per worker thread, fill it for the first row/cell and reuse them for subsequent rows/cells if possible. Change-Id: If8f20da618938d0e189224f189b4763815702e10 diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index e22e294b9262..7be682322221 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -171,12 +171,14 @@ public: { double fNan; rtl::math::setNan(&fNan); + ScTokenArray aCode2; for (SCROW i = mnIdx; i <= mnLastIdx; ++i, maBatchTopPos.IncRow()) { - ScTokenArray aCode2; formula::FormulaTokenArrayPlainIterator aIter(mrCode); - for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next()) + size_t nTokIdx = 0; + for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next(), ++nTokIdx) { + formula::FormulaToken* pTargetTok = aCode2.TokenAt(nTokIdx); switch (p->GetType()) { case formula::svSingleVectorRef: @@ -200,14 +202,25 @@ public: { // This is a string cell. svl::SharedStringPool& rPool = mrDoc.GetSharedStringPool(); - aCode2.AddString(rPool.intern(OUString(pStr))); + if ( !pTargetTok ) + aCode2.AddString(rPool.intern(OUString(pStr))); + else + pTargetTok->SetString(rPool.intern(OUString(pStr))); } else if (rtl::math::isNan(fVal)) + { // Value of NaN represents an empty cell. - aCode2.AddToken(ScEmptyCellToken(false, false)); + if ( !pTargetTok ) + aCode2.AddToken(ScEmptyCellToken(false, false)); + } else + { // Numeric cell. - aCode2.AddDouble(fVal); + if ( !pTargetTok ) + aCode2.AddDouble(fVal); + else + pTargetTok->GetDoubleAsReference() = fVal; + } } break; case formula::svDoubleVectorRef: @@ -229,17 +242,29 @@ public: aRefRange.aEnd.SetRow(mrTopPos.Row() + nRowEnd); aRef.InitRange(aRefRange); formula::FormulaTokenRef xTok(new ScMatrixRangeToken(pMat, aRef)); - aCode2.AddToken(*xTok); + if ( !pTargetTok ) + aCode2.AddToken(*xTok); + else + aCode2.ReplaceToken(nTokIdx, xTok.get(), formula::FormulaTokenArray::CODE_ONLY); } else { - ScMatrixToken aTok(pMat); - aCode2.AddToken(aTok); + if ( !pTargetTok ) + { + ScMatrixToken aTok(pMat); + aCode2.AddToken(aTok); + } + else + { + ScMatrixToken* pMatTok = new ScMatrixToken(pMat); + aCode2.ReplaceToken(nTokIdx, pMatTok, formula::FormulaTokenArray::CODE_ONLY); + } } } break; default: - aCode2.AddToken(*p); + if ( !pTargetTok ) + aCode2.AddToken(*p); } // end of switch statement } // end of formula token for loop commit 12fdb96cec0d9d06a60ce0641386108401eaf367 Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 1 13:45:09 2017 +0530 Thread the software interpreter Also introduce new state ScFormulaVectorState::FormulaVectorEnabledForThreading to indicate that using the âtraditionalâ vectoring is disabled, but threading should be tried. Change-Id: I552d9e29e1ab9e5721534e07f4a45fdd5a23f399 diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 294794f959e0..8b352b447f09 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -92,6 +92,7 @@ public: svl::SharedStringPool& rSPool, formula::ExternalReferenceHelper* _pRef) override; virtual void CheckToken( const formula::FormulaToken& r ) override; + void CheckForThreading( OpCode eOp ); virtual formula::FormulaToken* AddOpCode( OpCode eCode ) override; /** ScSingleRefToken with ocPush. */ formula::FormulaToken* AddSingleReference( const ScSingleRefData& rRef ); diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index 51898c291fde..cc82e363765d 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -59,6 +59,7 @@ enum ScFormulaVectorState FormulaVectorEnabled, FormulaVectorCheckReference, + FormulaVectorEnabledForThreading, FormulaVectorUnknown }; diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 61b0f5a87702..1159814783d2 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -4345,7 +4345,9 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } - if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && pCode->GetVectorState() != FormulaVectorDisabledNotInSubSet && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) + if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && + pCode->GetVectorState() == FormulaVectorEnabledForThreading && + officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) { // iterate over code in the formula ... // ensure all input is pre-calculated - @@ -4437,26 +4439,30 @@ bool ScFormulaCell::InterpretFormulaGroup() return true; } + bool bCanVectorize = false; switch (pCode->GetVectorState()) { case FormulaVectorEnabled: case FormulaVectorCheckReference: - // Good. + bCanVectorize = true; // Good. break; // Not good. case FormulaVectorDisabledByOpCode: aScope.addMessage("group calc disabled due to vector state (non-vector-supporting opcode)"); - return false; + break; case FormulaVectorDisabledNotInSoftwareSubset: aScope.addMessage("group calc disabled due to vector state (opcode not in software subset)"); - return false; + break; case FormulaVectorDisabledByStackVariable: aScope.addMessage("group calc disabled due to vector state (non-vector-supporting stack variable)"); - return false; + break; case FormulaVectorDisabledNotInSubSet: aScope.addMessage("group calc disabled due to vector state (opcode not in subset)"); - return false; + break; + case FormulaVectorEnabledForThreading: + aScope.addMessage("group calc disabled due to vector state (wanted to try threading but couldn't)"); + break; case FormulaVectorDisabled: case FormulaVectorUnknown: default: @@ -4464,6 +4470,9 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } + if (!bCanVectorize) + return false; + if (!ScCalcConfig::isOpenCLEnabled() && !ScCalcConfig::isSwInterpreterEnabled()) { aScope.addMessage("opencl not enabled and sw interpreter not enabled"); diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index f637ab5753bc..e22e294b9262 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -18,9 +18,11 @@ #include <interpre.hxx> #include <scmatrix.hxx> #include <globalnames.hxx> +#include <comphelper/threadpool.hxx> #include <formula/vectortoken.hxx> #include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Calc.hxx> #if HAVE_FEATURE_OPENCL #include <opencl/platforminfo.hxx> #endif @@ -145,117 +147,208 @@ ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMa return ScMatrixRef(); } +class SoftwareInterpreterFunc +{ +public: + SoftwareInterpreterFunc(ScTokenArray& rCode, + ScAddress aBatchTopPos, + const ScAddress& rTopPos, + ScDocument& rDoc, + std::vector<formula::FormulaConstTokenRef>& rRes, + SCROW nIndex, + SCROW nLastIndex) : + mrCode(rCode), + maBatchTopPos(aBatchTopPos), + mrTopPos(rTopPos), + mrDoc(rDoc), + mrResults(rRes), + mnIdx(nIndex), + mnLastIdx(nLastIndex) + { + } + + void operator() () + { + double fNan; + rtl::math::setNan(&fNan); + for (SCROW i = mnIdx; i <= mnLastIdx; ++i, maBatchTopPos.IncRow()) + { + ScTokenArray aCode2; + formula::FormulaTokenArrayPlainIterator aIter(mrCode); + for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next()) + { + switch (p->GetType()) + { + case formula::svSingleVectorRef: + { + const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p); + const formula::VectorRefArray& rArray = p2->GetArray(); + + rtl_uString* pStr = nullptr; + double fVal = fNan; + if (static_cast<size_t>(i) < p2->GetArrayLength()) + { + if (rArray.mpStringArray) + // See if the cell is of string type. + pStr = rArray.mpStringArray[i]; + + if (!pStr && rArray.mpNumericArray) + fVal = rArray.mpNumericArray[i]; + } + + if (pStr) + { + // This is a string cell. + svl::SharedStringPool& rPool = mrDoc.GetSharedStringPool(); + aCode2.AddString(rPool.intern(OUString(pStr))); + } + else if (rtl::math::isNan(fVal)) + // Value of NaN represents an empty cell. + aCode2.AddToken(ScEmptyCellToken(false, false)); + else + // Numeric cell. + aCode2.AddDouble(fVal); + } + break; + case formula::svDoubleVectorRef: + { + const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p); + size_t nRowStart = p2->IsStartFixed() ? 0 : i; + size_t nRowEnd = p2->GetRefRowSize() - 1; + if (!p2->IsEndFixed()) + nRowEnd += i; + + assert(nRowStart <= nRowEnd); + ScMatrixRef pMat(new ScVectorRefMatrix(p2, nRowStart, nRowEnd - nRowStart + 1)); + + if (p2->IsStartFixed() && p2->IsEndFixed()) + { + // Cached the converted token for absolute range reference. + ScComplexRefData aRef; + ScRange aRefRange = mrTopPos; + aRefRange.aEnd.SetRow(mrTopPos.Row() + nRowEnd); + aRef.InitRange(aRefRange); + formula::FormulaTokenRef xTok(new ScMatrixRangeToken(pMat, aRef)); + aCode2.AddToken(*xTok); + } + else + { + ScMatrixToken aTok(pMat); + aCode2.AddToken(aTok); + } + } + break; + default: + aCode2.AddToken(*p); + } // end of switch statement + } // end of formula token for loop + + ScFormulaCell* pDest = mrDoc.GetFormulaCell(maBatchTopPos); + if (!pDest) + return; + + ScCompiler aComp(&mrDoc, maBatchTopPos, aCode2); + aComp.CompileTokenArray(); + ScInterpreter aInterpreter(pDest, &mrDoc, mrDoc.GetNonThreadedContext(), maBatchTopPos, aCode2); + aInterpreter.Interpret(); + mrResults[i] = aInterpreter.GetResultToken(); + } // Row iteration for loop end + } // operator () end + +private: + ScTokenArray& mrCode; + ScAddress maBatchTopPos; + const ScAddress& mrTopPos; + ScDocument& mrDoc; + std::vector<formula::FormulaConstTokenRef>& mrResults; + SCROW mnIdx; + SCROW mnLastIdx; +}; + bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddress& rTopPos, ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) { - typedef std::unordered_map<const formula::FormulaToken*, formula::FormulaTokenRef> CachedTokensType; - // Decompose the group into individual cells and calculate them individually. // The caller must ensure that the top position is the start position of // the group. ScAddress aTmpPos = rTopPos; - std::vector<formula::FormulaConstTokenRef> aResults; - aResults.reserve(xGroup->mnLength); - CachedTokensType aCachedTokens; - - double fNan; - rtl::math::setNan(&fNan); + std::vector<formula::FormulaConstTokenRef> aResults(xGroup->mnLength); - for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow()) + class Executor : public comphelper::ThreadTask { - ScTokenArray aCode2; - formula::FormulaTokenArrayPlainIterator aIter(rCode); - for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next()) + public: + Executor(std::shared_ptr<comphelper::ThreadTaskTag>& rTag, + ScTokenArray& rCode2, + ScAddress aBatchTopPos, + const ScAddress& rTopPos2, + ScDocument& rDoc2, + std::vector<formula::FormulaConstTokenRef>& rRes, + SCROW nIndex, + SCROW nLastIndex) : + comphelper::ThreadTask(rTag), + maSWIFunc(rCode2, aBatchTopPos, rTopPos2, rDoc2, rRes, nIndex, nLastIndex) { - CachedTokensType::iterator it = aCachedTokens.find(p); - if (it != aCachedTokens.end()) - { - // This token is cached. Use the cached one. - aCode2.AddToken(*it->second); - continue; - } + } + virtual void doWork() override + { + maSWIFunc(); + } - switch (p->GetType()) - { - case formula::svSingleVectorRef: - { - const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p); - const formula::VectorRefArray& rArray = p2->GetArray(); + private: + SoftwareInterpreterFunc maSWIFunc; + }; - rtl_uString* pStr = nullptr; - double fVal = fNan; - if (static_cast<size_t>(i) < p2->GetArrayLength()) - { - if (rArray.mpStringArray) - // See if the cell is of string type. - pStr = rArray.mpStringArray[i]; + static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION"); - if (!pStr && rArray.mpNumericArray) - fVal = rArray.mpNumericArray[i]; - } + bool bUseThreading = !bThreadingProhibited && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get(); - if (pStr) - { - // This is a string cell. - svl::SharedStringPool& rPool = rDoc.GetSharedStringPool(); - aCode2.AddString(rPool.intern(OUString(pStr))); - } - else if (rtl::math::isNan(fVal)) - // Value of NaN represents an empty cell. - aCode2.AddToken(ScEmptyCellToken(false, false)); - else - // Numeric cell. - aCode2.AddDouble(fVal); - } - break; - case formula::svDoubleVectorRef: - { - const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p); - size_t nRowStart = p2->IsStartFixed() ? 0 : i; - size_t nRowEnd = p2->GetRefRowSize() - 1; - if (!p2->IsEndFixed()) - nRowEnd += i; + if (bUseThreading) + { + comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool()); + sal_Int32 nThreadCount = rThreadPool.getWorkerCount(); + + SCROW nLen = xGroup->mnLength; + SCROW nBatchSize = nLen / nThreadCount; + if (nLen < nThreadCount) + { + nBatchSize = 1; + nThreadCount = nLen; + } + SCROW nRemaining = nLen - nBatchSize * nThreadCount; - assert(nRowStart <= nRowEnd); - ScMatrixRef pMat(new ScVectorRefMatrix(p2, nRowStart, nRowEnd - nRowStart + 1)); + SAL_INFO("sc.swipret.threaded", "Running " << nThreadCount << " threads"); - if (p2->IsStartFixed() && p2->IsEndFixed()) - { - // Cached the converted token for absolute range reference. - ScComplexRefData aRef; - ScRange aRefRange = rTopPos; - aRefRange.aEnd.SetRow(rTopPos.Row() + nRowEnd); - aRef.InitRange(aRefRange); - formula::FormulaTokenRef xTok(new ScMatrixRangeToken(pMat, aRef)); - aCachedTokens.emplace(p, xTok); - aCode2.AddToken(*xTok); - } - else - { - ScMatrixToken aTok(pMat); - aCode2.AddToken(aTok); - } - } - break; - default: - aCode2.AddToken(*p); - } + SCROW nLeft = nLen; + SCROW nStart = 0; + std::shared_ptr<comphelper::ThreadTaskTag> aTag = comphelper::ThreadPool::createThreadTaskTag(); + while (nLeft > 0) + { + SCROW nCount = std::min(nLeft, nBatchSize) + (nRemaining ? 1 : 0); + if ( nRemaining ) + --nRemaining; + SCROW nLast = nStart + nCount - 1; + rThreadPool.pushTask(new Executor(aTag, rCode, aTmpPos, rTopPos, rDoc, aResults, nStart, nLast)); + aTmpPos.IncRow(nCount); + nLeft -= nCount; + nStart = nLast + 1; } + SAL_INFO("sc.swipret.threaded", "Joining threads"); + rThreadPool.waitUntilDone(aTag); + SAL_INFO("sc.swipret.threaded", "Done"); + } + else + { + SoftwareInterpreterFunc aSWIFunc(rCode, aTmpPos, rTopPos, rDoc, aResults, 0, xGroup->mnLength - 1); + aSWIFunc(); + } - ScFormulaCell* pDest = rDoc.GetFormulaCell(aTmpPos); - if (!pDest) + for (SCROW i = 0; i < xGroup->mnLength; ++i) + if (!aResults[i].get()) return false; - ScCompiler aComp(&rDoc, aTmpPos, aCode2); - aComp.CompileTokenArray(); - ScInterpreter aInterpreter(pDest, &rDoc, rDoc.GetNonThreadedContext(), aTmpPos, aCode2); - aInterpreter.Interpret(); - aResults.push_back(aInterpreter.GetResultToken()); - } // for loop end (xGroup->mnLength) - if (!aResults.empty()) rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size()); diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 43f0825b3f1e..e8e30b9d24ad 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1336,7 +1336,7 @@ bool ScTokenArray::AddFormulaToken( return bError; } -void ScTokenArray::CheckToken( const FormulaToken& r ) +void ScTokenArray::CheckForThreading( OpCode eOp ) { static const std::set<OpCode> aThreadedCalcBlackList({ ocIndirect, @@ -1345,23 +1345,32 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) ocTableOp }); - if (IsFormulaVectorDisabled()) - // It's already disabled. No more checking needed. - return; + // We only call this if it was already disabled + assert(IsFormulaVectorDisabled()); static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION"); - OpCode eOp = r.GetOpCode(); - if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) { if (aThreadedCalcBlackList.count(eOp)) { - meVectorState = FormulaVectorDisabledNotInSubSet; SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables threaded calculation of formula group"); } - return; + else + { + SAL_INFO("sc.core.formulagroup", "but enabling for threading instead"); + meVectorState = FormulaVectorEnabledForThreading; + } } +} + +void ScTokenArray::CheckToken( const FormulaToken& r ) +{ + if (IsFormulaVectorDisabled()) + // It's already disabled. No more checking needed. + return; + + OpCode eOp = r.GetOpCode(); if (SC_OPCODE_START_FUNCTION <= eOp && eOp < SC_OPCODE_STOP_FUNCTION) { @@ -1370,6 +1379,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) { SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables vectorisation for formula group"); meVectorState = FormulaVectorDisabledNotInSubSet; + CheckForThreading(eOp); return; } @@ -1381,6 +1391,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) { SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables S/W interpreter for formula group"); meVectorState = FormulaVectorDisabledNotInSoftwareSubset; + CheckForThreading(eOp); return; } @@ -1608,6 +1619,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) // We don't support vectorization on these. SAL_INFO("sc.opencl", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType()) << " disables vectorisation for formula group"); meVectorState = FormulaVectorDisabledByStackVariable; + CheckForThreading(eOp); break; default: ; @@ -1619,6 +1631,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) { SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables vectorisation for formula group"); meVectorState = FormulaVectorDisabledNotInSubSet; + CheckForThreading(eOp); } // only when openCL interpreter is not enabled - the assumption is that // the S/W interpreter blacklist is more strict @@ -1629,6 +1642,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) { SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp) << " disables S/W interpreter for formula group"); meVectorState = FormulaVectorDisabledNotInSoftwareSubset; + CheckForThreading(eOp); } } @@ -1756,6 +1770,7 @@ bool ScTokenArray::IsFormulaVectorDisabled() const case FormulaVectorDisabledNotInSoftwareSubset: case FormulaVectorDisabledByStackVariable: case FormulaVectorDisabledNotInSubSet: + case FormulaVectorEnabledForThreading: return true; default: ;
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits