constellation: Use one image cache thread pool in the single-process mode (#38783)

Previously, each ScriptThread was creating a new image cache with a
separate thread pool. These changes add an image cache to the
constellation and create new image caches by calling the
`create_new_image_cache` method. It reuses the original image cache's
thread pool and reduces the number of spawned threads in the
single-process mode.

Testing: Tested manually, using `ps -M` to see the number of spawned
threads with multiple tabs open in servoshell before and after these
changes.
Fixes: #37770

Signed-off-by: Rodion Borovyk <rodion.borovyk@gmail.com>
This commit is contained in:
Rodion Borovyk 2025-09-12 14:35:26 +02:00 committed by GitHub
parent 23ac24438a
commit 4aabc67e57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 30 additions and 7 deletions

View file

@ -147,6 +147,8 @@ use keyboard_types::{Key, KeyState, Modifiers, NamedKey};
use layout_api::{LayoutFactory, ScriptThreadFactory}; use layout_api::{LayoutFactory, ScriptThreadFactory};
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use media::WindowGLContext; use media::WindowGLContext;
use net::image_cache::ImageCacheImpl;
use net_traits::image_cache::ImageCache;
use net_traits::pub_domains::reg_host; use net_traits::pub_domains::reg_host;
use net_traits::request::Referrer; use net_traits::request::Referrer;
use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use net_traits::storage_thread::{StorageThreadMsg, StorageType};
@ -486,6 +488,9 @@ pub struct Constellation<STF, SWF> {
/// A list of URLs that can access privileged internal APIs. /// A list of URLs that can access privileged internal APIs.
privileged_urls: Vec<ServoUrl>, privileged_urls: Vec<ServoUrl>,
/// The image cache for the single-process mode
image_cache: Box<dyn ImageCache>,
} }
/// State needed to construct a constellation. /// State needed to construct a constellation.
@ -684,7 +689,7 @@ where
compositor_receiver, compositor_receiver,
layout_factory, layout_factory,
embedder_proxy: state.embedder_proxy, embedder_proxy: state.embedder_proxy,
compositor_proxy: state.compositor_proxy, compositor_proxy: state.compositor_proxy.clone(),
webviews: WebViewManager::default(), webviews: WebViewManager::default(),
devtools_sender: state.devtools_sender, devtools_sender: state.devtools_sender,
#[cfg(feature = "bluetooth")] #[cfg(feature = "bluetooth")]
@ -731,12 +736,16 @@ where
active_keyboard_modifiers: Modifiers::empty(), active_keyboard_modifiers: Modifiers::empty(),
hard_fail, hard_fail,
active_media_session: None, active_media_session: None,
rippy_data, rippy_data: rippy_data.clone(),
user_content_manager: state.user_content_manager, user_content_manager: state.user_content_manager,
process_manager: ProcessManager::new(state.mem_profiler_chan), process_manager: ProcessManager::new(state.mem_profiler_chan),
async_runtime: state.async_runtime, async_runtime: state.async_runtime,
script_join_handles: Default::default(), script_join_handles: Default::default(),
privileged_urls: state.privileged_urls, privileged_urls: state.privileged_urls,
image_cache: Box::new(ImageCacheImpl::new(
state.compositor_proxy.cross_process_compositor_api,
rippy_data,
)),
}; };
constellation.run(); constellation.run();
@ -1014,6 +1023,10 @@ where
rippy_data: self.rippy_data.clone(), rippy_data: self.rippy_data.clone(),
user_content_manager: self.user_content_manager.clone(), user_content_manager: self.user_content_manager.clone(),
privileged_urls: self.privileged_urls.clone(), privileged_urls: self.privileged_urls.clone(),
image_cache: self.image_cache.create_new_image_cache(
Some(pipeline_id),
self.compositor_proxy.cross_process_compositor_api.clone(),
),
}); });
let pipeline = match result { let pipeline = match result {

View file

@ -212,6 +212,9 @@ pub struct InitialPipelineState {
/// A list of URLs that can access privileged internal APIs. /// A list of URLs that can access privileged internal APIs.
pub privileged_urls: Vec<ServoUrl>, pub privileged_urls: Vec<ServoUrl>,
/// The image cache for the single-process mode
pub image_cache: Arc<dyn ImageCache>,
} }
pub struct NewPipeline { pub struct NewPipeline {
@ -338,6 +341,7 @@ impl Pipeline {
false, false,
state.layout_factory, state.layout_factory,
register, register,
Some(state.image_cache),
); );
(None, None, Some(join_handle)) (None, None, Some(join_handle))
}; };
@ -517,15 +521,20 @@ impl UnprivilegedPipelineContent {
wait_for_completion: bool, wait_for_completion: bool,
layout_factory: Arc<dyn LayoutFactory>, layout_factory: Arc<dyn LayoutFactory>,
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
image_cache: Option<Arc<dyn ImageCache>>,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
// Setup pipeline-namespace-installing for all threads in this process. // Setup pipeline-namespace-installing for all threads in this process.
// Idempotent in single-process mode. // Idempotent in single-process mode.
PipelineNamespace::set_installer_sender(self.namespace_request_sender); PipelineNamespace::set_installer_sender(self.namespace_request_sender);
let image_cache = Arc::new(ImageCacheImpl::new( let image_cache = image_cache.unwrap_or_else(|| {
// Create a new image cache (in the multiprocess case)
Arc::new(ImageCacheImpl::new(
self.cross_process_compositor_api.clone(), self.cross_process_compositor_api.clone(),
self.rippy_data, self.rippy_data,
)); ))
});
let (content_process_shutdown_chan, content_process_shutdown_port) = unbounded(); let (content_process_shutdown_chan, content_process_shutdown_port) = unbounded();
let join_handle = STF::create( let join_handle = STF::create(
InitialScriptState { InitialScriptState {
@ -542,7 +551,7 @@ impl UnprivilegedPipelineContent {
#[cfg(feature = "bluetooth")] #[cfg(feature = "bluetooth")]
bluetooth_sender: self.bluetooth_thread, bluetooth_sender: self.bluetooth_thread,
resource_threads: self.resource_threads, resource_threads: self.resource_threads,
image_cache: image_cache.clone(), image_cache,
time_profiler_sender: self.time_profiler_chan.clone(), time_profiler_sender: self.time_profiler_chan.clone(),
memory_profiler_sender: self.mem_profiler_chan.clone(), memory_profiler_sender: self.mem_profiler_chan.clone(),
devtools_server_sender: self.devtools_ipc_sender, devtools_server_sender: self.devtools_ipc_sender,

View file

@ -1289,6 +1289,7 @@ pub fn run_content_process(token: String) {
true, true,
layout_factory, layout_factory,
background_hang_monitor_register, background_hang_monitor_register,
None,
); );
// Since wait_for_completion is true, // Since wait_for_completion is true,