sw/inc/IDocumentTimerAccess.hxx                 |    4 ++++
 sw/inc/doc.hxx                                  |    2 +-
 sw/qa/extras/tiledrendering/tiledrendering2.cxx |   11 ++++++++++-
 sw/source/core/doc/DocumentTimerManager.cxx     |   10 ++++++++++
 sw/source/core/inc/DocumentTimerManager.hxx     |    2 ++
 5 files changed, 27 insertions(+), 2 deletions(-)

New commits:
commit 8278384498d4a02559c81884c0ffe763b9facc1b
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Apr 29 15:04:42 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Apr 30 10:31:25 2025 +0200

    cool#11785 sw lok: only start idling after the idle jobs timer stopped
    
    Open a 300 pages document with simple content, the load itself only
    takes ~100 ms, but the time between the end of load and start of
    rendering tiles is a lot more than that:
    debug:32053:31994: lo_documentLoadWithOptions: end @ 2092810770
    debug:32053:31994: DocumentTimerManager::DoIdleJobs: finished in 3152 ms
    debug:32053:31994: doc_paintPartTile: start @ 2092814038 -> 3268 ms
    
    Looking at the flamegraph in the issue shows that we start processing
    idle jobs, part of that is sw::DocumentTimerManager::DoIdleJobs(). That
    used to do ~no layout work since layout was fully done as part of
    document load before commit bba965b655a9181c07e5cfb6d3a59363e49e650b
    (cool#11064 sw lok: allow specifying the visible area during doc load,
    2025-02-13). Now some layout can be done on idle, and as part of that we
    call SpellCheckerDispatcher::isValid(), which takes a lot of time, and
    is not interrupted as a tile request comes in.
    
    Fix the problem by extending the delay effort of commit
    349748e63c698076bb44f75da9eaa104489e959c (sw lok: delay processing idle
    jobs to let LOK finish initialization, 2018-12-03), which already had a
    1s delay of idle jobs, but it didn't work, because
    sw::DocumentTimerManager::StartIdling() is also called from e.g.
    SwRootFrame::SetIdleFlags(), so the idle jobs still started. Now we
    explicitly don't start idling till m_aFireIdleJobsTimer is active
    (started, but not yet invoked).
    
    With this, the first tiles are rendered much faster after load:
    debug:14058:13996: lo_documentLoadWithOptions: end @ 2095914924
    debug:14058:13996: doc_paintPartTile: start @ 2095915224 -> 300 ms
    This also means that two tests now don't get idle jobs done after
    Scheduler::ProcessEventsToIdle() (and this is wanted by default), so
    explicitly stop m_aFireIdleJobsTimer in those tests to be able to assert
    what would happen after waiting for long enough.
    
    Change-Id: I8398dc7687d8ac0858f804e687593c5cb7c4e47b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184809
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/inc/IDocumentTimerAccess.hxx b/sw/inc/IDocumentTimerAccess.hxx
index 5cfb1a3ecc41..6ccb4c7efc14 100644
--- a/sw/inc/IDocumentTimerAccess.hxx
+++ b/sw/inc/IDocumentTimerAccess.hxx
@@ -19,6 +19,8 @@
 
 #pragma once
 
+class Timer;
+
 /**
  * Handle the background jobs of a Writer document.
  *
@@ -69,6 +71,8 @@ public:
      */
     virtual bool IsIdlingBlocked() const = 0;
 
+    virtual Timer& GetFireIdleJobsTimer() = 0;
+
 protected:
     virtual ~IDocumentTimerAccess(){};
 };
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 8e599232aedb..837359fbffaf 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -547,7 +547,7 @@ public:
     // IDocumentTimerAccess
     // Our own 'IdleTimer' calls the following method
     IDocumentTimerAccess const & getIDocumentTimerAccess() const;
-    IDocumentTimerAccess & getIDocumentTimerAccess();
+    SW_DLLPUBLIC IDocumentTimerAccess & getIDocumentTimerAccess();
 
     // IDocumentChartDataProviderAccess
     IDocumentChartDataProviderAccess const & 
getIDocumentChartDataProviderAccess() const;
diff --git a/sw/qa/extras/tiledrendering/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index e94293d66246..50a3e18a8a68 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -191,7 +191,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAsyncLayout)
     CPPUNIT_ASSERT(pPage2->IsInvalidContent());
     CPPUNIT_ASSERT(pPage3->IsInvalidContent());
 
-    // And then processing all idle events:
+    // And when processing all idle events:
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentTimerAccess& rIDTA = pDoc->getIDocumentTimerAccess();
+    rIDTA.GetFireIdleJobsTimer().Stop();
+    rIDTA.StartIdling();
     Scheduler::ProcessEventsToIdle();
 
     // Then make sure all pages get an async layout:
@@ -731,6 +735,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCommentsOnLoad)
     // When getting the list of comments from the document + listening for 
notifications from idle
     // layout:
     pXTextDocument->getPostIts(aWriter);
+    SwDocShell* pDocShell = getSwDocShell();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentTimerAccess& rIDTA = pDoc->getIDocumentTimerAccess();
+    rIDTA.GetFireIdleJobsTimer().Stop();
+    rIDTA.StartIdling();
     Scheduler::ProcessEventsToIdle();
 
     // Then make sure that:
diff --git a/sw/source/core/doc/DocumentTimerManager.cxx 
b/sw/source/core/doc/DocumentTimerManager.cxx
index df232238eca0..c24b2204fb66 100644
--- a/sw/source/core/doc/DocumentTimerManager.cxx
+++ b/sw/source/core/doc/DocumentTimerManager.cxx
@@ -56,6 +56,11 @@ DocumentTimerManager::DocumentTimerManager(SwDoc& i_rSwdoc)
 
 void DocumentTimerManager::StartIdling()
 {
+    if (m_aFireIdleJobsTimer.IsActive())
+    {
+        return;
+    }
+
     if (m_bWaitForLokInit && comphelper::LibreOfficeKit::isActive())
     {
         // Start the idle jobs only after a certain delay.
@@ -102,6 +107,11 @@ void DocumentTimerManager::UnblockIdling()
     }
 }
 
+Timer& DocumentTimerManager::GetFireIdleJobsTimer()
+{
+    return m_aFireIdleJobsTimer;
+}
+
 IMPL_LINK(DocumentTimerManager, FireIdleJobsTimeout, Timer*, , void)
 {
     // Now we can run the idle jobs, assuming we finished LOK initialization.
diff --git a/sw/source/core/inc/DocumentTimerManager.hxx 
b/sw/source/core/inc/DocumentTimerManager.hxx
index d22852b910bb..20a9cd83a222 100644
--- a/sw/source/core/inc/DocumentTimerManager.hxx
+++ b/sw/source/core/inc/DocumentTimerManager.hxx
@@ -57,6 +57,8 @@ public:
 
     bool IsIdlingBlocked() const override;
 
+    Timer& GetFireIdleJobsTimer() override;
+
 private:
     DocumentTimerManager(DocumentTimerManager const&) = delete;
     DocumentTimerManager& operator=(DocumentTimerManager const&) = delete;

Reply via email to