Skip to content

Optimize dep-graph serialization and improve meta-data hashing #35406

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

Merged
merged 24 commits into from
Aug 9, 2016

Conversation

nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Aug 6, 2016

This makes a number of related changes:

  • instead of serializing the whole graph, we only serialize HIR -> WorkProduct edges
  • we gather predecessors more efficiently and cache effort, drastically cutting serialization time by over 6x in my measurements
  • compute the metadata hashes more determinstically
  • improve -Z incremental-info, which tells you how much re-use you are getting, and tells you why you are not getting re-use

The end result is that, at least in my tests, we are now able to get 100% re-use when doing cargo clean; cargo build twice in a row (with an incremental directory, of course). Here are some rough performance numbers from the syntex-syntax crate:

build normal time (debug) incremental time (debug)
full build 128s 78s
just syntex_syntax 96s 51s

Note that these numbers only reflect the first phase of incremental, where we are just skipping the trans/LLVM phases. They will get better as we incrementalize more of the compiler. Also, these numbers represent the simplest case, where no actual changes were made. There is still more work to do to handle the case some small number of changes were made correctly (in particular, verifying that the dep-graph is complete etc).

r? @michaelwoerister

Fixes #35167.

The way we do HIR inlining introduces reads of the "Hir" into the graph,
but this Hir in fact belongs to other crates, so when we try to load
later, we ICE because the Hir nodes in question don't belond to the
crate (and we haven't done inlining yet). This pass rewrites those HIR
nodes to the metadata from which the inlined HIR was loaded.
The biggest problem, actually, is krate numbers being removed entirely,
which can lead to array-index-out-of-bounds errors.

cc rust-lang#35123 -- not a complete fix, since really we ought to "map" the old
crate numbers to the new ones, not just detect changes.
The reads will occur naturally as the HIR/MIR is fetched from the
tracked tables, and this winds up adding reads to the hir of foreign
def-ids somehow.
When we hash the inputs to a MetaData node, we have to hash them in a
consistent order. We achieve this by sorting the stringfied `DefPath`
entries. Also, micro-optimie by cache more results across the saving
process.
It's nice to get a rough idea of how much work we're
saving.
We now detect inlined id's earlier (in the HIR map) and rewrite a read
of them to be a read of the metadata for the associated item.
I cannot figure out how to write a test for this, but I observed
incorrect edges as a result of not using memoized pattern here
(e.g., LateLintCheck -> SizedConstraint).
this can actually be expensive!
@michaelwoerister
Copy link
Member

michaelwoerister commented Aug 6, 2016

Are these numbers for a release or for a debug build?
Nevermind :)

@@ -39,6 +39,14 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
}
}

pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer if this was called is_input_node or is_graph_root to make it clearer what we are after.

@michaelwoerister
Copy link
Member

Ok, I've reviewed everything after rustfmt save.rs. The question in encode_dep_graph seems important.

Per the discussion on rust-lang#34765, we make one `DepNode::Mir` variant and use
it to represent both the MIR tracking map as well as passes that operate
on MIR. We also track loads of cached MIR (which naturally comes from
metadata).

Note that the "HAIR" pass adds a read of TypeckItemBody because it uses
a myriad of tables that are not individually tracked.
it now carries a def-id; supply a dummy
The new `Predecessors` type computes a set of interesting targets and
their HIR predecessors, and discards everything in between.
Produces a deterministic hash, at least for a single platform /
compiler-version.
This massively speeds up serialization. It also
seems to produce deterministic metadata hashes
(before I was seeing inconsistent results).

Fixes rust-lang#35232.
@nikomatsakis
Copy link
Contributor Author

@michaelwoerister OK, I addressed your nits. I will rebase atop of #35166, I think, and maybe try to land them together once you've revised the additional commits in there.

// encoding, rather than having been retraced to a `DefId`. The
// reason for this is that this way we can include nodes that have
// been removed (which no longer have a `DefId` in the current
// compilation).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@michaelwoerister
Copy link
Member

LGTM.

@bors bors merged commit e0b82d5 into rust-lang:master Aug 9, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants