From 26f32b11f963f2c551e37cbedba640efb5e794ba Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 24 Nov 2024 15:47:18 +0100 Subject: [PATCH] LibWeb: Avoid expensive Vector filtering in event loop Instead of collecting all documents in a big vector and then filtering the vector (twice!) with remove_all_matching(), we now pass a filter callback to documents_in_this_event_loop_matching() and avoid all the extra shuffling work. Saw this stuff hogging ~20% of CPU time when profiling a WebContent process in the middle of a WPT run. --- Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp | 38 ++++++++++--------- Libraries/LibWeb/HTML/EventLoop/EventLoop.h | 2 + 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index 6d596a0c9de..603119593bd 100644 --- a/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -260,30 +260,28 @@ void EventLoop::update_the_rendering() // FIXME: 1. Let frameTimestamp be eventLoop's last render opportunity time. // FIXME: 2. Let docs be all fully active Document objects whose relevant agent's event loop is eventLoop, sorted arbitrarily except that the following conditions must be met: - auto docs = documents_in_this_event_loop(); - docs.remove_all_matching([&](auto& document) { - return !document->is_fully_active(); - }); - // 3. Filter non-renderable documents: Remove from docs any Document object doc for which any of the following are true: - docs.remove_all_matching([&](auto const& document) { - auto navigable = document->navigable(); - if (!navigable) - return true; + auto docs = documents_in_this_event_loop_matching([&](auto const& document) { + if (!document.is_fully_active()) + return false; // FIXME: doc is render-blocked; // doc's visibility state is "hidden"; - if (document->hidden()) - return true; + if (document.hidden()) + return false; // FIXME: doc's rendering is suppressed for view transitions; or + auto navigable = document.navigable(); + if (!navigable) + return false; + // doc's node navigable doesn't currently have a rendering opportunity. if (!navigable->has_a_rendering_opportunity()) - return true; + return false; - return false; + return true; }); // FIXME: 4. Unnecessary rendering: Remove from docs any Document object doc for which all of the following are true: @@ -515,18 +513,25 @@ void EventLoop::perform_a_microtask_checkpoint() // FIXME: 8. Record timing info for microtask checkpoint. } -Vector> EventLoop::documents_in_this_event_loop() const +Vector> EventLoop::documents_in_this_event_loop_matching(auto callback) const { Vector> documents; for (auto& document : m_documents) { VERIFY(document); if (document->is_decoded_svg()) continue; + if (!callback(*document)) + continue; documents.append(GC::make_root(*document)); } return documents; } +Vector> EventLoop::documents_in_this_event_loop() const +{ + return documents_in_this_event_loop_matching([](auto&) { return true; }); +} + void EventLoop::register_document(Badge, DOM::Document& document) { m_documents.append(&document); @@ -568,9 +573,8 @@ void EventLoop::unregister_environment_settings_object(Badge> EventLoop::same_loop_windows() const { Vector> windows; - for (auto& document : documents_in_this_event_loop()) { - if (document->is_fully_active()) - windows.append(GC::make_root(document->window())); + for (auto& document : documents_in_this_event_loop_matching([](auto& document) { return document.is_fully_active(); })) { + windows.append(GC::make_root(document->window())); } return windows; } diff --git a/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index 0da37deb25e..2e27eaa142e 100644 --- a/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -95,6 +95,8 @@ private: virtual void visit_edges(Visitor&) override; + [[nodiscard]] Vector> documents_in_this_event_loop_matching(auto callback) const; + void update_the_rendering(); Type m_type { Type::Window };