mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Eliminate the sequential/traversal parallel distinction in favor of a unified adaptive driver.
MozReview-Commit-ID: ADVTNJntzmp
This commit is contained in:
parent
f7c6b2f04e
commit
707ab455bb
13 changed files with 164 additions and 208 deletions
|
@ -23,15 +23,13 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
|
||||
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
||||
use context::{StyleContext, ThreadLocalStyleContext};
|
||||
use dom::{OpaqueNode, SendNode, TElement};
|
||||
use itertools::Itertools;
|
||||
use rayon;
|
||||
use scoped_tls::ScopedTLS;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Borrow;
|
||||
use time;
|
||||
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
|
||||
use traversal::{DomTraversal, PerLevelTraversalData};
|
||||
|
||||
/// The minimum stack size for a thread in the styling pool, in kilobytes.
|
||||
pub const STYLE_THREAD_STACK_SIZE_KB: usize = 128;
|
||||
|
@ -54,59 +52,6 @@ pub const WORK_UNIT_MAX: usize = 16;
|
|||
/// threads, so we keep it compact.
|
||||
type WorkUnit<N> = ArrayVec<[SendNode<N>; WORK_UNIT_MAX]>;
|
||||
|
||||
/// Entry point for the parallel traversal.
|
||||
#[allow(unsafe_code)]
|
||||
pub fn traverse_dom<E, D>(traversal: &D,
|
||||
root: E,
|
||||
token: PreTraverseToken,
|
||||
pool: &rayon::ThreadPool)
|
||||
where E: TElement,
|
||||
D: DomTraversal<E>,
|
||||
{
|
||||
debug_assert!(traversal.is_parallel());
|
||||
debug_assert!(token.should_traverse());
|
||||
|
||||
let dump_stats = traversal.shared_context().options.dump_style_statistics;
|
||||
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
|
||||
|
||||
let traversal_data = PerLevelTraversalData {
|
||||
current_dom_depth: root.depth(),
|
||||
};
|
||||
let tls = ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool);
|
||||
let send_root = unsafe { SendNode::new(root.as_node()) };
|
||||
|
||||
pool.install(|| {
|
||||
rayon::scope(|scope| {
|
||||
let root = send_root;
|
||||
let root_opaque = root.opaque();
|
||||
traverse_nodes(Some(root).into_iter(),
|
||||
DispatchMode::TailCall,
|
||||
true,
|
||||
root_opaque,
|
||||
traversal_data,
|
||||
scope,
|
||||
pool,
|
||||
traversal,
|
||||
&tls);
|
||||
});
|
||||
});
|
||||
|
||||
// Dump statistics to stdout if requested.
|
||||
if dump_stats {
|
||||
let slots = unsafe { tls.unsafe_get() };
|
||||
let mut aggregate = slots.iter().fold(TraversalStatistics::default(), |acc, t| {
|
||||
match *t.borrow() {
|
||||
None => acc,
|
||||
Some(ref cx) => &cx.borrow().statistics + &acc,
|
||||
}
|
||||
});
|
||||
aggregate.finish(traversal, start_time.unwrap());
|
||||
if aggregate.is_large_traversal() {
|
||||
println!("{}", aggregate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A callback to create our thread local context. This needs to be
|
||||
/// out of line so we don't allocate stack space for the entire struct
|
||||
/// in the caller.
|
||||
|
@ -255,8 +200,10 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
|||
/// Controls whether traverse_nodes may make a recursive call to continue
|
||||
/// doing work, or whether it should always dispatch work asynchronously.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum DispatchMode {
|
||||
pub enum DispatchMode {
|
||||
/// This is the last operation by the caller.
|
||||
TailCall,
|
||||
/// This is not the last operation by the caller.
|
||||
NotTailCall,
|
||||
}
|
||||
|
||||
|
@ -267,7 +214,7 @@ impl DispatchMode {
|
|||
/// Enqueues |nodes| for processing, possibly on this thread if the tail call
|
||||
/// conditions are met.
|
||||
#[inline]
|
||||
fn traverse_nodes<'a, 'scope, E, D, I>(
|
||||
pub fn traverse_nodes<'a, 'scope, E, D, I>(
|
||||
nodes: I,
|
||||
mode: DispatchMode,
|
||||
recursion_ok: bool,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue