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

Dennis Francis (via logerrit) logerrit at kemper.freedesktop.org
Tue Oct 1 16:11:05 UTC 2019


 sc/inc/column.hxx                       |    3 
 sc/inc/document.hxx                     |    4 -
 sc/inc/formulacell.hxx                  |    2 
 sc/inc/interpretercontext.hxx           |    3 
 sc/inc/recursionhelper.hxx              |   22 ++++++
 sc/inc/table.hxx                        |    5 -
 sc/source/core/data/column2.cxx         |    5 -
 sc/source/core/data/documen8.cxx        |   14 +--
 sc/source/core/data/formulacell.cxx     |  117 ++++++++++++++++++++++++++++++--
 sc/source/core/data/table1.cxx          |   22 ++++--
 sc/source/core/tool/recursionhelper.cxx |   44 ++++++++++++
 11 files changed, 213 insertions(+), 28 deletions(-)

New commits:
commit 845e1cdca3349c72e3083186502285d5b776abbe
Author:     Dennis Francis <dennis.francis at collabora.com>
AuthorDate: Wed May 29 10:28:22 2019 +0530
Commit:     Dennis Francis <dennis.francis at collabora.com>
CommitDate: Tue Oct 1 18:10:09 2019 +0200

    Thread a group of formula-groups together if possible
    
    Just before about to thread a FG, look to left and right for
    "mutually" independent FG's with some restrictions and thread
    this group of FG's together treating it as a single but longer
    computation load.
    
    For now the restrictions are :-
    All formula-groups in a FG "group" must have :-
    
    1. Same length
    2. Same relative position.
    3. Same weight.
    
    This is very helpful in cases similar to the below :
    There are lots of (say 32) consecutive formula-groups
    all with same "small" length (say 8) and same weight.
    By conventional formula-group-threading the speed-up is
    limited to 8x even if we have a 256 core processor, but
    with this threading-multiple-formula-groups patch
    (in this case) we can get a speed-up of 256x provided
    we have a >= 256 core machine. So effectively with this
    patch the speed-up is now only limited to the number of
    cells in a range consisting of mutually indepdendent
    formula-groups rather than number of cells in each
    formula-group.
    
    Change-Id: Ib25b5abbb583fa207e8befff9a908d14313f3d51
    Reviewed-on: https://gerrit.libreoffice.org/79485
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 78272c7f4f3b..3b7ffbe645e1 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -593,7 +593,8 @@ public:
 #endif
     void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen );
 
-    void CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal );
+    void CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, size_t nOffset,
+                            unsigned nThisThread, unsigned nThreadsTotal );
     void HandleStuffAfterParallelCalculation( SCROW nRow, size_t nLen );
 
     void SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 9ac4bca15288..2b2ae8d99c0c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2148,8 +2148,8 @@ public:
      */
     void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen );
 
-    const ScDocumentThreadSpecific& CalculateInColumnInThread( ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
-    void HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen );
+    const ScDocumentThreadSpecific& CalculateInColumnInThread( ScInterpreterContext& rContext, const ScRange& rCalcRange, unsigned nThisThread, unsigned nThreadsTotal);
+    void HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen, SCTAB nTab );
 
     /**
      * Transfer a series of contiguous cell values from specified position to
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index fe421508ea18..65a3a4af7733 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -146,7 +146,7 @@ private:
     ScFormulaCell( const ScFormulaCell& ) = delete;
 
     bool CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow,
-                                  SCROW nStartOffset, SCROW nEndOffset);
+                                  SCROW nStartOffset, SCROW nEndOffset, bool bCalcDependencyOnly = false);
     bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope& aScope,
                                         bool& bDependencyComputed,
                                         bool& bDependencyCheckFailed,
diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx
index 9fb2bc3993c5..c7598fef8cdc 100644
--- a/sc/inc/interpretercontext.hxx
+++ b/sc/inc/interpretercontext.hxx
@@ -28,7 +28,8 @@ struct ScLookupCacheMap;
 // SetNumberFormat() is not thread-safe, so calls to it need to be delayed to the main thread.
 struct DelayedSetNumberFormat
 {
-    SCROW mRow; // Used only with formula groups, so column and tab do not need to be stored.
+    SCROW mCol;
+    SCROW mRow;
     sal_uInt32 mnNumberFormat;
 };
 
diff --git a/sc/inc/recursionhelper.hxx b/sc/inc/recursionhelper.hxx
index 2a72be7b9d76..5962f11eb61a 100644
--- a/sc/inc/recursionhelper.hxx
+++ b/sc/inc/recursionhelper.hxx
@@ -25,6 +25,7 @@
 #include <list>
 #include <vector>
 #include <stack>
+#include <unordered_set>
 
 class ScFormulaCell;
 
@@ -59,7 +60,9 @@ class ScRecursionHelper
     bool                                bDoingRecursion;
     bool                                bInIterationReturn;
     bool                                bConverging;
+    bool                                bGroupsIndependent;
     std::vector< ScFormulaCell* >       aTemporaryGroupCells;
+    std::unordered_set< ScFormulaCellGroup* >* pFGSet;
 
     void Init();
     void ResetIteration();
@@ -111,6 +114,12 @@ public:
 
     void AddTemporaryGroupCell(ScFormulaCell* cell);
     void CleanTemporaryGroupCells();
+
+    void SetFormulaGroupSet(std::unordered_set<ScFormulaCellGroup*>* pSet) { pFGSet = pSet; }
+    bool HasFormulaGroupSet() { return pFGSet != nullptr; }
+    bool CheckFGIndependence(ScFormulaCellGroup* pFG);
+    void SetGroupsIndependent(bool bSet) { bGroupsIndependent = bSet; }
+    bool AreGroupsIndependent() { return bGroupsIndependent; }
 };
 
 /** A class to wrap ScRecursionHelper::PushFormulaGroup(),
@@ -136,6 +145,19 @@ public:
     ~ScFormulaGroupDependencyComputeGuard();
 };
 
+class ScCheckIndependentFGGuard
+{
+    ScRecursionHelper& mrRecHelper;
+    bool mbUsedFGSet;
+public:
+    ScCheckIndependentFGGuard() = delete;
+    ScCheckIndependentFGGuard(ScRecursionHelper& rRecursionHelper,
+                              std::unordered_set<ScFormulaCellGroup*>* pSet);
+    ~ScCheckIndependentFGGuard();
+
+    bool AreGroupsIndependent();
+};
+
 #endif // INCLUDED_SC_INC_RECURSIONHELPER_HXX
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index b3ea9016725e..78bfa854e33d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1012,8 +1012,9 @@ public:
 
     void SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen );
 
-    void CalculateInColumnInThread( ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal);
-    void HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen);
+    void CalculateInColumnInThread( ScInterpreterContext& rContext, SCCOL nColStart, SCCOL nColEnd,
+                                    SCROW nRowStart, SCROW nRowEnd, unsigned nThisThread, unsigned nThreadsTotal);
+    void HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen);
 
     /**
      * Either start all formula cells as listeners unconditionally, or start
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 613107696561..c0fcc103b676 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2930,7 +2930,8 @@ void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLe
     }
 }
 
-void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, size_t nOffset,
+                                  unsigned nThisThread, unsigned nThreadsTotal)
 {
     assert(GetDoc()->IsThreadedGroupCalcInProgress());
 
@@ -2953,7 +2954,7 @@ void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, si
 
     for (size_t i = 0; i < nLen; ++i, ++itCell)
     {
-        if (nThreadsTotal > 0 && (i % nThreadsTotal) != nThisThread)
+        if (nThreadsTotal > 0 && ((i + nOffset) % nThreadsTotal) != nThisThread)
             continue;
 
         ScFormulaCell& rCell = **itCell;
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
index 2c1fd4ec00bd..d7fff9711e0e 100644
--- a/sc/source/core/data/documen8.cxx
+++ b/sc/source/core/data/documen8.cxx
@@ -410,9 +410,9 @@ void ScDocument::SetFormulaResults( const ScAddress& rTopPos, const double* pRes
     pTab->SetFormulaResults(rTopPos.Col(), rTopPos.Row(), pResults, nLen);
 }
 
-const ScDocumentThreadSpecific& ScDocument::CalculateInColumnInThread( ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+const ScDocumentThreadSpecific& ScDocument::CalculateInColumnInThread( ScInterpreterContext& rContext, const ScRange& rCalcRange, unsigned nThisThread, unsigned nThreadsTotal)
 {
-    ScTable* pTab = FetchTable(rTopPos.Tab());
+    ScTable* pTab = FetchTable(rCalcRange.aStart.Tab());
     if (!pTab)
         return maNonThreaded;
 
@@ -420,7 +420,7 @@ const ScDocumentThreadSpecific& ScDocument::CalculateInColumnInThread( ScInterpr
 
     maThreadSpecific.pContext = &rContext;
     ScDocumentThreadSpecific::SetupFromNonThreadedData(maNonThreaded);
-    pTab->CalculateInColumnInThread(rContext, rTopPos.Col(), rTopPos.Row(), nLen, nThisThread, nThreadsTotal);
+    pTab->CalculateInColumnInThread(rContext, rCalcRange.aStart.Col(), rCalcRange.aEnd.Col(), rCalcRange.aStart.Row(), rCalcRange.aEnd.Row(), nThisThread, nThreadsTotal);
 
     assert(IsThreadedGroupCalcInProgress());
     maThreadSpecific.pContext = nullptr;
@@ -428,18 +428,18 @@ const ScDocumentThreadSpecific& ScDocument::CalculateInColumnInThread( ScInterpr
     return maThreadSpecific;
 }
 
-void ScDocument::HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen )
+void ScDocument::HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen, SCTAB nTab )
 {
     assert(!IsThreadedGroupCalcInProgress());
     for( const DelayedSetNumberFormat& data : GetNonThreadedContext().maDelayedSetNumberFormat)
-        SetNumberFormat( ScAddress( rTopPos.Col(), data.mRow, rTopPos.Tab()), data.mnNumberFormat );
+        SetNumberFormat( ScAddress( data.mCol, data.mRow, nTab ), data.mnNumberFormat );
     GetNonThreadedContext().maDelayedSetNumberFormat.clear();
 
-    ScTable* pTab = FetchTable(rTopPos.Tab());
+    ScTable* pTab = FetchTable(nTab);
     if (!pTab)
         return;
 
-    pTab->HandleStuffAfterParallelCalculation(rTopPos.Col(), rTopPos.Row(), nLen);
+    pTab->HandleStuffAfterParallelCalculation(nColStart, nColEnd, nRow, nLen);
 }
 
 void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 628e5ac3a7ba..78fd4a7a734c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -74,6 +74,7 @@
 #include <memory>
 #include <map>
 #include <vector>
+#include <unordered_set>
 
 using namespace formula;
 
@@ -1516,6 +1517,9 @@ bool ScFormulaCell::Interpret(SCROW nStartOffset, SCROW nEndOffset)
     ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
     bool bGroupInterpreted = false;
 
+    if (mxGroup && !rRecursionHelper.CheckFGIndependence(mxGroup.get()))
+        return bGroupInterpreted;
+
     static ForceCalculationType forceType = ScCalcConfig::getForceCalculationType();
     TemporaryCellGroupMaker cellGroupMaker( this, forceType != ForceCalculationNone && forceType != ForceCalculationCore );
 
@@ -2109,7 +2113,7 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
                     // SetNumberFormat() is not thread-safe (modifies ScAttrArray), delay the work
                     // to the main thread. Since thread calculations operate on formula groups,
                     // it's enough to store just the row.
-                    DelayedSetNumberFormat data = { aPos.Row(), nFormatIndex };
+                    DelayedSetNumberFormat data = { aPos.Col(), aPos.Row(), nFormatIndex };
                     rContext.maDelayedSetNumberFormat.push_back( data );
                 }
                 bChanged = true;
@@ -4606,12 +4610,20 @@ bool ScFormulaCell::InterpretFormulaGroup(SCROW nStartOffset, SCROW nEndOffset)
     return false;
 }
 
-bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow, SCROW nStartOffset, SCROW nEndOffset)
+bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow,
+                                             SCROW nStartOffset, SCROW nEndOffset,
+                                             bool bCalcDependencyOnly)
 {
     ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
     // iterate over code in the formula ...
     // ensure all input is pre-calculated -
     // to avoid writing during the calculation
+    if (bCalcDependencyOnly)
+    {
+        ScFormulaGroupDependencyComputeGuard aDepComputeGuard(rRecursionHelper);
+        ScDependantsCalculator aCalculator(*pDocument, *pCode, *this, mxGroup->mpTopCell->aPos, fromFirstRow, nStartOffset, nEndOffset);
+        return aCalculator.DoIt();
+    }
 
     bool bOKToParallelize = false;
     {
@@ -4652,6 +4664,61 @@ bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rSco
     return true;
 }
 
+static SCCOL lcl_probeLeftOrRightFGs(const ScFormulaCellGroupRef& xGroup, const ScDocument& rDoc,
+                                     std::unordered_set<ScFormulaCellGroup*>& rFGSet,
+                                     std::map<SCCOL, ScFormulaCell*>& rFGMap, bool bLeft)
+{
+    const SCROW nLen = xGroup->mnLength;
+    const sal_Int32 nWt = xGroup->mnWeight;
+    ScAddress aAddr(xGroup->mpTopCell->aPos);
+
+    SCCOL nColRet = aAddr.Col();
+
+    const SCCOL nMaxCol = rDoc.GetAllocatedColumnsCount(aAddr.Tab()) - 1;
+    if (bLeft)
+        --nColRet;
+    else
+        ++nColRet;
+
+    while (nColRet >= 0 && nColRet <= nMaxCol)
+    {
+        aAddr.SetCol(nColRet);
+        const ScFormulaCell* pCell = rDoc.GetFormulaCell(aAddr);
+        if (!pCell)
+            break;
+
+        if (!pCell->NeedsInterpret())
+            break;
+
+        const ScFormulaCellGroupRef& xNGroup = pCell->GetCellGroup();
+        if (!xNGroup)
+            break;
+
+        if (xNGroup->mpTopCell->aPos.Row() != aAddr.Row())
+            break;
+
+        const SCROW nNLen = xNGroup->mnLength;
+        const sal_Int32 nNWt = pCell->GetWeight();
+        if (nNLen != nLen || nNWt != nWt)
+            break;
+
+        rFGSet.insert(xNGroup.get());
+        rFGMap[nColRet] = xNGroup->mpTopCell;
+
+        if (bLeft)
+            --nColRet;
+        else
+            ++nColRet;
+    }
+
+    if (bLeft)
+        ++nColRet;
+    else
+        --nColRet;
+
+    return nColRet;
+}
+
 // To be called only from InterpretFormulaGroup().
 bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope& aScope,
                                                    bool& bDependencyComputed,
@@ -4685,6 +4752,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
             ScDocument* mpDocument;
             ScInterpreterContext* mpContext;
             const ScAddress& mrTopPos;
+            SCCOL const mnStartCol;
+            SCCOL const mnEndCol;
             SCROW const mnStartOffset;
             SCROW const mnEndOffset;
 
@@ -4695,6 +4764,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
                      ScDocument* pDocument2,
                      ScInterpreterContext* pContext,
                      const ScAddress& rTopPos,
+                     SCCOL nStartCol,
+                     SCCOL nEndCol,
                      SCROW nStartOff,
                      SCROW nEndOff) :
                 comphelper::ThreadTask(rTag),
@@ -4703,6 +4774,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
                 mpDocument(pDocument2),
                 mpContext(pContext),
                 mrTopPos(rTopPos),
+                mnStartCol(nStartCol),
+                mnEndCol(nEndCol),
                 mnStartOffset(nStartOff),
                 mnEndOffset(nEndOff)
             {
@@ -4710,8 +4783,9 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
 
             virtual void doWork() override
             {
-                ScAddress aStartPos(mrTopPos.Col(), mrTopPos.Row() + mnStartOffset, mrTopPos.Tab());
-                mpDocument->CalculateInColumnInThread(*mpContext, aStartPos, mnEndOffset - mnStartOffset + 1, mnThisThread, mnThreadsTotal);
+                ScRange aCalcRange(mnStartCol, mrTopPos.Row() + mnStartOffset, mrTopPos.Tab(),
+                                   mnEndCol, mrTopPos.Row() + mnEndOffset, mrTopPos.Tab());
+                mpDocument->CalculateInColumnInThread(*mpContext, aCalcRange, mnThisThread, mnThreadsTotal);
                 ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(mpDocument->maNonThreaded);
             }
 
@@ -4726,6 +4800,37 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
             nThreadCount /= 2;
 
         SAL_INFO("sc.threaded", "Running " << nThreadCount << " threads");
+
+        std::unordered_set<ScFormulaCellGroup*> aFGSet;
+        std::map<SCCOL, ScFormulaCell*> aFGMap;
+        aFGSet.insert(mxGroup.get());
+
+        ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
+        SCCOL nColStart = aPos.Col();
+        SCCOL nColEnd = nColStart;
+        if (!rRecursionHelper.HasFormulaGroupSet() && pDocument->IsInDocShellRecalc())
+        {
+            nColStart = lcl_probeLeftOrRightFGs(mxGroup, *pDocument, aFGSet, aFGMap, true);
+            nColEnd = lcl_probeLeftOrRightFGs(mxGroup, *pDocument, aFGSet, aFGMap, false);
+        }
+
+        if (nColStart != nColEnd)
+        {
+            ScCheckIndependentFGGuard aGuard(rRecursionHelper, &aFGSet);
+            for (SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
+            {
+                if (nCurrCol == aPos.Col())
+                    continue;
+
+                bool bFGOK = aFGMap[nCurrCol]->CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset, true);
+                if (!bFGOK || !aGuard.AreGroupsIndependent())
+                {
+                    nColEnd = nColStart = aPos.Col();
+                    break;
+                }
+            }
+        }
+
         {
             assert(!pDocument->IsThreadedGroupCalcInProgress());
             pDocument->SetThreadedGroupCalcInProgress(true);
@@ -4742,7 +4847,7 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
                 context = aContextGetterGuard.GetInterpreterContextForThreadIdx(i);
                 ScDocument::SetupFromNonThreadedContext(*context, i);
                 rThreadPool.pushTask(std::make_unique<Executor>(aTag, i, nThreadCount, pDocument, context, mxGroup->mpTopCell->aPos,
-                                                                nStartOffset, nEndOffset));
+                                                                nColStart, nColEnd, nStartOffset, nEndOffset));
             }
 
             SAL_INFO("sc.threaded", "Waiting for threads to finish work");
@@ -4765,7 +4870,7 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
         ScAddress aStartPos(mxGroup->mpTopCell->aPos);
         SCROW nSpanLen = nEndOffset - nStartOffset + 1;
         aStartPos.SetRow(aStartPos.Row() + nStartOffset);
-        pDocument->HandleStuffAfterParallelCalculation(aStartPos, nSpanLen);
+        pDocument->HandleStuffAfterParallelCalculation(nColStart, nColEnd, aStartPos.Row(), nSpanLen, aStartPos.Tab());
 
         return true;
     }
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 27d6fb0fab22..69e0d7ac9713 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2468,19 +2468,29 @@ void ScTable::SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults,
     aCol[nCol].SetFormulaResults(nRow, pResults, nLen);
 }
 
-void ScTable::CalculateInColumnInThread( ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal)
+void ScTable::CalculateInColumnInThread( ScInterpreterContext& rContext,
+                                         SCCOL nColStart, SCCOL nColEnd,
+                                         SCROW nRowStart, SCROW nRowEnd,
+                                         unsigned nThisThread, unsigned nThreadsTotal)
 {
-    if (!ValidCol(nCol))
+    if (!ValidCol(nColStart) || !ValidCol(nColEnd))
         return;
 
-    aCol[nCol].CalculateInThread( rContext, nRow, nLen, nThisThread, nThreadsTotal );
+    size_t nLen = nRowEnd - nRowStart + 1;
+    size_t nOffset = 0;
+    for (SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
+    {
+        aCol[nCurrCol].CalculateInThread( rContext, nRowStart, nLen, nOffset, nThisThread, nThreadsTotal );
+        nOffset += nLen;
+    }
 }
 
-void ScTable::HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen)
+void ScTable::HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen)
 {
-    assert(ValidCol(nCol));
+    assert(ValidCol(nColStart) && ValidCol(nColEnd));
 
-    aCol[nCol].HandleStuffAfterParallelCalculation( nRow, nLen );
+    for (SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
+        aCol[nCurrCol].HandleStuffAfterParallelCalculation( nRow, nLen );
 }
 
 #if DUMP_COLUMN_STORAGE
diff --git a/sc/source/core/tool/recursionhelper.cxx b/sc/source/core/tool/recursionhelper.cxx
index 1375048759e8..4bd819a12b75 100644
--- a/sc/source/core/tool/recursionhelper.cxx
+++ b/sc/source/core/tool/recursionhelper.cxx
@@ -29,6 +29,8 @@ void ScRecursionHelper::ResetIteration()
 
 ScRecursionHelper::ScRecursionHelper()
 {
+    pFGSet = nullptr;
+    bGroupsIndependent = true;
     Init();
 }
 
@@ -172,6 +174,17 @@ void ScRecursionHelper::CleanTemporaryGroupCells()
     }
 }
 
+bool ScRecursionHelper::CheckFGIndependence(ScFormulaCellGroup* pFG)
+{
+    if (pFGSet && pFGSet->count(pFG))
+    {
+        bGroupsIndependent = false;
+        return false;
+    }
+
+    return true;
+}
+
 ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper& rRecursionHelper, ScFormulaCell* pCell) :
     mrRecHelper(rRecursionHelper)
 {
@@ -201,4 +214,35 @@ ScFormulaGroupDependencyComputeGuard::~ScFormulaGroupDependencyComputeGuard()
     mrRecHelper.DecDepComputeLevel();
 }
 
+ScCheckIndependentFGGuard::ScCheckIndependentFGGuard(ScRecursionHelper& rRecursionHelper,
+                                                     std::unordered_set<ScFormulaCellGroup*>* pSet) :
+    mrRecHelper(rRecursionHelper),
+    mbUsedFGSet(false)
+{
+    if (!mrRecHelper.HasFormulaGroupSet())
+    {
+        mrRecHelper.SetFormulaGroupSet(pSet);
+        mrRecHelper.SetGroupsIndependent(true);
+        mbUsedFGSet = true;
+    }
+}
+
+ScCheckIndependentFGGuard::~ScCheckIndependentFGGuard()
+{
+    if (mbUsedFGSet)
+    {
+        // Reset to defaults.
+        mrRecHelper.SetFormulaGroupSet(nullptr);
+        mrRecHelper.SetGroupsIndependent(true);
+    }
+}
+
+bool ScCheckIndependentFGGuard::AreGroupsIndependent()
+{
+    if (!mbUsedFGSet)
+        return false;
+
+    return mrRecHelper.AreGroupsIndependent();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list