Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor task system for efficiency #56717

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
327 changes: 188 additions & 139 deletions src/librustc/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,196 +202,245 @@ impl DepGraph {
arg: A,
task: fn(C, A) -> R)
-> (R, DepNodeIndex)
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
where C: DepGraphSafe + StableHashingContextProvider<'gcx> + Clone,
R: HashStable<StableHashingContext<'gcx>>,
{
self.with_task_impl(key, cx, arg, false, task,
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
if let Some(ref data) = self.data {
let open_task = OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
reads: SmallVec::new(),
read_set: Default::default(),
})),
|data, key, task| data.borrow_mut().complete_task(key, task))
}));
let result = ty::tls::with_context(|icx| {
let icx = ty::tls::ImplicitCtxt {
task: &open_task,
..icx.clone()
};

ty::tls::enter_context(&icx, |_| {
task(cx.clone(), arg)
})
});
let dep_node_index = data.current.borrow_mut().complete_task(key, open_task);
self.finish_task_incr_on(data, key, cx, &result, dep_node_index);
(result, dep_node_index)
} else {
let result = task(cx.clone(), arg);
self.finish_task_incr_off(key, cx, &result);
(result, DepNodeIndex::INVALID)
}
}

/// Creates a new dep-graph input with value `input`
pub fn input_task<'gcx, C, R>(&self,
key: DepNode,
cx: C,
input: R)
-> (R, DepNodeIndex)
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
/// Execute something within an "eval-always" task which is a task
// that runs whenever anything changes.
// FIXME: Find a way to make F: DepGraphSafe
pub fn with_eval_always_task<'a, F, R>(
&self,
tcx: TyCtxt<'a, '_, '_>,
key: DepNode,
task: F,
) -> (R, DepNodeIndex)
where F: FnOnce(&OpenTask) -> R,
R: HashStable<StableHashingContext<'a>>,
{
fn identity_fn<C, A>(_: C, arg: A) -> A {
arg
if let Some(ref data) = self.data {
let open_task = OpenTask::EvalAlways { node: key };
let result = task(&open_task);
let dep_node_index = data.current.borrow_mut()
.complete_eval_always_task(key, open_task);
self.finish_task_incr_on(data, key, tcx, &result, dep_node_index);
(result, dep_node_index)
} else {
debug_assert!(!key.kind.fingerprint_needed_for_crate_hash());
(task(&OpenTask::Ignore), DepNodeIndex::INVALID)
}
}

self.with_task_impl(key, cx, input, true, identity_fn,
|_| OpenTask::Ignore,
|data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
// FIXME: Merge with with_task?
pub fn with_query_task<'a, F, R>(
&self,
tcx: TyCtxt<'a, '_, '_>,
key: DepNode,
task: F,
) -> (R, DepNodeIndex)
where F: FnOnce(&OpenTask) -> R,
R: HashStable<StableHashingContext<'a>>,
{
if let Some(ref data) = self.data {
let open_task = OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
reads: SmallVec::new(),
read_set: Default::default(),
}));
let result = task(&open_task);
// FIXME: Look at `complete_task` and the same for other functions
let dep_node_index = data.current.borrow_mut().complete_task(key, open_task);
self.finish_task_incr_on(data, key, tcx, &result, dep_node_index);
(result, dep_node_index)
} else {
debug_assert!(!key.kind.fingerprint_needed_for_crate_hash());
// with_task runs finish_task_incr_off here
(task(&OpenTask::Ignore), DepNodeIndex::INVALID)
}
}

/// Creates a new dep-graph input with value `input`
pub fn input_dep_index<'gcx, R>(
&self,
key: DepNode,
cx: &StableHashingContext<'gcx>,
input: &R
) -> DepNodeIndex
where R: HashStable<StableHashingContext<'gcx>>,
{
// This assumes that we don't have an ImplicitCtxt and thus have
// an implicit OpenTask::Ignore task
debug_assert!(ty::tls::with_opt(|tcx| tcx.is_none()));

if let Some(ref data) = self.data {
let dep_node_index = data.current.borrow_mut().alloc_node(key, SmallVec::new());
self.finish_task_incr_on(data, key, cx, input, dep_node_index);
dep_node_index
} else {
self.finish_task_incr_off(key, cx, input)
}
}

fn with_task_impl<'gcx, C, A, R>(
fn finish_task_incr_on<'gcx, C, R>(
&self,
data: &DepGraphData,
key: DepNode,
cx: C,
arg: A,
no_tcx: bool,
task: fn(C, A) -> R,
create_task: fn(DepNode) -> OpenTask,
finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>,
DepNode,
OpenTask) -> DepNodeIndex
) -> (R, DepNodeIndex)
result: &R,
dep_node_index: DepNodeIndex,
)
where
C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
{
if let Some(ref data) = self.data {
let open_task = create_task(key);
// In incremental mode, hash the result of the task. We don't
// do anything with the hash yet, but we are computing it
// anyway so that
// - we make sure that the infrastructure works and
// - we can get an idea of the runtime cost.
let mut hcx = cx.get_stable_hashing_context();

if cfg!(debug_assertions) {
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone()))
};

// In incremental mode, hash the result of the task. We don't
// do anything with the hash yet, but we are computing it
// anyway so that
// - we make sure that the infrastructure works and
// - we can get an idea of the runtime cost.
let mut hcx = cx.get_stable_hashing_context();
if cfg!(debug_assertions) {
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)
};

if cfg!(debug_assertions) {
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone()))
};
let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);

let result = if no_tcx {
task(cx, arg)
} else {
ty::tls::with_context(|icx| {
let icx = ty::tls::ImplicitCtxt {
task: &open_task,
..icx.clone()
};

ty::tls::enter_context(&icx, |_| {
task(cx, arg)
})
})
};
let current_fingerprint = stable_hasher.finish();

if cfg!(debug_assertions) {
profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)
};
// Store the current fingerprint
{
let mut fingerprints = self.fingerprints.borrow_mut();

let dep_node_index = finish_task_and_alloc_depnode(&data.current, key, open_task);
if dep_node_index.index() >= fingerprints.len() {
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
}

let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);
debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO,
"DepGraph::with_task() - Duplicate fingerprint \
insertion for {:?}", key);
fingerprints[dep_node_index] = current_fingerprint;
}

let current_fingerprint = stable_hasher.finish();
// Determine the color of the new DepNode.
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);

// Store the current fingerprint
{
let mut fingerprints = self.fingerprints.borrow_mut();
let color = if current_fingerprint == prev_fingerprint {
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};

if dep_node_index.index() >= fingerprints.len() {
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
}
let mut colors = data.colors.borrow_mut();
debug_assert!(colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
insertion for {:?}", key);

debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO,
"DepGraph::with_task() - Duplicate fingerprint \
insertion for {:?}", key);
fingerprints[dep_node_index] = current_fingerprint;
}
colors.insert(prev_index, color);
}
}

// Determine the color of the new DepNode.
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
fn finish_task_incr_off<'gcx, C, R>(
&self,
key: DepNode,
cx: C,
result: &R,
) -> DepNodeIndex
where
C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
{
debug_assert!(self.data.is_none());

let color = if current_fingerprint == prev_fingerprint {
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};
if key.kind.fingerprint_needed_for_crate_hash() {
let mut hcx = cx.get_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);
let fingerprint = stable_hasher.finish();

let mut colors = data.colors.borrow_mut();
debug_assert!(colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
insertion for {:?}", key);
let mut fingerprints = self.fingerprints.borrow_mut();
let dep_node_index = DepNodeIndex::new(fingerprints.len());
fingerprints.push(fingerprint);

colors.insert(prev_index, color);
}
debug_assert!(fingerprints[dep_node_index] == fingerprint,
"DepGraph::with_task() - Assigned fingerprint to \
unexpected index for {:?}", key);

(result, dep_node_index)
dep_node_index
} else {
if key.kind.fingerprint_needed_for_crate_hash() {
let mut hcx = cx.get_stable_hashing_context();
let result = task(cx, arg);
let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);
let fingerprint = stable_hasher.finish();

let mut fingerprints = self.fingerprints.borrow_mut();
let dep_node_index = DepNodeIndex::new(fingerprints.len());
fingerprints.push(fingerprint);

debug_assert!(fingerprints[dep_node_index] == fingerprint,
"DepGraph::with_task() - Assigned fingerprint to \
unexpected index for {:?}", key);

(result, dep_node_index)
} else {
(task(cx, arg), DepNodeIndex::INVALID)
}
DepNodeIndex::INVALID
}
}

/// Execute something within an "anonymous" task, that is, a task the
/// DepNode of which is determined by the list of inputs it read from.
pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex)
where OP: FnOnce() -> R
pub fn with_anon_open_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex)
where OP: FnOnce(&OpenTask) -> R
{
if let Some(ref data) = self.data {
let (result, open_task) = ty::tls::with_context(|icx| {
let task = OpenTask::Anon(Lock::new(AnonOpenTask {
reads: SmallVec::new(),
read_set: Default::default(),
}));

let r = {
let icx = ty::tls::ImplicitCtxt {
task: &task,
..icx.clone()
};

ty::tls::enter_context(&icx, |_| {
op()
})
};
let task = OpenTask::Anon(Lock::new(AnonOpenTask {
reads: SmallVec::new(),
read_set: Default::default(),
}));

(r, task)
});
let result = op(&task);
let dep_node_index = data.current
.borrow_mut()
.pop_anon_task(dep_kind, open_task);
.pop_anon_task(dep_kind, task);
(result, dep_node_index)
} else {
(op(), DepNodeIndex::INVALID)
(op(&OpenTask::Ignore), DepNodeIndex::INVALID)
}
}

/// Execute something within an "eval-always" task which is a task
// that runs whenever anything changes.
pub fn with_eval_always_task<'gcx, C, A, R>(&self,
key: DepNode,
cx: C,
arg: A,
task: fn(C, A) -> R)
-> (R, DepNodeIndex)
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
/// Execute something within an "anonymous" task, that is, a task the
/// DepNode of which is determined by the list of inputs it read from.
pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex)
where OP: FnOnce() -> R
{
self.with_task_impl(key, cx, arg, false, task,
|key| OpenTask::EvalAlways { node: key },
|data, key, task| data.borrow_mut().complete_eval_always_task(key, task))
self.with_anon_open_task(dep_kind, |task| {
ty::tls::with_context(|icx| {
let icx = ty::tls::ImplicitCtxt {
task,
..icx.clone()
};

ty::tls::enter_context(&icx, |_| {
op()
})
})
})
}

#[inline]
Expand Down
Loading