summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Francis <dennis.francis@collabora.com>2019-05-29 10:28:22 +0530
committerDennis Francis <dennis.francis@collabora.com>2019-10-01 18:10:09 +0200
commit845e1cdca3349c72e3083186502285d5b776abbe (patch)
treea4496df89f4b7f21a1ab98c3e672b9d75d1a52e2
parent1028841feb815dfcfee97422f3de1e06e48db580 (diff)
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@collabora.com>
-rw-r--r--sc/inc/column.hxx3
-rw-r--r--sc/inc/document.hxx4
-rw-r--r--sc/inc/formulacell.hxx2
-rw-r--r--sc/inc/interpretercontext.hxx3
-rw-r--r--sc/inc/recursionhelper.hxx22
-rw-r--r--sc/inc/table.hxx5
-rw-r--r--sc/source/core/data/column2.cxx5
-rw-r--r--sc/source/core/data/documen8.cxx14
-rw-r--r--sc/source/core/data/formulacell.cxx117
-rw-r--r--sc/source/core/data/table1.cxx22
-rw-r--r--sc/source/core/tool/recursionhelper.cxx44
11 files changed, 213 insertions, 28 deletions
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: */