diff options
author | Dennis Francis <dennis.francis@collabora.com> | 2019-10-15 06:57:56 +0530 |
---|---|---|
committer | Dennis Francis <dennis.francis@collabora.com> | 2019-10-17 08:06:49 +0200 |
commit | 4ee424b3ddc6e483cac8bd76ddc0bcabe48241dc (patch) | |
tree | a552432da4728517cea4f0a11816545ebe178caa /sc | |
parent | 30d803e83390d8a4f475522dc23bcd107f7fdc12 (diff) |
Pre-allocate an ScInterpreter object for each thread...
and reuse them for interpret'ing all cells under the
respective threads. This gives a sizeable win in the execution
time especially for long formula-groups.
Change-Id: Ib340950f21e863b5b821d20c092214d8bc5012aa
Reviewed-on: https://gerrit.libreoffice.org/80845
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/interpretercontext.hxx | 3 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 19 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 9 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 8 | ||||
-rw-r--r-- | sc/source/core/tool/interpr2.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/tool/interpr4.cxx | 37 | ||||
-rw-r--r-- | sc/source/core/tool/interpr7.cxx | 2 |
7 files changed, 65 insertions, 15 deletions
diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx index c7598fef8cdc..b46a23f4e6a0 100644 --- a/sc/inc/interpretercontext.hxx +++ b/sc/inc/interpretercontext.hxx @@ -24,6 +24,7 @@ class FormulaToken; class ScDocument; class SvNumberFormatter; struct ScLookupCacheMap; +class ScInterpreter; // SetNumberFormat() is not thread-safe, so calls to it need to be delayed to the main thread. struct DelayedSetNumberFormat @@ -45,12 +46,14 @@ struct ScInterpreterContext // Allocation cache for "aConditions" array in ScInterpreter::IterateParameterIfs() // This is populated/used only when formula-group threading is enabled. std::vector<sal_uInt32> maConditions; + ScInterpreter* pInterpreter; ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter) : mpDoc(&rDoc) , mnTokenCachePos(0) , maTokens(TOKEN_CACHE_SIZE, nullptr) , mScLookupCache(nullptr) + , pInterpreter(nullptr) , mpFormatter(pFormatter) { } diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 572353c01bf7..d3dfbd18ea1a 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1886,7 +1886,19 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa if( pCode->GetCodeLen() && pDocument ) { - std::unique_ptr<ScInterpreter> pInterpreter(new ScInterpreter( this, pDocument, rContext, aPos, *pCode )); + std::unique_ptr<ScInterpreter> pScopedInterpreter; + ScInterpreter* pInterpreter; + if (rContext.pInterpreter) + { + pInterpreter = rContext.pInterpreter; + pInterpreter->Init(this, aPos, *pCode); + } + else + { + pScopedInterpreter.reset(new ScInterpreter( this, pDocument, rContext, aPos, *pCode )); + pInterpreter = pScopedInterpreter.get(); + } + FormulaError nOldErrCode = aResult.GetResultError(); if ( nSeenInIteration == 0 ) { // Only the first time @@ -4841,10 +4853,14 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope std::shared_ptr<comphelper::ThreadTaskTag> aTag = comphelper::ThreadPool::createThreadTaskTag(); ScThreadedInterpreterContextGetterGuard aContextGetterGuard(nThreadCount, *pDocument, pNonThreadedFormatter); ScInterpreterContext* context = nullptr; + std::vector<std::unique_ptr<ScInterpreter>> aInterpreters(nThreadCount); for (int i = 0; i < nThreadCount; ++i) { context = aContextGetterGuard.GetInterpreterContextForThreadIdx(i); + assert(!context->pInterpreter); + aInterpreters[i].reset(new ScInterpreter(this, pDocument, *context, mxGroup->mpTopCell->aPos, *pCode, true)); + context->pInterpreter = aInterpreters[i].get(); ScDocument::SetupFromNonThreadedContext(*context, i); rThreadPool.pushTask(std::make_unique<Executor>(aTag, i, nThreadCount, pDocument, context, mxGroup->mpTopCell->aPos, nColStart, nColEnd, nStartOffset, nEndOffset)); @@ -4862,6 +4878,7 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope context = aContextGetterGuard.GetInterpreterContextForThreadIdx(i); // This is intentionally done in this main thread in order to avoid locking. pDocument->MergeBackIntoNonThreadedContext(*context, i); + context->pInterpreter = nullptr; } SAL_INFO("sc.threaded", "Done"); diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index b47f7bf08239..d5e3d85ec20d 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -195,7 +195,7 @@ private: ScCalcConfig maCalcConfig; formula::FormulaTokenIterator aCode; ScAddress aPos; - ScTokenArray& rArr; + ScTokenArray* pArr; ScInterpreterContext& mrContext; ScDocument* pDok; sfx2::LinkManager* mpLinkManager; @@ -1004,9 +1004,14 @@ private: public: ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, ScInterpreterContext& rContext, - const ScAddress&, ScTokenArray& ); + const ScAddress&, ScTokenArray&, bool bForGroupThreading = false ); ~ScInterpreter(); + // Used only for threaded formula-groups. + // Resets the interpreter object, allowing reuse of interpreter object for each cell + // in the group. + void Init( ScFormulaCell* pCell, const ScAddress& rPos, ScTokenArray& rTokArray ); + formula::StackVar Interpret(); void SetError(FormulaError nError) diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 1c0e0237ad53..47c22449c581 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -8161,10 +8161,10 @@ void ScInterpreter::ScIndirect() { ScCompiler aComp( pDok, aPos, pDok->GetGrammar()); aComp.SetRefConvention( eConv); // must be after grammar - std::unique_ptr<ScTokenArray> pArr( aComp.CompileString( sRefStr)); + std::unique_ptr<ScTokenArray> pTokArr( aComp.CompileString( sRefStr)); // Whatever... use only the specific case. - if (!pArr->HasOpCode( ocTableRef)) + if (!pTokArr->HasOpCode( ocTableRef)) break; aComp.CompileTokenArray(); @@ -8172,10 +8172,10 @@ void ScInterpreter::ScIndirect() // A syntactically valid reference will generate exactly // one RPN token, a reference or error. Discard everything // else as error. - if (pArr->GetCodeLen() != 1) + if (pTokArr->GetCodeLen() != 1) break; - ScTokenRef xTok( pArr->FirstRPNToken()); + ScTokenRef xTok( pTokArr->FirstRPNToken()); if (!xTok) break; diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx index 653d524731dc..d6c76315b8fd 100644 --- a/sc/source/core/tool/interpr2.cxx +++ b/sc/source/core/tool/interpr2.cxx @@ -2764,7 +2764,7 @@ void ScInterpreter::ScDde() } // Need to reinterpret after loading (build links) - rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); + pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); // while the link is not evaluated, idle must be disabled (to avoid circular references) diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 77c0a48589ab..544a9ab11d0a 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -2660,7 +2660,7 @@ void ScInterpreter::ScExternal() else { // enable asyncs after loading - rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); + pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); // assure identical handler with identical call? double nErg = 0.0; ppParam[0] = &nErg; @@ -3020,7 +3020,7 @@ void ScInterpreter::ScExternal() if ( aCall.HasVarRes() ) // handle async functions { - rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); + pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); uno::Reference<sheet::XVolatileResult> xRes = aCall.GetVarRes(); ScAddInListener* pLis = ScAddInListener::Get( xRes ); // In case there is no pMyFormulaCell, i.e. while interpreting @@ -3767,10 +3767,10 @@ void ScInterpreter::ScTTT() } ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, ScInterpreterContext& rContext, - const ScAddress& rPos, ScTokenArray& r ) + const ScAddress& rPos, ScTokenArray& r, bool bForGroupThreading ) : aCode(r) , aPos(rPos) - , rArr(r) + , pArr(&r) , mrContext(rContext) , pDok(pDoc) , mpLinkManager(pDok->GetLinkManager()) @@ -3804,7 +3804,10 @@ ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, ScInterpre else bMatrixFormula = false; - if (!bGlobalStackInUse) + // Lets not use the global stack while formula-group-threading. + // as it complicates its life-cycle mgmt since for threading formula-groups, + // ScInterpreter is preallocated (in main thread) for each worker thread. + if (!bGlobalStackInUse && !bForGroupThreading) { bGlobalStackInUse = true; if (!pGlobalStack) @@ -3826,6 +3829,28 @@ ScInterpreter::~ScInterpreter() delete pStackObj; } +void ScInterpreter::Init( ScFormulaCell* pCell, const ScAddress& rPos, ScTokenArray& rTokArray ) +{ + aCode.ReInit(rTokArray); + aPos = rPos; + pArr = &rTokArray; + xResult = nullptr; + pMyFormulaCell = pCell; + pCur = nullptr; + nGlobalError = FormulaError::NONE; + sp = 0; + maxsp = 0; + nFuncFmtIndex = 0; + nCurFmtIndex = 0; + nRetFmtIndex = 0; + nFuncFmtType = SvNumFormatType::ALL; + nCurFmtType = SvNumFormatType::ALL; + nRetFmtType = SvNumFormatType::ALL; + mnStringNoValueError = FormulaError::NoValue; + mnSubTotalFlags = SubtotalFlags::NONE; + cPar = 0; +} + ScCalcConfig& ScInterpreter::GetOrCreateGlobalConfig() { if (!mpGlobalConfig) @@ -4503,7 +4528,7 @@ StackVar ScInterpreter::Interpret() { if ( !nErrorFunctionCount ) { // count of errorcode functions in formula - FormulaTokenArrayPlainIterator aIter(rArr); + FormulaTokenArrayPlainIterator aIter(*pArr); for ( FormulaToken* t = aIter.FirstRPN(); t; t = aIter.NextRPN() ) { if ( IsErrFunc(t->GetOpCode()) ) diff --git a/sc/source/core/tool/interpr7.cxx b/sc/source/core/tool/interpr7.cxx index 908c1d20aef2..8b58519bcda2 100644 --- a/sc/source/core/tool/interpr7.cxx +++ b/sc/source/core/tool/interpr7.cxx @@ -312,7 +312,7 @@ void ScInterpreter::ScWebservice() } // Need to reinterpret after loading (build links) - rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); + pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT ); // while the link is not evaluated, idle must be disabled (to avoid circular references) bool bOldEnabled = pDok->IsIdleEnabled(); |