aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout_thread/lib.rs65
-rw-r--r--components/script/dom/document.rs23
-rw-r--r--components/script/dom/element.rs8
-rw-r--r--components/script/dom/htmlheadelement.rs5
-rw-r--r--components/script/dom/htmltitleelement.rs7
-rw-r--r--components/script/dom/window.rs1
-rw-r--r--components/script_layout_interface/message.rs2
7 files changed, 76 insertions, 35 deletions
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 19593c72d77..04f35183ff4 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -175,6 +175,9 @@ pub struct LayoutThread {
/// The workers that we use for parallel operation.
parallel_traversal: Option<rayon::ThreadPool>,
+ /// Flag to indicate whether to use parallel operations
+ parallel_flag: bool,
+
/// Starts at zero, and increased by one every time a layout completes.
/// This can be used to easily check for invalid stale data.
generation: u32,
@@ -389,13 +392,11 @@ impl LayoutThread {
let device = Device::new(
MediaType::Screen,
opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0));
- let parallel_traversal = if layout_threads != 1 {
- let configuration =
- rayon::Configuration::new().set_num_threads(layout_threads);
- rayon::ThreadPool::new(configuration).ok()
- } else {
- None
- };
+
+ let configuration =
+ rayon::Configuration::new().set_num_threads(layout_threads);
+ let parallel_traversal = rayon::ThreadPool::new(configuration).ok();
+ debug!("Possible layout Threads: {}", layout_threads);
// Create the channel on which new animations can be sent.
let (new_animations_sender, new_animations_receiver) = channel();
@@ -441,6 +442,7 @@ impl LayoutThread {
font_cache_receiver: font_cache_receiver,
font_cache_sender: ipc_font_cache_sender,
parallel_traversal: parallel_traversal,
+ parallel_flag: true,
generation: 0,
new_animations_sender: new_animations_sender,
new_animations_receiver: new_animations_receiver,
@@ -979,6 +981,13 @@ impl LayoutThread {
(data.reflow_info.goal == ReflowGoal::ForScriptQuery &&
data.query_type != ReflowQueryType::NoQuery));
+ // Parallelize if there's more than 750 objects based on rzambre's suggestion
+ // https://github.com/servo/servo/issues/10110
+ self.parallel_flag = self.layout_threads > 1 && data.dom_count > 750;
+ debug!("layout: received layout request for: {}", self.url);
+ debug!("Number of objects in DOM: {}", data.dom_count);
+ debug!("layout: parallel? {}", self.parallel_flag);
+
let mut rw_data = possibly_locked_rw_data.lock();
let element: ServoLayoutElement = match document.root_node() {
@@ -1140,18 +1149,16 @@ impl LayoutThread {
self.time_profiler_chan.clone(),
|| {
// Perform CSS selector matching and flow construction.
- match self.parallel_traversal {
- None => {
- sequential::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
- element.as_node(), &shared_layout_context);
- }
- Some(ref mut traversal) => {
- parallel::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
- element.as_node(), dom_depth, &shared_layout_context, traversal);
- }
+ if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
+ // Parallel mode
+ parallel::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
+ element.as_node(), dom_depth, &shared_layout_context, traversal);
+ } else {
+ // Sequential mode
+ sequential::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
+ element.as_node(), &shared_layout_context);
}
});
-
// TODO(pcwalton): Measure energy usage of text shaping, perhaps?
let text_shaping_time =
(font::get_and_reset_text_shaping_performance_counter() as u64) /
@@ -1402,19 +1409,17 @@ impl LayoutThread {
self.time_profiler_chan.clone(),
|| {
let profiler_metadata = self.profiler_metadata();
- match self.parallel_traversal {
- None => {
- // Sequential mode.
- LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &layout_context)
- }
- Some(ref mut parallel) => {
- // Parallel mode.
- LayoutThread::solve_constraints_parallel(parallel,
- FlowRef::deref_mut(&mut root_flow),
- profiler_metadata,
- self.time_profiler_chan.clone(),
- &*layout_context);
- }
+
+ if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
+ // Parallel mode.
+ LayoutThread::solve_constraints_parallel(traversal,
+ FlowRef::deref_mut(&mut root_flow),
+ profiler_metadata,
+ self.time_profiler_chan.clone(),
+ &*layout_context);
+ } else {
+ //Sequential mode
+ LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &layout_context)
}
});
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 68777b70d39..468f127f7ad 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -284,6 +284,12 @@ pub struct Document {
last_click_info: DOMRefCell<Option<(Instant, Point2D<f32>)>>,
/// https://html.spec.whatwg.org/multipage/#ignore-destructive-writes-counter
ignore_destructive_writes_counter: Cell<u32>,
+ /// Track the total number of elements in this DOM's tree.
+ /// This is sent to the layout thread every time a reflow is done;
+ /// layout uses this to determine if the gains from parallel layout will be worth the overhead.
+ ///
+ /// See also: https://github.com/servo/servo/issues/10110
+ dom_count: Cell<u32>,
}
#[derive(JSTraceable, HeapSizeOf)]
@@ -455,6 +461,22 @@ impl Document {
self.base_element.set(base.r());
}
+ pub fn dom_count(&self) -> u32 {
+ self.dom_count.get()
+ }
+
+ /// This is called by `bind_to_tree` when a node is added to the DOM.
+ /// The internal count is used by layout to determine whether to be sequential or parallel.
+ /// (it's sequential for small DOMs)
+ pub fn increment_dom_count(&self) {
+ self.dom_count.set(self.dom_count.get() + 1);
+ }
+
+ /// This is called by `unbind_from_tree` when a node is removed from the DOM.
+ pub fn decrement_dom_count(&self) {
+ self.dom_count.set(self.dom_count.get() - 1);
+ }
+
pub fn quirks_mode(&self) -> QuirksMode {
self.quirks_mode.get()
}
@@ -1884,6 +1906,7 @@ impl Document {
target_element: MutNullableHeap::new(None),
last_click_info: DOMRefCell::new(None),
ignore_destructive_writes_counter: Default::default(),
+ dom_count: Cell::new(1),
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index c384001e33a..6df2122e7b3 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -2151,10 +2151,12 @@ impl VirtualMethods for Element {
return;
}
+ let doc = document_from_node(self);
if let Some(ref value) = *self.id_attribute.borrow() {
- let doc = document_from_node(self);
doc.register_named_element(self, value.clone());
}
+ // This is used for layout optimization.
+ doc.increment_dom_count();
}
fn unbind_from_tree(&self, context: &UnbindContext) {
@@ -2164,10 +2166,12 @@ impl VirtualMethods for Element {
return;
}
+ let doc = document_from_node(self);
if let Some(ref value) = *self.id_attribute.borrow() {
- let doc = document_from_node(self);
doc.unregister_named_element(self, value.clone());
}
+ // This is used for layout optimization.
+ doc.decrement_dom_count();
}
fn children_changed(&self, mutation: &ChildrenMutation) {
diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs
index 419644c5bb3..fc6e888d015 100644
--- a/components/script/dom/htmlheadelement.rs
+++ b/components/script/dom/htmlheadelement.rs
@@ -71,7 +71,10 @@ impl VirtualMethods for HTMLHeadElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
- fn bind_to_tree(&self, _tree_in_doc: bool) {
+ fn bind_to_tree(&self, tree_in_doc: bool) {
+ if let Some(ref s) = self.super_type() {
+ s.bind_to_tree(tree_in_doc);
+ }
load_script(self);
}
}
diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs
index c124a4a3604..f3ec357cb56 100644
--- a/components/script/dom/htmltitleelement.rs
+++ b/components/script/dom/htmltitleelement.rs
@@ -71,9 +71,12 @@ impl VirtualMethods for HTMLTitleElement {
}
}
- fn bind_to_tree(&self, is_in_doc: bool) {
+ fn bind_to_tree(&self, tree_in_doc: bool) {
+ if let Some(ref s) = self.super_type() {
+ s.bind_to_tree(tree_in_doc);
+ }
let node = self.upcast::<Node>();
- if is_in_doc {
+ if tree_in_doc {
node.owner_doc().title_changed();
}
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 31daeec1f9d..77a569ef65a 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1084,6 +1084,7 @@ impl Window {
window_size: window_size,
script_join_chan: join_chan,
query_type: query_type,
+ dom_count: self.Document().dom_count(),
};
self.layout_chan.send(Msg::Reflow(reflow)).unwrap();
diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs
index 6abbfcb3e3b..581adbb45bc 100644
--- a/components/script_layout_interface/message.rs
+++ b/components/script_layout_interface/message.rs
@@ -126,6 +126,8 @@ pub struct ScriptReflow {
pub script_join_chan: Sender<()>,
/// The type of query if any to perform during this reflow.
pub query_type: ReflowQueryType,
+ /// The number of objects in the dom #10110
+ pub dom_count: u32,
}
impl Drop for ScriptReflow {