Skip to content

Commit

Permalink
Measure layout queries blocked by ongoing layout
Browse files Browse the repository at this point in the history
  • Loading branch information
pylbrecht committed Apr 13, 2019
1 parent a74f522 commit 858011c
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 6 deletions.
4 changes: 4 additions & 0 deletions components/constellation/pipeline.rs
Expand Up @@ -40,6 +40,7 @@ use std::env;
use std::ffi::OsStr;
use std::process;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use style_traits::CSSPixel;
use style_traits::DevicePixel;
Expand Down Expand Up @@ -528,6 +529,7 @@ impl UnprivilegedPipelineContent {
self.script_chan.clone(),
self.load_data.url.clone(),
);
let layout_thread_busy_flag = Arc::new(AtomicBool::new(false));
let layout_pair = STF::create(
InitialScriptState {
id: self.id,
Expand All @@ -554,6 +556,7 @@ impl UnprivilegedPipelineContent {
webvr_chan: self.webvr_chan,
webrender_document: self.webrender_document,
webrender_api_sender: self.webrender_api_sender.clone(),
layout_is_busy: layout_thread_busy_flag.clone(),
},
self.load_data.clone(),
);
Expand All @@ -576,6 +579,7 @@ impl UnprivilegedPipelineContent {
self.webrender_api_sender,
self.webrender_document,
paint_time_metrics,
layout_thread_busy_flag.clone(),
);

if wait_for_completion {
Expand Down
17 changes: 14 additions & 3 deletions components/layout_thread/lib.rs
Expand Up @@ -96,7 +96,7 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;
use std::time::Duration;
Expand Down Expand Up @@ -244,6 +244,9 @@ pub struct LayoutThread {

/// The sizes of all iframes encountered during the last layout operation.
last_iframe_sizes: RefCell<HashMap<BrowsingContextId, TypedSize2D<f32, CSSPixel>>>,

/// Flag that indicates if LayoutThread is busy handling a request.
busy: Arc<AtomicBool>,
}

impl LayoutThreadFactory for LayoutThread {
Expand All @@ -268,6 +271,7 @@ impl LayoutThreadFactory for LayoutThread {
webrender_api_sender: webrender_api::RenderApiSender,
webrender_document: webrender_api::DocumentId,
paint_time_metrics: PaintTimeMetrics,
busy: Arc<AtomicBool>,
) {
thread::Builder::new()
.name(format!("LayoutThread {:?}", id))
Expand Down Expand Up @@ -305,6 +309,7 @@ impl LayoutThreadFactory for LayoutThread {
webrender_api_sender,
webrender_document,
paint_time_metrics,
busy,
);

let reporter_name = format!("layout-reporter-{}", id);
Expand Down Expand Up @@ -466,6 +471,7 @@ impl LayoutThread {
webrender_api_sender: webrender_api::RenderApiSender,
webrender_document: webrender_api::DocumentId,
paint_time_metrics: PaintTimeMetrics,
busy: Arc<AtomicBool>,
) -> LayoutThread {
// The device pixel ratio is incorrect (it does not have the hidpi value),
// but it will be set correctly when the initial reflow takes place.
Expand Down Expand Up @@ -544,6 +550,7 @@ impl LayoutThread {
paint_time_metrics: paint_time_metrics,
layout_query_waiting_time: Histogram::new(),
last_iframe_sizes: Default::default(),
busy: busy,
}
}

Expand Down Expand Up @@ -648,7 +655,8 @@ impl LayoutThread {
recv(self.font_cache_receiver) -> msg => { msg.unwrap(); Request::FromFontCache }
};

match request {
self.busy.store(true, Ordering::Relaxed);
let result = match request {
Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => self
.handle_request_helper(
Msg::SetScrollStates(new_scroll_states),
Expand Down Expand Up @@ -679,7 +687,9 @@ impl LayoutThread {
.unwrap();
true
},
}
};
self.busy.store(false, Ordering::Relaxed);
result
}

/// Receives and dispatches messages from other threads.
Expand Down Expand Up @@ -861,6 +871,7 @@ impl LayoutThread {
self.webrender_api.clone_sender(),
self.webrender_document,
info.paint_time_metrics,
self.busy.clone(),
);
}

Expand Down
2 changes: 2 additions & 0 deletions components/layout_traits/lib.rs
Expand Up @@ -20,6 +20,7 @@ use profile_traits::{mem, time};
use script_traits::LayoutMsg as ConstellationMsg;
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use servo_url::ServoUrl;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

// A static method creating a layout thread
Expand All @@ -44,5 +45,6 @@ pub trait LayoutThreadFactory {
webrender_api_sender: webrender_api::RenderApiSender,
webrender_document: webrender_api::DocumentId,
paint_time_metrics: PaintTimeMetrics,
busy: Arc<AtomicBool>,
);
}
18 changes: 17 additions & 1 deletion components/profile/time.rs
Expand Up @@ -18,7 +18,7 @@ use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use servo_config::opts::OutputOptions;
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::error::Error;
use std::fs::File;
use std::io::{self, Write};
Expand Down Expand Up @@ -171,6 +171,7 @@ pub struct Profiler {
output: Option<OutputOptions>,
pub last_msg: Option<ProfilerMsg>,
trace: Option<TraceDump>,
blocked_layout_queries: HashMap<String, u32>,
}

impl Profiler {
Expand Down Expand Up @@ -305,6 +306,7 @@ impl Profiler {
output: output,
last_msg: None,
trace: trace,
blocked_layout_queries: HashMap::new(),
}
}

Expand Down Expand Up @@ -345,6 +347,9 @@ impl Profiler {
None => sender.send(ProfilerData::NoRecords).unwrap(),
};
},
ProfilerMsg::BlockedLayoutQuery(url) => {
*self.blocked_layout_queries.entry(url).or_insert(0) += 1;
},
ProfilerMsg::Exit(chan) => {
heartbeats::cleanup();
self.print_buckets();
Expand Down Expand Up @@ -411,6 +416,11 @@ impl Profiler {
.unwrap();
}
}

write!(file, "_url\t_blocked layout queries_\n").unwrap();
for (url, count) in &self.blocked_layout_queries {
write!(file, "{}\t{}\n", url, count).unwrap();
}
},
Some(OutputOptions::Stdout(_)) => {
let stdout = io::stdout();
Expand Down Expand Up @@ -450,6 +460,12 @@ impl Profiler {
}
}
writeln!(&mut lock, "").unwrap();

writeln!(&mut lock, "_url_\t_blocked layout queries_").unwrap();
for (url, count) in &self.blocked_layout_queries {
writeln!(&mut lock, "{}\t{}", url, count).unwrap();
}
writeln!(&mut lock, "").unwrap();
},
Some(OutputOptions::DB(ref hostname, ref dbname, ref user, ref password)) => {
// Unfortunately, influent does not like hostnames ending with "/"
Expand Down
5 changes: 5 additions & 0 deletions components/profile_traits/time.rs
Expand Up @@ -46,6 +46,11 @@ pub enum ProfilerMsg {
),
/// Message used to force print the profiling metrics
Print,

// TODO pylbrecht
// write meaningful docstring
BlockedLayoutQuery(String),

/// Tells the profiler to shut down.
Exit(IpcSender<()>),
}
Expand Down
16 changes: 14 additions & 2 deletions components/script/dom/window.rs
Expand Up @@ -92,7 +92,7 @@ use net_traits::{ReferrerPolicy, ResourceThreads};
use num_traits::ToPrimitive;
use profile_traits::ipc as ProfiledIpc;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
use profile_traits::time::ProfilerChan as TimeProfilerChan;
use profile_traits::time::{ProfilerChan as TimeProfilerChan, ProfilerMsg};
use script_layout_interface::message::{Msg, QueryMsg, Reflow, ReflowGoal, ScriptReflow};
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
use script_layout_interface::rpc::{
Expand All @@ -117,7 +117,7 @@ use std::fs;
use std::io::{stderr, stdout, Write};
use std::mem;
use std::rc::Rc;
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use style::dom::OpaqueNode;
use style::error_reporting::{ContextualParseError, ParseErrorReporter};
Expand Down Expand Up @@ -293,6 +293,10 @@ pub struct Window {
/// Indicate whether a SetDocumentStatus message has been sent after a reflow is complete.
/// It is used to avoid sending idle message more than once, which is unneccessary.
has_sent_idle_message: Cell<bool>,

/// Flag that indicates if the layout thread is busy handling a request.
#[ignore_malloc_size_of = "Arc<T> is hard"]
layout_is_busy: Arc<AtomicBool>,
}

impl Window {
Expand Down Expand Up @@ -1558,6 +1562,12 @@ impl Window {
}

pub fn layout_reflow(&self, query_msg: QueryMsg) -> bool {
if self.layout_is_busy.load(Ordering::Relaxed) {
let url = self.get_url().into_string();
self.time_profiler_chan()
.send(ProfilerMsg::BlockedLayoutQuery(url));
}

self.reflow(
ReflowGoal::LayoutQuery(query_msg, time::precise_time_ns()),
ReflowReason::Query,
Expand Down Expand Up @@ -2023,6 +2033,7 @@ impl Window {
microtask_queue: Rc<MicrotaskQueue>,
webrender_document: DocumentId,
webrender_api_sender: RenderApiSender,
layout_is_busy: Arc<AtomicBool>,
) -> DomRoot<Self> {
let layout_rpc: Box<dyn LayoutRPC + Send> = {
let (rpc_send, rpc_recv) = unbounded();
Expand Down Expand Up @@ -2095,6 +2106,7 @@ impl Window {
exists_mut_observer: Cell::new(false),
webrender_api_sender,
has_sent_idle_message: Cell::new(false),
layout_is_busy,
});

unsafe { WindowBinding::Wrap(runtime.cx(), win) }
Expand Down
12 changes: 12 additions & 0 deletions components/script/script_thread.rs
Expand Up @@ -144,6 +144,7 @@ use std::option::Option;
use std::ptr;
use std::rc::Rc;
use std::result::Result;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, SystemTime};
Expand Down Expand Up @@ -202,6 +203,8 @@ struct InProgressLoad {
navigation_start_precise: u64,
/// For cancelling the fetch
canceller: FetchCanceller,
/// Flag to indicate if the layout thread is busy handling a request.
layout_is_busy: Arc<AtomicBool>,
}

impl InProgressLoad {
Expand All @@ -216,6 +219,7 @@ impl InProgressLoad {
window_size: WindowSizeData,
url: ServoUrl,
origin: MutableOrigin,
layout_is_busy: Arc<AtomicBool>,
) -> InProgressLoad {
let current_time = get_time();
let navigation_start_precise = precise_time_ns();
Expand All @@ -237,6 +241,7 @@ impl InProgressLoad {
navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64,
navigation_start_precise: navigation_start_precise,
canceller: Default::default(),
layout_is_busy: layout_is_busy,
}
}
}
Expand Down Expand Up @@ -702,6 +707,7 @@ impl ScriptThreadFactory for ScriptThread {
let opener = state.opener;
let mem_profiler_chan = state.mem_profiler_chan.clone();
let window_size = state.window_size;
let layout_is_busy = state.layout_is_busy.clone();

let script_thread = ScriptThread::new(state, script_port, script_chan.clone());

Expand All @@ -722,6 +728,7 @@ impl ScriptThreadFactory for ScriptThread {
window_size,
load_data.url.clone(),
origin,
layout_is_busy,
);
script_thread.pre_page_load(new_load, load_data);

Expand Down Expand Up @@ -2025,6 +2032,8 @@ impl ScriptThread {
let layout_pair = unbounded();
let layout_chan = layout_pair.0.clone();

let layout_is_busy = Arc::new(AtomicBool::new(false));

let msg = message::Msg::CreateLayoutThread(LayoutThreadInit {
id: new_pipeline_id,
url: load_data.url.clone(),
Expand All @@ -2043,6 +2052,7 @@ impl ScriptThread {
self.control_chan.clone(),
load_data.url.clone(),
),
layout_is_busy: layout_is_busy.clone(),
});

// Pick a layout thread, any layout thread
Expand Down Expand Up @@ -2076,6 +2086,7 @@ impl ScriptThread {
window_size,
load_data.url.clone(),
origin,
layout_is_busy.clone(),
);
if load_data.url.as_str() == "about:blank" {
self.start_page_load_about_blank(new_load, load_data.js_eval_result);
Expand Down Expand Up @@ -2872,6 +2883,7 @@ impl ScriptThread {
self.microtask_queue.clone(),
self.webrender_document,
self.webrender_api_sender.clone(),
incomplete.layout_is_busy,
);

// Initialize the browsing context for the window.
Expand Down
2 changes: 2 additions & 0 deletions components/script_layout_interface/message.rs
Expand Up @@ -19,6 +19,7 @@ use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData};
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use style::context::QuirksMode;
use style::dom::OpaqueNode;
Expand Down Expand Up @@ -226,4 +227,5 @@ pub struct LayoutThreadInit {
pub image_cache: Arc<dyn ImageCache>,
pub content_process_shutdown_chan: Option<IpcSender<()>>,
pub paint_time_metrics: PaintTimeMetrics,
pub layout_is_busy: Arc<AtomicBool>,
}
3 changes: 3 additions & 0 deletions components/script_traits/lib.rs
Expand Up @@ -50,6 +50,7 @@ use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
use std::collections::HashMap;
use std::fmt;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::time::Duration;
use style_traits::CSSPixel;
Expand Down Expand Up @@ -600,6 +601,8 @@ pub struct InitialScriptState {
pub webrender_document: DocumentId,
/// FIXME(victor): The Webrender API sender in this constellation's pipeline
pub webrender_api_sender: RenderApiSender,
/// Flag to indicate if the layout thread is busy handling a request.
pub layout_is_busy: Arc<AtomicBool>,
}

/// This trait allows creating a `ScriptThread` without depending on the `script`
Expand Down

0 comments on commit 858011c

Please sign in to comment.