summaryrefslogtreecommitdiffstats
path: root/sw/source/core/layout
diff options
context:
space:
mode:
authorLuke Deller <luke@deller.id.au>2021-04-09 09:08:37 +1000
committerSamuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>2022-01-21 09:15:09 +0100
commit74d6225836b910b7b71d552c433352c9de5db329 (patch)
tree173a9969959d6361aad58fe4ba1c39fa5bc2541d /sw/source/core/layout
parentUpdate .gitreview (diff)
downloadcore-74d6225836b910b7b71d552c433352c9de5db329.tar.gz
core-74d6225836b910b7b71d552c433352c9de5db329.zip
tdf#141556 Fix 100% CPU usage in Writer idle loop
Do not interrupt the idle layout processing unnecessarily, because if it is continually interrupted before making enough progress then it will keep resuming at the same page, never finishing, constantly using CPU. This is achieved with two changes: - Revert "tdf#123583 use TaskStopwatch for Writer Idle loop" (commit 383032c50a3e3354f04200ce984a47ab9d2c5c67) which introduced a stopwatch timer to interrupt idle processing every 50ms. This reversion restores the previous behaviour where idle processing is interrupted only when there is an input event. - Filter out TIMER events so that they do not interrupt the idle loop; this fixes both tdf#123583 and tdf#141556 Conflicts: sw/source/core/inc/layact.hxx sw/source/core/layout/layact.cxx Change-Id: Ic989631e5f32199209d64b66b72059253fc0167a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113825 Tested-by: Jenkins Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 0fedac18214a6025401c4c426466a5166553e8ec) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114944 (cherry picked from commit b33148071ae6256845352f8625e58b1ab95be41c)
Diffstat (limited to 'sw/source/core/layout')
-rw-r--r--sw/source/core/layout/layact.cxx59
1 files changed, 32 insertions, 27 deletions
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index abac3364efd2..d5efa7680fd6 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -89,6 +89,13 @@ void SwLayAction::CheckWaitCursor()
}
}
+// Time over already?
+inline void SwLayAction::CheckIdleEnd()
+{
+ if ( !IsInput() )
+ m_bInput = bool(GetInputType()) && Application::AnyInput( GetInputType() );
+}
+
void SwLayAction::SetStatBar( bool bNew )
{
if ( bNew )
@@ -246,19 +253,19 @@ void SwLayAction::PaintContent( const SwContentFrame *pCnt,
}
}
-SwLayAction::SwLayAction(SwRootFrame *pRt, SwViewShellImp *pI, TaskStopwatch* pWatch)
- : m_pRoot(pRt),
+SwLayAction::SwLayAction( SwRootFrame *pRt, SwViewShellImp *pI ) :
+ m_pRoot( pRt ),
m_pImp( pI ),
- m_pWatch(pWatch),
m_pOptTab( nullptr ),
m_nPreInvaPage( USHRT_MAX ),
m_nStartTicks( std::clock() ),
+ m_nInputType( VclInputFlags::NONE ),
m_nEndPage( USHRT_MAX ),
m_nCheckPageNum( USHRT_MAX )
{
m_bPaintExtraData = ::IsExtraData( m_pImp->GetShell()->GetDoc() );
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+ m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle = m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = m_bActionInProgress = false;
// init new flag <mbFormatContentOnInterrupt>.
mbFormatContentOnInterrupt = false;
@@ -273,18 +280,14 @@ SwLayAction::~SwLayAction()
m_pImp->m_pLayAction = nullptr; // unregister
}
-bool SwLayAction::IsInterrupt()
-{
- return m_bInterrupt || (m_pWatch && m_pWatch->exceededRuntime());
-}
-
void SwLayAction::Reset()
{
m_pOptTab = nullptr;
m_nStartTicks = std::clock();
+ m_nInputType = VclInputFlags::NONE;
m_nEndPage = m_nPreInvaPage = m_nCheckPageNum = USHRT_MAX;
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+ m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle = m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = false;
}
@@ -443,7 +446,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
IDocumentLayoutAccess& rLayoutAccess = m_pRoot->GetFormat()->getIDocumentLayoutAccess();
bool bNoLoop = pPage && SwLayouter::StartLoopControl( m_pRoot->GetFormat()->GetDoc(), pPage );
sal_uInt16 nPercentPageNum = 0;
- while ((!IsInterrupt() && pPage) || (m_nCheckPageNum != USHRT_MAX))
+ while ( (pPage && !IsInterrupt()) || m_nCheckPageNum != USHRT_MAX )
{
// note: this is the only place that consumes and resets m_nCheckPageNum
if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
@@ -567,7 +570,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
pPage->InvalidateFlyLayout();
pPage->InvalidateFlyContent();
if ( IsBrowseActionStop() )
- m_bInterrupt = true;
+ m_bInput = true;
}
}
if( bNoLoop )
@@ -585,8 +588,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
pPage->ValidateFlyLayout();
pPage->ValidateFlyContent();
}
-
- if (!IsInterrupt())
+ if ( !IsInterrupt() )
{
SetNextCycle( false );
@@ -627,8 +629,8 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
if( bNoLoop )
rLayoutAccess.GetLayouter()->LoopControl( pPage );
}
+ CheckIdleEnd();
}
-
if ( !pPage && !IsInterrupt() &&
(m_pRoot->IsSuperfluous() || m_pRoot->IsAssertFlyPages()) )
{
@@ -654,7 +656,6 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
}
-
if ( IsInterrupt() && pPage )
{
// If we have input, we don't want to format content anymore, but
@@ -683,7 +684,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
// set flag for interrupt content formatting
- mbFormatContentOnInterrupt = IsInterrupt();
+ mbFormatContentOnInterrupt = IsInput();
long nBottom = rVis.Bottom();
// #i42586# - format current page, if idle action is active
// This is an optimization for the case that the interrupt is created by
@@ -777,6 +778,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
bool SwLayAction::TurboAction_( const SwContentFrame *pCnt )
{
+
const SwPageFrame *pPage = nullptr;
if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() || pCnt->IsRetouche() )
{
@@ -837,7 +839,10 @@ bool SwLayAction::TurboAction()
if ( m_pRoot->GetTurbo() )
{
if ( !TurboAction_( m_pRoot->GetTurbo() ) )
+ {
+ CheckIdleEnd();
bRet = false;
+ }
m_pRoot->ResetTurbo();
}
else
@@ -1683,6 +1688,7 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
// paragraph has been processed.
if (!pTab || !bInValid)
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
( !bBrowse && pPage->IsInvalidLayout() ) ||
@@ -1775,6 +1781,7 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
PaintContent( pContent, pPage, pContent->getFrameArea(), pContent->getFrameArea().Bottom());
if ( IsIdle() )
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return false;
@@ -1870,6 +1877,7 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame *pFly )
// If there's input, we interrupt processing.
if ( !pFly->IsFlyInContentFrame() )
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return;
@@ -1879,11 +1887,6 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame *pFly )
CheckWaitCursor();
}
-bool SwLayIdle::IsInterrupt()
-{
- return m_aWatch.exceededRuntime();
-}
-
bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
{
OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
@@ -1967,7 +1970,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
bPageValid = bPageValid && (SwTextNode::WrongState::TODO != pTextNode->GetWrongDirty());
if ( aRepaint.HasArea() )
pImp->GetShell()->InvalidateWindows( aRepaint );
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
}
@@ -1975,7 +1978,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
// note: bPageValid remains true here even if the cursor
// position is skipped, so no PENDING state needed currently
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
case WORD_COUNT :
@@ -1983,7 +1986,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
const sal_Int32 nEnd = pTextNode->GetText().getLength();
SwDocStat aStat;
pTextNode->CountWords( aStat, 0, nEnd );
- if (IsInterrupt())
+ if ( Application::AnyInput() )
return true;
break;
}
@@ -1998,7 +2001,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
// handle smarttag problems gracefully and provide diagnostics
SAL_WARN( "sw.core", "SMART_TAGS: " << e);
}
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
}
@@ -2190,7 +2193,9 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
bool bInterrupt(false);
{
- SwLayAction aAction(pRoot, pImp, &m_aWatch);
+ SwLayAction aAction( pRoot, pImp );
+ aAction.SetInputType( VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER) );
+ aAction.SetIdle( true );
aAction.SetWaitAllowed( false );
aAction.Action(pImp->GetShell()->GetOut());
bInterrupt = aAction.IsInterrupt();