mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
net: Report memory usage for image cache. (#36556)
These changes add a new report for image cache memory usage for each script thread. Testing: Looked at the numbers after browsing various stock photo sites that show galleries of images. Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
f16f625c9b
commit
afe98e9e1e
6 changed files with 49 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4900,6 +4900,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"percent-encoding",
|
||||
"pixels",
|
||||
"profile_traits",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"servo_arc",
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::cell::{LazyCell, RefCell};
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::c_void;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{mem, thread};
|
||||
|
||||
|
@ -11,6 +13,8 @@ use compositing_traits::{CrossProcessCompositorApi, SerializableImageData};
|
|||
use imsz::imsz_from_reader;
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use log::{debug, warn};
|
||||
use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
use net_traits::image_cache::{
|
||||
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponder, ImageResponse,
|
||||
PendingImageId, UsePlaceholder,
|
||||
|
@ -18,6 +22,8 @@ use net_traits::image_cache::{
|
|||
use net_traits::request::CorsSettings;
|
||||
use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
|
||||
use pixels::{CorsStatus, Image, ImageMetadata, PixelFormat, load_from_memory};
|
||||
use profile_traits::mem::{Report, ReportKind};
|
||||
use profile_traits::path;
|
||||
use servo_config::pref;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use webrender_api::units::DeviceIntSize;
|
||||
|
@ -98,6 +104,7 @@ type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
|
|||
|
||||
// Represents all the currently pending loads/decodings. For
|
||||
// performance reasons, loads are indexed by a dedicated load key.
|
||||
#[derive(MallocSizeOf)]
|
||||
struct AllPendingLoads {
|
||||
// The loads, indexed by a load key. Used during most operations,
|
||||
// for performance reasons.
|
||||
|
@ -180,6 +187,7 @@ enum CacheResult<'a> {
|
|||
/// Images that fail to load (due to network or decode
|
||||
/// failure) are still stored here, so that they aren't
|
||||
/// fetched again.
|
||||
#[derive(MallocSizeOf)]
|
||||
struct CompletedLoad {
|
||||
image_response: ImageResponse,
|
||||
id: PendingImageId,
|
||||
|
@ -197,9 +205,10 @@ struct DecoderMsg {
|
|||
image: Option<Image>,
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
enum ImageBytes {
|
||||
InProgress(Vec<u8>),
|
||||
Complete(Arc<Vec<u8>>),
|
||||
Complete(#[conditional_malloc_size_of] Arc<Vec<u8>>),
|
||||
}
|
||||
|
||||
impl ImageBytes {
|
||||
|
@ -234,6 +243,7 @@ impl ImageBytes {
|
|||
// A key used to communicate during loading.
|
||||
type LoadKey = PendingImageId;
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
struct LoadKeyGenerator {
|
||||
counter: u64,
|
||||
}
|
||||
|
@ -257,6 +267,7 @@ enum LoadResult {
|
|||
|
||||
/// Represents an image that is either being loaded
|
||||
/// by the resource thread, or decoded by a worker thread.
|
||||
#[derive(MallocSizeOf)]
|
||||
struct PendingLoad {
|
||||
/// The bytes loaded so far. Reset to an empty vector once loading
|
||||
/// is complete and the buffer has been transmitted to the decoder.
|
||||
|
@ -315,6 +326,7 @@ impl PendingLoad {
|
|||
// ======================================================================
|
||||
// Image cache implementation.
|
||||
// ======================================================================
|
||||
#[derive(MallocSizeOf)]
|
||||
struct ImageCacheStore {
|
||||
// Images that are loading over network, or decoding.
|
||||
pending_loads: AllPendingLoads,
|
||||
|
@ -323,12 +335,14 @@ struct ImageCacheStore {
|
|||
completed_loads: HashMap<ImageKey, CompletedLoad>,
|
||||
|
||||
// The placeholder image used when an image fails to load
|
||||
#[conditional_malloc_size_of]
|
||||
placeholder_image: Arc<Image>,
|
||||
|
||||
// The URL used for the placeholder image
|
||||
placeholder_url: ServoUrl,
|
||||
|
||||
// Cross-process compositor API instance.
|
||||
#[ignore_malloc_size_of = "Channel from another crate"]
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
}
|
||||
|
||||
|
@ -439,6 +453,22 @@ impl ImageCache for ImageCacheImpl {
|
|||
}
|
||||
}
|
||||
|
||||
fn memory_report(&self, prefix: &str) -> Report {
|
||||
let seen_pointer =
|
||||
move |ptr| SEEN_POINTERS.with(|pointers| !pointers.borrow_mut().insert(ptr));
|
||||
let mut ops = MallocSizeOfOps::new(
|
||||
servo_allocator::usable_size,
|
||||
None,
|
||||
Some(Box::new(seen_pointer)),
|
||||
);
|
||||
let size = self.store.lock().unwrap().size_of(&mut ops);
|
||||
Report {
|
||||
path: path![prefix, "image-cache"],
|
||||
kind: ReportKind::ExplicitSystemHeapSize,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_image(
|
||||
&self,
|
||||
url: ServoUrl,
|
||||
|
@ -641,3 +671,7 @@ impl ImageCacheImpl {
|
|||
warn!("Couldn't find cached entry for listener {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static SEEN_POINTERS: LazyCell<RefCell<HashSet<*const c_void>>> = const {
|
||||
LazyCell::new(|| RefCell::new(HashSet::new()))
|
||||
});
|
||||
|
|
|
@ -2435,11 +2435,14 @@ impl ScriptThread {
|
|||
let documents = self.documents.borrow();
|
||||
let urls = itertools::join(documents.iter().map(|(_, d)| d.url().to_string()), ", ");
|
||||
|
||||
let mut reports = self.get_cx().get_reports(format!("url({})", urls));
|
||||
let prefix = format!("url({urls})");
|
||||
let mut reports = self.get_cx().get_reports(prefix.clone());
|
||||
for (_, document) in documents.iter() {
|
||||
document.window().layout().collect_reports(&mut reports);
|
||||
}
|
||||
|
||||
reports.push(self.image_cache.memory_report(&prefix));
|
||||
|
||||
reports_chan.send(ProcessReports::new(reports));
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ mime = { workspace = true }
|
|||
num-traits = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
pixels = { path = "../../pixels" }
|
||||
profile_traits = { path = "../profile" }
|
||||
rustls-pki-types = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
servo_arc = { workspace = true }
|
||||
|
|
|
@ -10,6 +10,7 @@ use ipc_channel::ipc::IpcSender;
|
|||
use log::debug;
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
use pixels::{Image, ImageMetadata};
|
||||
use profile_traits::mem::Report;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
|
||||
|
@ -36,7 +37,7 @@ pub enum ImageOrMetadataAvailable {
|
|||
/// and image, and returned to the specified event loop when the
|
||||
/// image load completes. It is typically used to trigger a reflow
|
||||
/// and/or repaint.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct ImageResponder {
|
||||
pipeline_id: PipelineId,
|
||||
pub id: PendingImageId,
|
||||
|
@ -73,11 +74,11 @@ impl ImageResponder {
|
|||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub enum ImageResponse {
|
||||
/// The requested image was loaded.
|
||||
Loaded(#[ignore_malloc_size_of = "Arc"] Arc<Image>, ServoUrl),
|
||||
Loaded(#[conditional_malloc_size_of] Arc<Image>, ServoUrl),
|
||||
/// The request image metadata was loaded.
|
||||
MetadataLoaded(ImageMetadata),
|
||||
/// The requested image failed to load, so a placeholder was loaded instead.
|
||||
PlaceholderLoaded(#[ignore_malloc_size_of = "Arc"] Arc<Image>, ServoUrl),
|
||||
PlaceholderLoaded(#[conditional_malloc_size_of] Arc<Image>, ServoUrl),
|
||||
/// Neither the requested image nor the placeholder could be loaded.
|
||||
None,
|
||||
}
|
||||
|
@ -115,6 +116,8 @@ pub trait ImageCache: Sync + Send {
|
|||
where
|
||||
Self: Sized;
|
||||
|
||||
fn memory_report(&self, prefix: &str) -> Report;
|
||||
|
||||
/// Definitively check whether there is a cached, fully loaded image available.
|
||||
fn get_image(
|
||||
&self,
|
||||
|
|
|
@ -130,7 +130,7 @@ pub enum Window {
|
|||
}
|
||||
|
||||
/// [CORS settings attribute](https://html.spec.whatwg.org/multipage/#attr-crossorigin-anonymous)
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||
pub enum CorsSettings {
|
||||
Anonymous,
|
||||
UseCredentials,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue