diff options
author | Luke Deller <luke@deller.id.au> | 2021-04-09 09:08:37 +1000 |
---|---|---|
committer | Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de> | 2022-01-21 09:15:09 +0100 |
commit | 74d6225836b910b7b71d552c433352c9de5db329 (patch) | |
tree | 173a9969959d6361aad58fe4ba1c39fa5bc2541d /sw/source/core/layout | |
parent | Update .gitreview (diff) | |
download | core-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.cxx | 59 |
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(); |