Rebased ref, commits from common ancestor: commit b3e943b465cc5e4165e03d803c1eb27fa9827610 Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Fri Nov 17 15:30:35 2017 +0530
Move token-cache for doubles to ScInterpreterContext... ...from ScInterpreter and in the s/w interpreter, create a ScInterpreterContext for each thread for passing into per thread ScInterpreter constructor. Change-Id: I4e0abce043c7e1e70859efb2e5001fc284f416a9 diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 44bee716bf18..acd899e7658a 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -583,7 +583,7 @@ public: void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen ); void SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - void CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal ); + void CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, 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 8b138378dda3..c4db749eab6a 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -458,6 +458,8 @@ private: // plain thread_local static member. thread_local static ScDocumentThreadSpecific maThreadSpecific; + mutable ScInterpreterContext maInterpreterContext; + sal_uInt16 nSrcVer; // file version (load/save) sal_uInt16 nFormulaTrackCount; HardRecalcState eHardRecalcState; // off, temporary, eternal @@ -560,10 +562,11 @@ public: SC_DLLPUBLIC void InitDrawLayer( SfxObjectShell* pDocShell = nullptr ); - ScInterpreterContext GetNonThreadedContext() const + ScInterpreterContext& GetNonThreadedContext() const { // GetFormatTable() asserts that we are not in a threaded calculation - return ScInterpreterContext(*this, GetFormatTable()); + maInterpreterContext.mpFormatter = GetFormatTable(); + return maInterpreterContext; } SC_DLLPUBLIC sfx2::LinkManager* GetLinkManager(); @@ -2056,7 +2059,7 @@ public: void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen ); void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - ScDocumentThreadSpecific CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); + ScDocumentThreadSpecific CalculateInColumnInThread( ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); void HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen ); /** diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 0185e2629010..e75416de8e56 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -150,7 +150,7 @@ public: SCITP_FROM_ITERATION, SCITP_CLOSE_ITERATION_CIRCLE }; - void InterpretTail( const ScInterpreterContext&, ScInterpretTailParameter ); + void InterpretTail( ScInterpreterContext&, ScInterpretTailParameter ); void HandleStuffAfterParallelCalculation(); diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx index cbf05349ca5f..ff52267dfb26 100644 --- a/sc/inc/interpretercontext.hxx +++ b/sc/inc/interpretercontext.hxx @@ -10,6 +10,11 @@ #ifndef INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX #define INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX +#include <vector> +#include <formula/token.hxx> + +#define TOKEN_CACHE_SIZE 8 + class ScDocument; class SvNumberFormatter; @@ -17,15 +22,22 @@ struct ScInterpreterContext { const ScDocument& mrDoc; SvNumberFormatter* mpFormatter; + size_t mnTokenCachePos; + std::vector<formula::FormulaToken*> maTokens; ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter) : mrDoc(rDoc), - mpFormatter(pFormatter) + mpFormatter(pFormatter), + mnTokenCachePos(0), + maTokens(TOKEN_CACHE_SIZE, nullptr) { } ~ScInterpreterContext() { + for ( auto p : maTokens ) + if ( p ) + p->DecRef(); } SvNumberFormatter* GetFormatTable() const diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 1f77ae4d2e39..3721e2226a5a 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -998,7 +998,7 @@ public: void SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen ); void SetFormulaResults( SCCOL nCol, SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - void CalculateInColumnInThread( const ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); + void CalculateInColumnInThread( ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); void HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen); /** diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index daeda62bd881..fea8d080dd13 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2877,7 +2877,7 @@ void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRe } } -void ScColumn::CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) +void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) { assert(pDocument->mbThreadedGroupCalcInProgress); diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index b15ee591a7e2..9bf0fcf73194 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -177,6 +177,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) : nInterpretLevel(0), nMacroInterpretLevel(0), nInterpreterTableOpLevel(0), + maInterpreterContext( *this, nullptr ), nSrcVer( SC_CURRENT_VERSION ), nFormulaTrackCount(0), eHardRecalcState(HardRecalcState::OFF), diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx index 8bf1de3fb191..c7be637fb073 100644 --- a/sc/source/core/data/documen8.cxx +++ b/sc/source/core/data/documen8.cxx @@ -427,7 +427,7 @@ void ScDocument::SetFormulaResults( pTab->SetFormulaResults(rTopPos.Col(), rTopPos.Row(), pResults, nLen); } -ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) +ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) { ScTable* pTab = FetchTable(rTopPos.Tab()); if (!pTab) diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index f90e83cb6c06..dde15e97ad0e 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1750,7 +1750,7 @@ class StackCleaner }; } -void ScFormulaCell::InterpretTail( const ScInterpreterContext& rContext, ScInterpretTailParameter eTailParam ) +void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTailParameter eTailParam ) { RecursionCounter aRecursionCounter( pDocument->GetRecursionHelper(), this); nSeenInIteration = pDocument->GetRecursionHelper().GetIteration(); diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index e43ab0efc7ac..0b23c7474e91 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2338,7 +2338,7 @@ void ScTable::SetFormulaResults( aCol[nCol].SetFormulaResults(nRow, pResults, nLen); } -void ScTable::CalculateInColumnInThread( const ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) +void ScTable::CalculateInColumnInThread( ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) { if (!ValidCol(nCol)) return; diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index a6eaf5cd78ae..d6a77f2b9c1a 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -97,7 +97,6 @@ class SharedStringPool; } #define MAXSTACK (4096 / sizeof(formula::FormulaToken*)) -#define TOKEN_CACHE_SIZE 8 class ScTokenStack { @@ -200,7 +199,7 @@ private: formula::FormulaTokenIterator aCode; ScAddress aPos; ScTokenArray& rArr; - const ScInterpreterContext& mrContext; + ScInterpreterContext& mrContext; ScDocument* pDok; sfx2::LinkManager* mpLinkManager; svl::SharedStringPool& mrStrPool; @@ -230,8 +229,6 @@ private: bool bMatrixFormula; // formula cell is a matrix formula VolatileType meVolatileType; - size_t mnTokenCachePos; - std::vector<formula::FormulaToken*> maTokenCache; /// Merge global and document specific settings. void MergeCalcConfig(); @@ -994,7 +991,7 @@ private: double GetTInv( double fAlpha, double fSize, int nType ); public: - ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, const ScInterpreterContext& rContext, + ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, ScInterpreterContext& rContext, const ScAddress&, ScTokenArray& ); ~ScInterpreter(); diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 326392f6099e..3acc38d68051 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -155,6 +155,7 @@ public: ScAddress aBatchTopPos, const ScAddress& rTopPos, ScDocument& rDoc, + SvNumberFormatter* pFormatter, std::vector<formula::FormulaConstTokenRef>& rRes, SCROW nIndex, SCROW nLastIndex) : @@ -162,6 +163,7 @@ public: maBatchTopPos(aBatchTopPos), mrTopPos(rTopPos), mrDoc(rDoc), + mpFormatter(pFormatter), mrResults(rRes), mnIdx(nIndex), mnLastIdx(nLastIndex) @@ -296,7 +298,8 @@ public: ScCompiler aComp(&mrDoc, maBatchTopPos, aCode2); aComp.CompileTokenArray(); - ScInterpreter aInterpreter(pDest, &mrDoc, mrDoc.GetNonThreadedContext(), maBatchTopPos, aCode2); + ScInterpreterContext aContext(mrDoc, mpFormatter); + ScInterpreter aInterpreter(pDest, &mrDoc, aContext, maBatchTopPos, aCode2); aInterpreter.Interpret(); mrResults[i] = aInterpreter.GetResultToken(); } // Row iteration for loop end @@ -307,6 +310,7 @@ private: ScAddress maBatchTopPos; const ScAddress& mrTopPos; ScDocument& mrDoc; + SvNumberFormatter* mpFormatter; std::vector<formula::FormulaConstTokenRef>& mrResults; SCROW mnIdx; SCROW mnLastIdx; @@ -333,11 +337,12 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres ScAddress aBatchTopPos, const ScAddress& rTopPos2, ScDocument& rDoc2, + SvNumberFormatter* pFormatter2, std::vector<formula::FormulaConstTokenRef>& rRes, SCROW nIndex, SCROW nLastIndex) : comphelper::ThreadTask(rTag), - maSWIFunc(rCode2, aBatchTopPos, rTopPos2, rDoc2, rRes, nIndex, nLastIndex) + maSWIFunc(rCode2, aBatchTopPos, rTopPos2, rDoc2, pFormatter2, rRes, nIndex, nLastIndex) { } virtual void doWork() override @@ -353,6 +358,8 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres bool bUseThreading = !bThreadingProhibited && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get(); + SvNumberFormatter* pFormatter = rDoc.GetNonThreadedContext().GetFormatTable(); + if (bUseThreading) { comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool()); @@ -381,7 +388,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres if ( nRemaining ) --nRemaining; SCROW nLast = nStart + nCount - 1; - rThreadPool.pushTask(new Executor(aTag, rCode, aTmpPos, rTopPos, rDoc, aResults, nStart, nLast)); + rThreadPool.pushTask(new Executor(aTag, rCode, aTmpPos, rTopPos, rDoc, pFormatter, aResults, nStart, nLast)); aTmpPos.IncRow(nCount); nLeft -= nCount; nStart = nLast + 1; @@ -392,7 +399,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres } else { - SoftwareInterpreterFunc aSWIFunc(rCode, aTmpPos, rTopPos, rDoc, aResults, 0, xGroup->mnLength - 1); + SoftwareInterpreterFunc aSWIFunc(rCode, aTmpPos, rTopPos, rDoc, pFormatter, aResults, 0, xGroup->mnLength - 1); aSWIFunc(); } diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 106e3b6f3403..ec9f9fb0e16c 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -1730,15 +1730,13 @@ void ScInterpreter::QueryMatrixType(const ScMatrixRef& xMat, short& rRetTypeExpr formula::FormulaToken* ScInterpreter::CreateFormulaDoubleToken( double fVal, short nFmt ) { - if ( maTokenCache.size() != TOKEN_CACHE_SIZE ) - maTokenCache.resize( TOKEN_CACHE_SIZE ); + assert( mrContext.maTokens.size() == TOKEN_CACHE_SIZE ); // Find a spare token - for ( auto p : maTokenCache ) + for ( auto p : mrContext.maTokens ) { if (p && p->GetRef() == 1) { - p->IncRef(); p->GetDoubleAsReference() = fVal; p->SetDoubleType( nFmt ); return p; @@ -1747,12 +1745,11 @@ formula::FormulaToken* ScInterpreter::CreateFormulaDoubleToken( double fVal, sho // Allocate a new token auto p = new FormulaTypedDoubleToken( fVal, nFmt ); - size_t pos = (mnTokenCachePos++) % TOKEN_CACHE_SIZE; - if ( maTokenCache[pos] ) - maTokenCache[pos]->DecRef(); - maTokenCache[pos] = p; + if ( mrContext.maTokens[mrContext.mnTokenCachePos] ) + mrContext.maTokens[mrContext.mnTokenCachePos]->DecRef(); + mrContext.maTokens[mrContext.mnTokenCachePos] = p; p->IncRef(); - + mrContext.mnTokenCachePos = (mrContext.mnTokenCachePos + 1) % TOKEN_CACHE_SIZE; return p; } @@ -3810,7 +3807,7 @@ void ScInterpreter::ScTTT() PushError(FormulaError::NoValue); } -ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, const ScInterpreterContext& rContext, +ScInterpreter::ScInterpreter( ScFormulaCell* pCell, ScDocument* pDoc, ScInterpreterContext& rContext, const ScAddress& rPos, ScTokenArray& r ) : aCode(r) , aPos(rPos) @@ -3870,11 +3867,6 @@ ScInterpreter::~ScInterpreter() else delete pStackObj; delete pTokenMatrixMap; - - for ( auto p : maTokenCache ) - if ( p && p->GetRef() == 1 ) - p->DecRef(); - } ScCalcConfig& ScInterpreter::GetOrCreateGlobalConfig() commit 5ab9b543269070e41d021c24e2b552a13b9fae37 Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Fri Nov 17 14:05:56 2017 +0530 Type check the tokens before reuse If the exisiting token is of wrong type, create and use a fresh new token instead. Change-Id: I348b0972306497dfe7eae0655c9b93d5830cb740 diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index e77554d89805..326392f6099e 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -206,13 +206,26 @@ public: if ( !pTargetTok ) aCode2.AddString(rPool.intern(OUString(pStr))); else - pTargetTok->SetString(rPool.intern(OUString(pStr))); + { + if ( pTargetTok->GetType() == formula::svString ) + pTargetTok->SetString(rPool.intern(OUString(pStr))); + else + { + formula::FormulaStringToken* pStrTok = new formula::FormulaStringToken(rPool.intern(OUString(pStr))); + aCode2.ReplaceToken(nTokIdx, pStrTok, formula::FormulaTokenArray::CODE_ONLY); + } + } } else if (rtl::math::isNan(fVal)) { // Value of NaN represents an empty cell. if ( !pTargetTok ) aCode2.AddToken(ScEmptyCellToken(false, false)); + else if ( pTargetTok->GetType() != formula::svEmptyCell ) + { + ScEmptyCellToken* pEmptyTok = new ScEmptyCellToken(false, false); + aCode2.ReplaceToken(nTokIdx, pEmptyTok, formula::FormulaTokenArray::CODE_ONLY); + } } else { @@ -220,7 +233,15 @@ public: if ( !pTargetTok ) aCode2.AddDouble(fVal); else - pTargetTok->GetDoubleAsReference() = fVal; + { + if ( pTargetTok->GetType() == formula::svDouble ) + pTargetTok->GetDoubleAsReference() = fVal; + else + { + formula::FormulaDoubleToken* pDoubleTok = new formula::FormulaDoubleToken( fVal ); + aCode2.ReplaceToken(nTokIdx, pDoubleTok, formula::FormulaTokenArray::CODE_ONLY); + } + } } } break; commit f42dc9786efba0a0f07d745773bfc8bea42f0b88 Author: Eike Rathke <er...@redhat.com> Date: Wed Nov 15 18:08:30 2017 +0100 Assert also new FormulaToken::SetDoubleType() virtual dummy Change-Id: I4532d0329dc7cd2609bc96abba140aba3f3d36f3 diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index 2ed68521e720..07ff7cc59b6e 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -218,7 +218,7 @@ short FormulaToken::GetDoubleType() const void FormulaToken::SetDoubleType( short ) { - SAL_WARN( "formula.core", "FormulaToken::SetDoubleType: virtual dummy called" ); + assert( !"virtual dummy called" ); } svl::SharedString FormulaToken::GetString() const commit dc90516a2e3665a527adcd8a08fcac7795c3e54c Author: Dennis Francis <dennis.fran...@collabora.co.uk> Date: Wed Nov 15 21:08:44 2017 +0530 cache FormulaToken for doubles Change-Id: Ic0b4dff6f03ef3f88bd150e798fa2d83dfb0f486 diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index 04c4a203284d..2ed68521e720 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -216,6 +216,11 @@ short FormulaToken::GetDoubleType() const return 0; } +void FormulaToken::SetDoubleType( short ) +{ + SAL_WARN( "formula.core", "FormulaToken::SetDoubleType: virtual dummy called" ); +} + svl::SharedString FormulaToken::GetString() const { SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" ); @@ -1797,6 +1802,11 @@ short FormulaTypedDoubleToken::GetDoubleType() const return mnType; } +void FormulaTypedDoubleToken::SetDoubleType( short nType ) +{ + mnType = nType; +} + bool FormulaTypedDoubleToken::operator==( const FormulaToken& r ) const { return FormulaDoubleToken::operator==( r ) && mnType == r.GetDoubleType(); diff --git a/include/formula/token.hxx b/include/formula/token.hxx index 9b06ae48182c..3de7c761d658 100644 --- a/include/formula/token.hxx +++ b/include/formula/token.hxx @@ -181,6 +181,7 @@ public: virtual double GetDouble() const; virtual double& GetDoubleAsReference(); virtual short GetDoubleType() const; + virtual void SetDoubleType( short nType ); virtual svl::SharedString GetString() const; virtual void SetString( const svl::SharedString& rStr ); virtual sal_uInt16 GetIndex() const; @@ -321,6 +322,7 @@ public: virtual FormulaToken* Clone() const override { return new FormulaTypedDoubleToken(*this); } virtual short GetDoubleType() const override; + virtual void SetDoubleType( short nType ) override; virtual bool operator==( const FormulaToken& rToken ) const override; DECL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaTypedDoubleToken ) diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 8a240e617261..a6eaf5cd78ae 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -97,6 +97,7 @@ class SharedStringPool; } #define MAXSTACK (4096 / sizeof(formula::FormulaToken*)) +#define TOKEN_CACHE_SIZE 8 class ScTokenStack { @@ -229,6 +230,8 @@ private: bool bMatrixFormula; // formula cell is a matrix formula VolatileType meVolatileType; + size_t mnTokenCachePos; + std::vector<formula::FormulaToken*> maTokenCache; /// Merge global and document specific settings. void MergeCalcConfig(); @@ -395,6 +398,7 @@ private: sc::RangeMatrix PopRangeMatrix(); void QueryMatrixType(const ScMatrixRef& xMat, short& rRetTypeExpr, sal_uLong& rRetIndexExpr); + formula::FormulaToken* CreateFormulaDoubleToken( double fVal, short nFmt = css::util::NumberFormat::NUMBER ); formula::FormulaToken* CreateDoubleOrTypedToken( double fVal ); void PushDouble(double nVal); diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index a95d76b42cf0..106e3b6f3403 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -731,7 +731,7 @@ void ScInterpreter::PushCellResultToken( bool bDisplayEmptyAsString, { TreatDoubleError( fVal); if (!IfErrorPushError()) - PushTempTokenWithoutError( new FormulaDoubleToken( fVal)); + PushTempTokenWithoutError( CreateFormulaDoubleToken( fVal)); } else { @@ -1687,7 +1687,7 @@ void ScInterpreter::QueryMatrixType(const ScMatrixRef& xMat, short& rRetTypeExpr { if ( xMat->IsEmptyPath( 0, 0)) { // result of empty FALSE jump path - FormulaTokenRef xRes = new FormulaDoubleToken( 0.0); + FormulaTokenRef xRes = CreateFormulaDoubleToken( 0.0); PushTempToken( new ScMatrixFormulaCellToken(nCols, nRows, xMat, xRes.get())); rRetTypeExpr = css::util::NumberFormat::LOGICAL; } @@ -1716,7 +1716,7 @@ void ScInterpreter::QueryMatrixType(const ScMatrixRef& xMat, short& rRetTypeExpr if (nErr != FormulaError::NONE) xRes = new FormulaErrorToken( nErr); else - xRes = new FormulaDoubleToken( nMatVal.fVal); + xRes = CreateFormulaDoubleToken( nMatVal.fVal); PushTempToken( new ScMatrixFormulaCellToken(nCols, nRows, xMat, xRes.get())); if ( rRetTypeExpr != css::util::NumberFormat::LOGICAL ) rRetTypeExpr = css::util::NumberFormat::NUMBER; @@ -1728,14 +1728,42 @@ void ScInterpreter::QueryMatrixType(const ScMatrixRef& xMat, short& rRetTypeExpr SetError( FormulaError::UnknownStackVariable); } +formula::FormulaToken* ScInterpreter::CreateFormulaDoubleToken( double fVal, short nFmt ) +{ + if ( maTokenCache.size() != TOKEN_CACHE_SIZE ) + maTokenCache.resize( TOKEN_CACHE_SIZE ); + + // Find a spare token + for ( auto p : maTokenCache ) + { + if (p && p->GetRef() == 1) + { + p->IncRef(); + p->GetDoubleAsReference() = fVal; + p->SetDoubleType( nFmt ); + return p; + } + } + + // Allocate a new token + auto p = new FormulaTypedDoubleToken( fVal, nFmt ); + size_t pos = (mnTokenCachePos++) % TOKEN_CACHE_SIZE; + if ( maTokenCache[pos] ) + maTokenCache[pos]->DecRef(); + maTokenCache[pos] = p; + p->IncRef(); + + return p; +} + formula::FormulaToken* ScInterpreter::CreateDoubleOrTypedToken( double fVal ) { // NumberFormat::NUMBER is the default untyped double. if (nFuncFmtType && nFuncFmtType != css::util::NumberFormat::NUMBER && nFuncFmtType != css::util::NumberFormat::UNDEFINED) - return new FormulaTypedDoubleToken( fVal, nFuncFmtType); + return CreateFormulaDoubleToken( fVal, nFuncFmtType); else - return new FormulaDoubleToken( fVal); + return CreateFormulaDoubleToken( fVal); } void ScInterpreter::PushDouble(double nVal) @@ -3842,6 +3870,11 @@ ScInterpreter::~ScInterpreter() else delete pStackObj; delete pTokenMatrixMap; + + for ( auto p : maTokenCache ) + if ( p && p->GetRef() == 1 ) + p->DecRef(); + } ScCalcConfig& ScInterpreter::GetOrCreateGlobalConfig() @@ -4583,7 +4616,7 @@ StackVar ScInterpreter::Interpret() nRetIndexExpr = 0; // carry format index only for matching type nRetTypeExpr = nFuncFmtType = nCurFmtType; } - PushTempToken( new FormulaDoubleToken( fVal)); + PushTempToken( CreateFormulaDoubleToken( fVal)); } if ( nFuncFmtType == css::util::NumberFormat::UNDEFINED ) { commit 246b97c3daee18bf2fffa8d1d5ffbf3d24129502 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 e0ee5a1827ad..f90e83cb6c06 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 @@ -4408,6 +4411,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 7ab90bd124cb1f2948da9aff214f1cec68433ea0 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 8f3a77c05420dfb1bb22b6fe9a13c596ab7fc261 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 059d0a814d5f2933d7a6508afd4f9aac267ffdff 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 64f8f2ef4d41bcd96b35ef203be5eb9e1de49bab 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 36d4997ba157..e0ee5a1827ad 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 - @@ -4434,26 +4436,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: @@ -4461,6 +4467,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 5349e2d6dff3..2ded45291544 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: ; commit 718e8606714300d7a587b60f17aeb893abcac8f0 Author: Tor Lillqvist <t...@collabora.com> Date: Mon Oct 16 18:40:51 2017 +0300 Add OFFSET to blacklist for threaded calculation Change-Id: Ia1aaf40aa4e8e6f41ca190272365528bf37bf130 diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index b7c73ef7ea3d..5349e2d6dff3 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1341,6 +1341,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) static const std::set<OpCode> aThreadedCalcBlackList({ ocIndirect, ocMacro, + ocOffset, ocTableOp }); commit bfe5b5cb584eae3cecc9826ed16664518f323353 Author: Tor Lillqvist <t...@collabora.com> Date: Mon Oct 16 18:31:07 2017 +0300 Add INDIRECT to blacklist for threaded calculation Change-Id: I9a2066c396802551c3eda2c8db32b6d1a4171dfd diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index a24f41949022..b7c73ef7ea3d 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1339,6 +1339,7 @@ bool ScTokenArray::AddFormulaToken( void ScTokenArray::CheckToken( const FormulaToken& r ) { static const std::set<OpCode> aThreadedCalcBlackList({ + ocIndirect, ocMacro, ocTableOp }); commit b9485ab084e10970ae1da2435aac821444c1eb69 Author: Tor Lillqvist <t...@collabora.com> Date: Mon Oct 16 18:28:24 2017 +0300 Check whether ScTokenArray::CheckToken() has disabled threading of the group Otherwise the aThreadedCalcBlackList check in CheckToken() has no effect, we would still attempt the threaded code path. Change-Id: I08dc2dd174459615ab8a11dbb819e39fc5437d10 diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 44e046c26bcf..36d4997ba157 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -4345,7 +4345,7 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } - if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) + if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && pCode->GetVectorState() != FormulaVectorDisabledNotInSubSet && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) { // iterate over code in the formula ... // ensure all input is pre-calculated - commit bd244800b92572f652edd490ac5f3c5ff429d702 Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 22:55:19 2017 +0300 Avoid unused private field warning in the NDEBUG case Change-Id: I5e37b9a8325af35a15c01409f9eaa2f92459cc28 diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 73f450dc8163..a53258a2fb70 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6747,6 +6747,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl mpDocument(pDocument), mnFlags(nFlags) { + (void) mpDocument; for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++) { if (static_cast<std::size_t>(mnFlags) & (1 << b)) commit 9284ffd0a3711d36ad334ec37b976f036a043839 Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 16:55:59 2017 +0300 Move ScDocument::GetNonThreadedContext() inline Did not have any impact on performance, though. Change-Id: I7e769b4a74e0ff9e0aabfb7e291fc4b987441954 diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index f37e8e7d856e..8b138378dda3 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -560,7 +560,11 @@ public: SC_DLLPUBLIC void InitDrawLayer( SfxObjectShell* pDocShell = nullptr ); - SC_DLLPUBLIC ScInterpreterContext GetNonThreadedContext() const; + ScInterpreterContext GetNonThreadedContext() const + { + // GetFormatTable() asserts that we are not in a threaded calculation + return ScInterpreterContext(*this, GetFormatTable()); + } SC_DLLPUBLIC sfx2::LinkManager* GetLinkManager(); SC_DLLPUBLIC const sfx2::LinkManager* GetLinkManager() const; diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 0df71931c355..73f450dc8163 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6769,13 +6769,6 @@ ScMutationGuard::~ScMutationGuard() #endif } -ScInterpreterContext ScDocument::GetNonThreadedContext() const -{ - // GetFormatTable() asserts that we are not in a threaded calculation - ScInterpreterContext aResult(*this, GetFormatTable()); - return aResult; -} - thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific; ScRecursionHelper& ScDocument::GetRecursionHelper() commit 95a0fce7271e65f2d0d6af1cbd8ee96ccfb6e6cd Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 13:11:10 2017 +0300 Display the threaded calculation state in Help:About Change-Id: I299e555392bb4b09325ad2c92f843b1e12ee4d31 diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx index a7d219407249..c9ba680c8609 100644 --- a/cui/source/dialogs/about.cxx +++ b/cui/source/dialogs/about.cxx @@ -53,6 +53,7 @@ #include <opencl/openclwrapper.hxx> #endif #include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Calc.hxx> using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; @@ -334,19 +335,31 @@ OUString AboutDialog::GetVersionString() sVersion += m_aLocaleStr.replaceAll("$LOCALE", aLocaleStr); } -#if HAVE_FEATURE_OPENCL OUString aCalcMode = "Calc: "; // Calc calculation mode + +#if HAVE_FEATURE_OPENCL bool bSWInterp = officecfg::Office::Common::Misc::UseSwInterpreter::get(); bool bOpenCL = openclwrapper::GPUEnv::isOpenCLEnabled(); if (bOpenCL) aCalcMode += "CL"; else if (bSWInterp) aCalcMode += "group"; - else - aCalcMode += "single"; - sVersion += "; " + aCalcMode; +#else + const bool bOpenCL = false; #endif + static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION"); + bool bThreadedCalc = officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get(); + + if (!bThreadingProhibited && !bOpenCL && bThreadedCalc) + { + if (!aCalcMode.endsWith(" ")) + aCalcMode += " "; + aCalcMode += "threaded"; + } + + sVersion += "; " + aCalcMode; + return sVersion; } commit c5e976e2ad5dda092fb47fbf6e9ee823bc03782a Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 12:40:20 2017 +0300 Make threaded calculation the default (when OpenCL is not used) Introduce a configuration setting to turn it off. For now, can also be turned off with the environment variable SC_NO_THREADED_CALCULATION, but that is probably not something we want to keep or guarantee staility of. (LO looks at way too many environment variables already.) Change-Id: I469cde259eda72cc2d630814a25f707f1210b0ab diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs index b1feca1825c6..72ac33b99413 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs @@ -1416,6 +1416,12 @@ <info> <desc>Contains settings for how to calculate formulae.</desc> </info> + <prop oor:name="UseThreadedCalculationForFormulaGroups" oor:type="xs:boolean" oor:nillable="false"> + <info> + <desc>Whether to use threaded calculation of forumula groups when applicable.</desc> + </info> + <value>true</value> + </prop> <!-- Note: The default values below probably must correspond to those assigned in setOpenCLConfigToDefault() in sc/source/core/tool/calcconfig.cxx diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 2b87393c7d5a..44e046c26bcf 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -54,6 +54,7 @@ #include <svl/intitem.hxx> #include <o3tl/make_unique.hxx> #include <rtl/strbuf.hxx> +#include <officecfg/Office/Calc.hxx> #include <formulagroup.hxx> #include <listenercontext.hxx> #include <types.hxx> @@ -4326,11 +4327,10 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } - static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION"); + static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION"); // To temporarilu use threading for sc unit tests regardless of the size of the formula group, - // add the condition !std::getenv("LO_TESTNAME") below (with &&), and run with - // CPU_THREADED_CALCULATION=yes + // add the condition !std::getenv("LO_TESTNAME") below (with &&) if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize) { mxGroup->meCalcState = sc::GroupCalcDisabled; @@ -4345,7 +4345,7 @@ bool ScFormulaCell::InterpretFormulaGroup() return false; } - if (!ScCalcConfig::isOpenCLEnabled() && bThreadingRequested) + if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) { // iterate over code in the formula ... // ensure all input is pre-calculated - diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 0a586073c7c6..a24f41949022 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -25,6 +25,7 @@ #include <tools/mempool.hxx> #include <osl/diagnose.h> #include <sfx2/docfile.hxx> +#include <officecfg/Office/Calc.hxx> #include <token.hxx> #include <tokenarray.hxx> @@ -1346,11 +1347,11 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) // It's already disabled. No more checking needed. return; - static const bool bThreadingRequested = std::getenv("CPU_THREADED_CALCULATION"); + static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION"); OpCode eOp = r.GetOpCode(); - if (!ScCalcConfig::isOpenCLEnabled() && bThreadingRequested) + if (!bThreadingProhibited && !ScCalcConfig::isOpenCLEnabled() && officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get()) { if (aThreadedCalcBlackList.count(eOp)) { commit 26a9157a4b28e7cf80f2f16bc314b4b4b4a23d8c Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 10:55:13 2017 +0300 Need more ScInterpreterContexts Change-Id: I1dd679156661bb5cb025ca6cb46d19783524d5a4 diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx index 0f513c231327..00f399fab47c 100644 --- a/sc/source/core/tool/interpr6.cxx +++ b/sc/source/core/tool/interpr6.cxx @@ -846,7 +846,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero ) nFuncFmtIndex = aAction.getNumberFormat(); } - nFuncFmtType = pDok->GetFormatTable()->GetType( nFuncFmtIndex ); + nFuncFmtType = mrContext.GetFormatTable()->GetType( nFuncFmtIndex ); } else { commit 39ede542924672c97749147141c924a03dbfa25f Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 08:48:05 2017 +0300 -Werror,-Wunused-parameter Change-Id: If10c6a58f5b6f196f3644f6c592dd6d1dc0d860c diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 62f4baa471c3..0df71931c355 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6794,13 +6794,13 @@ ScRecursionHelper& ScDocument::GetRecursionHelper() } } -void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& rNonThreadedData) +void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& /*rNonThreadedData*/) { // What about the recursion helper? // Copy the lookup cache? } -void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& rNonThreadedData) +void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& /*rNonThreadedData*/) { // What about recursion helper and lookup cache? } commit 034e06f3a8da0e766fc5e7bde88c9fe7b5a11937 Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 08:47:02 2017 +0300 -Werror,-Wsign-compare Change-Id: Ide03e0ae1fe97e1a09a767908a981a1e803a3474 diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index f15107bc3fe7..62f4baa471c3 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6747,7 +6747,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl mpDocument(pDocument), mnFlags(nFlags) { - for (auto b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++) + for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++) { if (static_cast<std::size_t>(mnFlags) & (1 << b)) { @@ -6759,7 +6759,7 @@ ScMutationGuard::ScMutationGuard(ScDocument* pDocument, ScMutationGuardFlags nFl ScMutationGuard::~ScMutationGuard() { #ifndef NDEBUG - for (auto b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++) + for (unsigned b = 0; b < static_cast<std::size_t>(ScMutationGuardFlags::N); b++) { if (static_cast<std::size_t>(mnFlags) & (1 << b)) { commit ada660b44bb44913d880cebc775016aa3ee75fd9 Author: Tor Lillqvist <t...@collabora.com> Date: Wed Oct 4 00:12:31 2017 +0300 Introduce ScInterpreterContext When calculating a formula group in multiple threads in parallel, we need to use separate SvNumberFormatters in the threads. Possibly later also other things that need to be thread-local can be handled through the ScInterpreterContext. Why handle some thread-local things through the ScDocument::maNonThreaded and ScDocument::maThreadSpecific mechanism, and others through this ScInterpreterContext? Good question. Share SvNumberFormatter across worker threads and use mutex to protect SvNumberFormatter::IsNumberFormat() Change-Id: I372e5fbd9a19785f55f0faf4a4bedc5fc1ef3e03 diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 67bc6c348c5e..44bee716bf18 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -106,6 +106,7 @@ class ScDocumentImport; class ScHint; enum class ScMF; struct ScFilterEntries; +struct ScInterpreterContext; struct ScNeededSizeOptions { @@ -447,7 +448,7 @@ public: const ScPatternAttr* GetPattern( SCROW nRow ) const; const ScPatternAttr* GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const; - sal_uInt32 GetNumberFormat( SCROW nRow ) const; + sal_uInt32 GetNumberFormat( const ScInterpreterContext& rContext, SCROW nRow ) const; sal_uInt32 GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const; void MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const; @@ -582,7 +583,7 @@ public: void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen ); void SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - void CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); + void CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal ); void HandleStuffAfterParallelCalculation( SCROW nRow, size_t nLen ); void SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat ); diff --git a/sc/inc/dociter.hxx b/sc/inc/dociter.hxx index 544e64ebc9c1..904f471c3c4f 100644 --- a/sc/inc/dociter.hxx +++ b/sc/inc/dociter.hxx @@ -45,6 +45,7 @@ struct ScQueryParam; struct ScDBQueryParamInternal; struct ScDBQueryParamMatrix; class ScFormulaCell; +struct ScInterpreterContext; class ScValueIterator // walk through all values in an area { @@ -84,7 +85,7 @@ public: ScDocument* pDocument, const ScRange& rRange, SubtotalFlags nSubTotalFlags = SubtotalFlags::NONE, bool bTextAsZero = false ); - void GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ); + void GetCurNumFmtInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex ); /// Does NOT reset rValue if no value found! bool GetFirst( double& rValue, FormulaError& rErr ); @@ -125,7 +126,7 @@ private: { typedef std::pair<sc::CellStoreType::const_iterator,size_t> PositionType; public: - DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc); + DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc, const ScInterpreterContext& rContext); virtual ~DataAccessInternal() override; virtual bool getCurrent(Value& rValue) override; virtual bool getFirst(Value& rValue) override; @@ -139,6 +140,7 @@ private: PositionType maCurPos; ScDBQueryParamInternal* mpParam; ScDocument* mpDoc; + const ScInterpreterContext& mrContext; const ScAttrArray* pAttrArray; sal_uLong nNumFormat; // for CalcAsShown sal_uLong nNumFmtIndex; @@ -171,7 +173,7 @@ private: ::std::unique_ptr<DataAccess> mpData; public: - ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam); + ScDBQueryDataIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, ScDBQueryParamBase* pParam); /// Does NOT reset rValue if no value found! bool GetFirst(Value& rValue); /// Does NOT reset rValue if no value found! @@ -266,6 +268,7 @@ class ScQueryCellIterator // walk through all non-empty cells in an ar std::unique_ptr<ScQueryParam> mpParam; ScDocument* pDoc; + const ScInterpreterContext& mrContext; SCTAB nTab; SCCOL nCol; SCROW nRow; @@ -292,7 +295,7 @@ class ScQueryCellIterator // walk through all non-empty cells in an ar bool BinarySearch(); public: - ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable, + ScQueryCellIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, SCTAB nTable, const ScQueryParam& aParam, bool bMod); // when !bMod, the QueryParam has to be filled // (bIsString) diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index eef7c4c8df07..f37e8e7d856e 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -26,6 +26,7 @@ #include <com/sun/star/uno/Reference.hxx> #include <vcl/vclptr.hxx> #include "scdllapi.h" +#include "interpretercontext.hxx" #include "rangelst.hxx" #include "rangenam.hxx" #include "tabopparams.hxx" @@ -559,6 +560,8 @@ public: SC_DLLPUBLIC void InitDrawLayer( SfxObjectShell* pDocShell = nullptr ); + SC_DLLPUBLIC ScInterpreterContext GetNonThreadedContext() const; + SC_DLLPUBLIC sfx2::LinkManager* GetLinkManager(); SC_DLLPUBLIC const sfx2::LinkManager* GetLinkManager() const; @@ -1111,10 +1114,10 @@ public: SC_DLLPUBLIC void GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt32& rFormat ) const; sal_uInt32 GetNumberFormat( const ScRange& rRange ) const; - SC_DLLPUBLIC sal_uInt32 GetNumberFormat( const ScAddress& ) const; + SC_DLLPUBLIC sal_uInt32 GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& ) const; void SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat ); - void GetNumberFormatInfo( short& nType, sal_uLong& nIndex, const ScAddress& rPos ) const; + void GetNumberFormatInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex, const ScAddress& rPos ) const; SC_DLLPUBLIC const ScFormulaCell* GetFormulaCell( const ScAddress& rPos ) const; SC_DLLPUBLIC ScFormulaCell* GetFormulaCell( const ScAddress& rPos ); SC_DLLPUBLIC void GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const; @@ -2049,7 +2052,7 @@ public: void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen ); void SC_DLLPUBLIC SetFormulaResults( const ScAddress& rTopPos, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - ScDocumentThreadSpecific CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); + ScDocumentThreadSpecific CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); void HandleStuffAfterParallelCalculation( const ScAddress& rTopPos, size_t nLen ); /** diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 40fe21598e28..0185e2629010 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -30,7 +30,7 @@ #include <svl/listener.hxx> #include "types.hxx" - +#include "interpretercontext.hxx" #include "formularesult.hxx" namespace sc { @@ -150,7 +150,7 @@ public: SCITP_FROM_ITERATION, SCITP_CLOSE_ITERATION_CIRCLE }; - void InterpretTail( ScInterpretTailParameter ); + void InterpretTail( const ScInterpreterContext&, ScInterpretTailParameter ); void HandleStuffAfterParallelCalculation(); diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx new file mode 100644 index 000000000000..cbf05349ca5f --- /dev/null +++ b/sc/inc/interpretercontext.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX +#define INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX + +class ScDocument; +class SvNumberFormatter; + +struct ScInterpreterContext +{ + const ScDocument& mrDoc; + SvNumberFormatter* mpFormatter; + + ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter) : + mrDoc(rDoc), + mpFormatter(pFormatter) + { + } + + ~ScInterpreterContext() + { + } + + SvNumberFormatter* GetFormatTable() const + { + return mpFormatter; + } +}; + +#endif // INCLUDED_SC_INC_INTERPRETERCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 9b04a4d019a4..1f77ae4d2e39 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -116,6 +116,7 @@ class ScRangeName; class ScDBData; class ScDocumentImport; class ScHint; +struct ScInterpreterContext; class ScColumnsRange final { @@ -672,7 +673,7 @@ public: const ScPatternAttr* GetPattern( SCCOL nCol, SCROW nRow ) const; const ScPatternAttr* GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const; - sal_uInt32 GetNumberFormat( const ScAddress& rPos ) const; + sal_uInt32 GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const; sal_uInt32 GetNumberFormat( SCCOL nCol, SCROW nRow ) const; sal_uInt32 GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const; @@ -997,7 +998,7 @@ public: void SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen ); void SetFormulaResults( SCCOL nCol, SCROW nRow, const formula::FormulaConstTokenRef* pResults, size_t nLen ); - void CalculateInColumnInThread( SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); + void CalculateInColumnInThread( const ScInterpreterContext& rContext, SCCOL nCol, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal); void HandleStuffAfterParallelCalculation( SCCOL nCol, SCROW nRow, size_t nLen); /** diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index ea93b02156f1..5d021d41aec4 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -418,9 +418,9 @@ sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const return nFormat; } -sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const +sal_uInt32 ScColumn::GetNumberFormat( const ScInterpreterContext& rContext, SCROW nRow ) const { - return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() ); + return pAttrArray->GetPattern( nRow )->GetNumberFormat( rContext.GetFormatTable() ); } SCROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray, bool* const pIsChanged ) @@ -1151,7 +1151,7 @@ void ScColumn::CopyStaticToDocument( // Dont' forget to copy the number formats over. Charts may reference them. for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) { - sal_uInt32 nNumFmt = GetNumberFormat(nRow); + sal_uInt32 nNumFmt = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt); if (itNum != rMap.end()) nNumFmt = itNum->second; @@ -2890,7 +2890,7 @@ public: void operator() (size_t nRow, ScFormulaCell* pCell) { - sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow); + sal_uInt32 nFormat = mrCol.GetNumberFormat(mrCol.GetDoc().GetNonThreadedContext(), nRow); if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0) // Non-default number format is set. pCell->SetNeedNumberFormat(false); diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index aaa897889603..daeda62bd881 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2877,8 +2877,10 @@ void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaConstTokenRe } } -void ScColumn::CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) +void ScColumn::CalculateInThread( const ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) { + assert(pDocument->mbThreadedGroupCalcInProgress); + sc::CellStoreType::position_type aPos = maCells.position(nRow); sc::CellStoreType::iterator it = aPos.first; if (it->type != sc::element_type_formula) @@ -2901,8 +2903,7 @@ void ScColumn::CalculateInThread( SCROW nRow, size_t nLen, unsigned nThisThread, ScFormulaCell& rCell = **itCell; // Here we don't call IncInterpretLevel() and DecInterpretLevel() as this call site is // always in a threaded calculation. - assert(pDocument->mbThreadedGroupCalcInProgress); - rCell.InterpretTail(ScFormulaCell::SCITP_NORMAL); + rCell.InterpretTail(rContext, ScFormulaCell::SCITP_NORMAL); } } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 646210a8e679..9a5a57205436 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1700,7 +1700,7 @@ bool ScColumn::ParseString( if (!aParam.mpNumFormatter) aParam.mpNumFormatter = pDocument->GetFormatTable(); - nIndex = nOldIndex = GetNumberFormat( nRow ); + nIndex = nOldIndex = GetNumberFormat( pDocument->GetNonThreadedContext(), nRow ); if ( rString.getLength() > 1 && aParam.mpNumFormatter->GetType(nIndex) != css::util::NumberFormat::TEXT ) cFirstChar = rString[0]; @@ -1922,7 +1922,7 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form sc::CellStoreType::iterator it = GetPositionToInsert(nRow); ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rArray, eGram); - sal_uInt32 nCellFormat = GetNumberFormat(nRow); + sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) pCell->SetNeedNumberFormat(true); it = maCells.set(it, nRow, pCell); @@ -1939,7 +1939,7 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul sc::CellStoreType::iterator it = GetPositionToInsert(nRow); ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram); - sal_uInt32 nCellFormat = GetNumberFormat(nRow); + sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) pCell->SetNeedNumberFormat(true); it = maCells.set(it, nRow, pCell); @@ -1954,7 +1954,7 @@ ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType ) { sc::CellStoreType::iterator it = GetPositionToInsert(nRow); - sal_uInt32 nCellFormat = GetNumberFormat(nRow); + sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) pCell->SetNeedNumberFormat(true); it = maCells.set(it, nRow, pCell); @@ -1971,7 +1971,7 @@ void ScColumn::SetFormulaCell( sc::StartListeningType eListenType ) { rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); - sal_uInt32 nCellFormat = GetNumberFormat(nRow); + sal_uInt32 nCellFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) pCell->SetNeedNumberFormat(true); rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell); @@ -2002,7 +2002,7 @@ bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells for (size_t i = 0, n = rCells.size(); i < n; ++i) { SCROW nThisRow = nRow + i; - sal_uInt32 nFmt = GetNumberFormat(nThisRow); + sal_uInt32 nFmt = GetNumberFormat(pDocument->GetNonThreadedContext(), nThisRow); if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0) rCells[i]->SetNeedNumberFormat(true); } @@ -2055,7 +2055,7 @@ class FilterEntriesHandler { SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable(); OUString aStr; - sal_uLong nFormat = mrColumn.GetNumberFormat(nRow); + sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow); ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, &mrColumn.GetDoc()); if (rCell.hasString()) @@ -2543,7 +2543,7 @@ void ScColumn::GetString( SCROW nRow, OUString& rString ) const if (aCell.meType == CELLTYPE_FORMULA) aCell.mpFormula->MaybeInterpret(); - sal_uLong nFormat = GetNumberFormat(nRow); + sal_uLong nFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); Color* pColor = nullptr; ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()), pDocument); } @@ -2564,7 +2564,7 @@ double* ScColumn::GetValueCell( SCROW nRow ) void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const { ScRefCellValue aCell = GetCellValue(nRow); - sal_uLong nFormat = GetNumberFormat(nRow); + sal_uLong nFormat = GetNumberFormat(pDocument->GetNonThreadedContext(), nRow); ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()), pDocument); } diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 358774153027..fa7f9dfb8c05 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -262,14 +262,14 @@ bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr) } } -void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) +void ScValueIterator::GetCurNumFmtInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex ) { if (!bNumValid && mnTab < pDoc->GetTableCount()) { SCROW nCurRow = GetRow(); const ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol]; - nNumFmtIndex = pCol->GetNumberFormat(nCurRow); - nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); + nNumFmtIndex = pCol->GetNumberFormat(rContext, nCurRow); + nNumFmtType = rContext.GetFormatTable()->GetType( nNumFmtIndex ); bNumValid = true; } @@ -334,11 +334,12 @@ bool ScDBQueryDataIterator::IsQueryValid( return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell); } -ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc) +ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument* pDoc, const ScInterpreterContext& rContext) : DataAccess() , mpCells(nullptr) , mpParam(pParam) , mpDoc(pDoc) + , mrContext(rContext) , pAttrArray(nullptr) , nNumFormat(0) // Initialized in GetNumberFormat , nNumFmtIndex(0) @@ -432,7 +433,7 @@ bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue) rValue.mfValue = aCell.mpFormula->GetValue(); rValue.mbIsNumber = true; mpDoc->GetNumberFormatInfo( - nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab)); + mrContext, nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab)); rValue.mnError = aCell.mpFormula->GetErrCode(); return true; // Found it! } @@ -744,7 +745,7 @@ ScDBQueryDataIterator::Value::Value() : ::rtl::math::setNan(&mfValue); } -ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) : +ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, ScDBQueryParamBase* pParam) : mpParam (pParam) { switch (mpParam->GetType()) @@ -752,7 +753,7 @@ ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryPar case ScDBQueryParamBase::INTERNAL: { ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam); - mpData.reset(new DataAccessInternal(p, pDocument)); + mpData.reset(new DataAccessInternal(p, pDocument, rContext)); } break; case ScDBQueryParamBase::MATRIX: @@ -1046,10 +1047,11 @@ bool ScCellIterator::next() return getCurrent(); } -ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable, +ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, const ScInterpreterContext& rContext, SCTAB nTable, const ScQueryParam& rParam, bool bMod ) : mpParam(new ScQueryParam(rParam)), pDoc( pDocument ), + mrContext( rContext ), nTab( nTable), nStopOnMismatch( nStopOnMismatchDisabled ), nTestEqualCondition( nTestEqualConditionDisabled ), @@ -1681,7 +1683,7 @@ bool ScQueryCellIterator::BinarySearch() if (aPos.first->type == sc::element_type_string || aPos.first->type == sc::element_type_edittext) { aCell = sc::toRefCell(aPos.first, aPos.second); - sal_uLong nFormat = pCol->GetNumberFormat(nRow); + sal_uLong nFormat = pCol->GetNumberFormat(mrContext, nRow); OUString aCellStr; ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc); sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString()); @@ -1715,7 +1717,7 @@ bool ScQueryCellIterator::BinarySearch() aCell = aCellData.first; if (aCell.hasString()) { - sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second); + sal_uLong nFormat = pCol->GetNumberFormat(mrContext, aCellData.second); OUString aStr; ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter, pDoc); aLastInRangeString = aStr; @@ -1814,7 +1816,7 @@ bool ScQueryCellIterator::BinarySearch() else if (bStr && bByString) { OUString aCellStr; - sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second); + sal_uLong nFormat = pCol->GetNumberFormat(mrContext, aCellData.second); ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc); nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString()); diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 283c082199b2..b15ee591a7e2 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -502,6 +502,7 @@ void ScDocument::InitClipPtrs( ScDocument* pSourceDoc ) SvNumberFormatter* ScDocument::GetFormatTable() const { + assert(!mbThreadedGroupCalcInProgress); return mxPoolHelper->GetFormTable(); } diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx index b29de4004c90..8bf1de3fb191 100644 --- a/sc/source/core/data/documen8.cxx +++ b/sc/source/core/data/documen8.cxx @@ -427,7 +427,7 @@ void ScDocument::SetFormulaResults( pTab->SetFormulaResults(rTopPos.Col(), rTopPos.Row(), pResults, nLen); } -ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) +ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScInterpreterContext& rContext, const ScAddress& rTopPos, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal) { ScTable* pTab = FetchTable(rTopPos.Tab()); if (!pTab) @@ -436,7 +436,7 @@ ScDocumentThreadSpecific ScDocument::CalculateInColumnInThread( const ScAddress& assert(mbThreadedGroupCalcInProgress); maThreadSpecific.SetupFromNonThreadedData(maNonThreaded); - pTab->CalculateInColumnInThread(rTopPos.Col(), rTopPos.Row(), nLen, nThisThread, nThreadsTotal); + pTab->CalculateInColumnInThread(rContext, rTopPos.Col(), rTopPos.Row(), nLen, nThisThread, nThreadsTotal); assert(mbThreadedGroupCalcInProgress); diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 185115ac8ad7..f15107bc3fe7 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -3702,13 +3702,13 @@ sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const return nFormat; } -sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const +sal_uInt32 ScDocument::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const { SCTAB nTab = rPos.Tab(); if (!TableExists(nTab)) return 0; - return maTabs[nTab]->GetNumberFormat( rPos ); + return maTabs[nTab]->GetNumberFormat( rContext, rPos ); } void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat ) @@ -3720,14 +3720,14 @@ void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberForma maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat); } -void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex, +void ScDocument::GetNumberFormatInfo( const ScInterpreterContext& rContext, short& nType, sal_uLong& nIndex, const ScAddress& rPos ) const { SCTAB nTab = rPos.Tab(); if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] ) { - nIndex = maTabs[nTab]->GetNumberFormat( rPos ); - nType = GetFormatTable()->GetType( nIndex ); + nIndex = maTabs[nTab]->GetNumberFormat( rContext, rPos ); + nType = rContext.GetFormatTable()->GetType( nIndex ); } else { @@ -6769,6 +6769,13 @@ ScMutationGuard::~ScMutationGuard() #endif } +ScInterpreterContext ScDocument::GetNonThreadedContext() const +{ + // GetFormatTable() asserts that we are not in a threaded calculation + ScInterpreterContext aResult(*this, GetFormatTable()); + return aResult; +} + thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific; ScRecursionHelper& ScDocument::GetRecursionHelper() diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index bc6fd157e34b..2b87393c7d5a 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1528,10 +1528,10 @@ void ScFormulaCell::Interpret() bool bGroupInterpreted = InterpretFormulaGroup(); aDC.leaveGroup(); if (!bGroupInterpreted) - InterpretTail( SCITP_NORMAL); + InterpretTail( pDocument->GetNonThreadedContext(), SCITP_NORMAL); #else if (!InterpretFormulaGroup()) - InterpretTail( SCITP_NORMAL); + InterpretTail( pDocument->GetNonThreadedContext(), SCITP_NORMAL); #endif pDocument->DecInterpretLevel(); } @@ -1595,8 +1595,8 @@ void ScFormulaCell::Interpret() bResumeIteration = false; // Close circle once. ... etc. - the rest is truncated
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits