diff options
author | bors-servo <release+servo@mozilla.com> | 2013-10-31 23:25:26 -0700 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2013-10-31 23:25:26 -0700 |
commit | ddce8b8fa0b09f1d56ce9684028e23f4974b2e5f (patch) | |
tree | 948bc835efe92c8acf61148113535e4082716ffb /src | |
parent | a72d0558006b42bf9c697702057911bd45e102bf (diff) | |
parent | 901dfc45e5ed2e0506a18488be69e083fd59501f (diff) | |
download | servo-ddce8b8fa0b09f1d56ce9684028e23f4974b2e5f.tar.gz servo-ddce8b8fa0b09f1d56ce9684028e23f4974b2e5f.zip |
auto merge of #1152 : ILyoan/servo/parallel_selector_matching, r=SimonSapin
This an attempt to parallelize selector matching.
Approach
* Let the `match_subtree` spawn limited number of tasks.
* Each of them takes a list of nodes that is uniformly distributed
* And then each task does the selector matching for every single node in its list.
(Not sure if this is worthwhile for long term especially considering CSS optimizing techniques such as ancestor filter or style sharing)
Benchmark from my machine (LayoutSelectorMatchCategory) (intel i7 3.4GHz * 8, linux x86_64)
* src/test/demo.html
* original: 0.07ms
* parallel: 0.20ms
* perf-rainbow.html
* original: 485ms
* parallel: 245ms
* A test page with 15000 nodes and 3000 CSS selector(including inline style).
* original: 140ms
* parallel: 60ms
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/css/matching.rs | 45 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 13 |
2 files changed, 47 insertions, 11 deletions
diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs index c777a676505..f7da616f19e 100644 --- a/src/components/main/css/matching.rs +++ b/src/components/main/css/matching.rs @@ -5,6 +5,12 @@ // High-level interface to CSS selector matching. use std::cell::Cell; +use std::comm; +use std::rt::default_sched_threads; +use std::task; +use std::vec; +use extra::arc::RWArc; + use css::node_style::StyledNode; use css::node_util::NodeUtil; use layout::incremental; @@ -16,7 +22,7 @@ use servo_util::tree::TreeNodeRef; pub trait MatchMethods { fn match_node(&self, stylist: &Stylist); - fn match_subtree(&self, stylist: &Stylist); + fn match_subtree(&self, stylist: RWArc<Stylist>); fn cascade_node(&self, parent: Option<AbstractNode<LayoutView>>); fn cascade_subtree(&self, parent: Option<AbstractNode<LayoutView>>); @@ -36,14 +42,41 @@ impl MatchMethods for AbstractNode<LayoutView> { data.applicable_declarations = cell.take(); } } - fn match_subtree(&self, stylist: &Stylist) { - self.match_node(stylist); + fn match_subtree(&self, stylist: RWArc<Stylist>) { + let num_tasks = default_sched_threads() * 2; + let mut node_count = 0; + let mut nodes_per_task = vec::from_elem(num_tasks, ~[]); - for kid in self.children() { - if kid.is_element() { - kid.match_subtree(stylist); + for node in self.traverse_preorder() { + if node.is_element() { + nodes_per_task[node_count % num_tasks].push(node); + node_count += 1; + } + } + + let (port, chan) = comm::stream(); + let chan = comm::SharedChan::new(chan); + let mut num_spawned = 0; + + for nodes in nodes_per_task.move_iter() { + if nodes.len() > 0 { + let chan = chan.clone(); + let stylist = stylist.clone(); + do task::spawn_with((nodes, stylist)) |(nodes, stylist)| { + let nodes = Cell::new(nodes); + do stylist.read |stylist| { + for node in nodes.take().move_iter() { + node.match_node(stylist); + } + } + chan.send(()); + } + num_spawned += 1; } } + for _ in range(0, num_spawned) { + port.recv(); + } } fn cascade_node(&self, parent: Option<AbstractNode<LayoutView>>) { diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index a894ffc3896..a0a2161e2da 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -20,7 +20,7 @@ use std::cast::transmute; use std::cell::Cell; use std::comm::{Port}; use std::task; -use extra::arc::Arc; +use extra::arc::{Arc, RWArc}; use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; @@ -65,7 +65,7 @@ struct LayoutTask { display_list: Option<Arc<DisplayList<AbstractNode<()>>>>, - stylist: Stylist, + stylist: RWArc<Stylist>, profiler_chan: ProfilerChan, } @@ -241,7 +241,7 @@ impl LayoutTask { display_list: None, - stylist: new_stylist(), + stylist: RWArc::new(new_stylist()), profiler_chan: profiler_chan, } } @@ -294,7 +294,10 @@ impl LayoutTask { } fn handle_add_stylesheet(&mut self, sheet: Stylesheet) { - self.stylist.add_stylesheet(sheet, AuthorOrigin); + let sheet = Cell::new(sheet); + do self.stylist.write |stylist| { + stylist.add_stylesheet(sheet.take(), AuthorOrigin) + } } /// Performs layout constraint solving. @@ -359,7 +362,7 @@ impl LayoutTask { ReflowDocumentDamage => {} MatchSelectorsDocumentDamage => { do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) { - node.match_subtree(&self.stylist); + node.match_subtree(self.stylist.clone()); node.cascade_subtree(None); } } |