[Libreoffice-commits] core.git: formula/source include/formula sc/inc sc/source

Dennis Francis (via logerrit) logerrit at kemper.freedesktop.org
Thu Oct 17 06:07:49 UTC 2019


 formula/source/core/api/token.cxx   |    6 +++++
 include/formula/tokenarray.hxx      |    4 +++
 sc/inc/interpretercontext.hxx       |    3 ++
 sc/source/core/data/formulacell.cxx |   19 +++++++++++++++++-
 sc/source/core/inc/interpre.hxx     |    9 ++++++--
 sc/source/core/tool/interpr1.cxx    |    8 +++----
 sc/source/core/tool/interpr2.cxx    |    2 -
 sc/source/core/tool/interpr4.cxx    |   37 ++++++++++++++++++++++++++++++------
 sc/source/core/tool/interpr7.cxx    |    2 -
 9 files changed, 75 insertions(+), 15 deletions(-)

New commits:
commit 4ee424b3ddc6e483cac8bd76ddc0bcabe48241dc
Author:     Dennis Francis <dennis.francis at collabora.com>
AuthorDate: Tue Oct 15 06:57:56 2019 +0530
Commit:     Dennis Francis <dennis.francis at collabora.com>
CommitDate: Thu Oct 17 08:06:49 2019 +0200

    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 at collabora.com>

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index bb08d4447e0d..17594207234f 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -1634,6 +1634,12 @@ void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
     }
 }
 
+void FormulaTokenIterator::ReInit( const FormulaTokenArray& rArr )
+{
+    maStack.clear();
+    Push( &rArr );
+}
+
 const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
 {
     FormulaTokenIterator::Item cur = maStack.back();
diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index 635e5c1f3907..44122686c158 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -563,6 +563,10 @@ public:
     void Push( const FormulaTokenArray* );
     void Pop();
 
+    /** Reconstruct the iterator afresh from a token array
+    */
+    void ReInit( const FormulaTokenArray& );
+
 private:
     const FormulaToken* GetNonEndOfPathToken( short nIdx ) const;
 };
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();


More information about the Libreoffice-commits mailing list