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