Skip to content

Commit 4f7895f

Browse files
committed
Garbage collect dep graph
1 parent 3a45328 commit 4f7895f

File tree

3 files changed

+212
-32
lines changed

3 files changed

+212
-32
lines changed

src/librustc/dep_graph/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ pub use self::prev::PreviousDepGraph;
1616
pub use self::query::DepGraphQuery;
1717
pub use self::safe::AssertDepGraphSafe;
1818
pub use self::safe::DepGraphSafe;
19-
pub use self::serialized::decode_dep_graph;
19+
pub use self::serialized::{DecodedDepGraph, decode_dep_graph, gc_dep_graph};

src/librustc/dep_graph/serialized.rs

Lines changed: 183 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_data_structures::sync::worker::{Worker, WorkerExecutor};
22
use rustc_data_structures::sync::{Lrc, AtomicCell};
33
use rustc_data_structures::{unlikely, cold_path};
4-
use rustc_data_structures::indexed_vec::IndexVec;
4+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
55
use rustc_data_structures::fingerprint::Fingerprint;
66
use rustc_data_structures::fx::FxHashMap;
77
use rustc_serialize::{Decodable, Encodable, Encoder, Decoder, opaque};
@@ -14,15 +14,158 @@ use crate::dep_graph::dep_node::{DepKind, DepNode};
1414
use super::prev::PreviousDepGraph;
1515
use super::graph::{DepNodeData, DepNodeIndex, DepNodeState};
1616

17+
// calcutale a list of bytes to copy from the previous graph
18+
19+
fn decode_bounds(
20+
d: &mut opaque::Decoder<'_>,
21+
f: impl FnOnce(&mut opaque::Decoder<'_>) -> Result<(), String>
22+
) -> Result<(usize, usize), String> {
23+
let start = d.position();
24+
f(d)?;
25+
Ok((start, d.position()))
26+
}
27+
28+
type NodePoisitions = Vec<Option<(usize, usize)>>;
29+
30+
fn read_dep_graph_positions(
31+
d: &mut opaque::Decoder<'_>,
32+
result: &DecodedDepGraph,
33+
) -> Result<(NodePoisitions, NodePoisitions), String> {
34+
let node_count = result.prev_graph.nodes.len();
35+
let mut nodes: NodePoisitions = repeat(None).take(node_count).collect();
36+
let mut edges: NodePoisitions = repeat(None).take(node_count).collect();
37+
38+
loop {
39+
if d.position() == d.data.len() {
40+
break;
41+
}
42+
match SerializedAction::decode(d)? {
43+
SerializedAction::AllocateNodes => {
44+
let len = d.read_u32()?;
45+
let start = DepNodeIndex::decode(d)?.as_u32();
46+
for i in 0..len {
47+
let i = (start + i) as usize;
48+
nodes[i] = Some(decode_bounds(d, |d| DepNode::decode(d).map(|_| ()))?);
49+
edges[i] = Some(decode_bounds(d, |d| {
50+
let len = d.read_u32()?;
51+
for _ in 0..len {
52+
DepNodeIndex::decode(d)?;
53+
}
54+
Ok(())
55+
})?);
56+
}
57+
}
58+
SerializedAction::UpdateEdges => {
59+
let len = d.read_u32()?;
60+
for _ in 0..len {
61+
let i = DepNodeIndex::decode(d)?.as_u32() as usize;
62+
edges[i] = Some(decode_bounds(d, |d| {
63+
let len = d.read_u32()?;
64+
for _ in 0..len {
65+
DepNodeIndex::decode(d)?;
66+
}
67+
Ok(())
68+
})?);
69+
}
70+
}
71+
SerializedAction::InvalidateNodes => {
72+
let len = d.read_u32()?;
73+
for _ in 0..len {
74+
let i = DepNodeIndex::decode(d)?.as_u32() as usize;
75+
nodes[i] = None;
76+
edges[i] = None;
77+
}
78+
}
79+
}
80+
}
81+
82+
Ok((nodes, edges))
83+
}
84+
85+
pub fn gc_dep_graph(
86+
time_passes: bool,
87+
d: &mut opaque::Decoder<'_>,
88+
result: &DecodedDepGraph,
89+
file: &mut File,
90+
) {
91+
let (nodes, edges) = time_ext(time_passes, None, "read dep-graph positions", || {
92+
read_dep_graph_positions(d, result).unwrap()
93+
});
94+
95+
let mut i = 0;
96+
97+
loop {
98+
// Skip empty nodes
99+
while i < nodes.len() && nodes[i].is_none() {
100+
i += 1;
101+
}
102+
103+
// Break if we are done
104+
if i >= nodes.len() {
105+
break;
106+
}
107+
108+
// Find out how many consecutive nodes we will emit
109+
let mut len = 1;
110+
while i + len < nodes.len() && nodes[i + len].is_some() {
111+
len += 1;
112+
}
113+
114+
let mut encoder = opaque::Encoder::new(Vec::with_capacity(11));
115+
SerializedAction::AllocateNodes.encode(&mut encoder).ok();
116+
// Emit the number of nodes we're emitting
117+
encoder.emit_u32(len as u32).ok();
118+
119+
// Emit the dep node index of the first node
120+
DepNodeIndex::new(i).encode(&mut encoder).ok();
121+
122+
file.write_all(&encoder.into_inner()).unwrap();
123+
124+
let mut buffers = Vec::with_capacity(nodes.len() * 2);
125+
126+
let push_buffer = |buffers: &mut Vec<(usize, usize)>, range: (usize, usize)| {
127+
if let Some(last) = buffers.last_mut() {
128+
if last.1 == range.0 {
129+
// Extend the last range
130+
last.1 = range.1;
131+
return;
132+
}
133+
}
134+
buffers.push(range);
135+
};
136+
137+
for i in i..(i + len) {
138+
// Encode the node
139+
push_buffer(&mut buffers, nodes[i].unwrap());
140+
141+
// Encode dependencies
142+
push_buffer(&mut buffers, edges[i].unwrap());
143+
}
144+
145+
for buffer in buffers {
146+
file.write_all(&d.data[buffer.0..buffer.1]).unwrap();
147+
}
148+
149+
i += len;
150+
}
151+
}
152+
153+
pub struct DecodedDepGraph {
154+
pub prev_graph: PreviousDepGraph,
155+
pub state: IndexVec<DepNodeIndex, AtomicCell<DepNodeState>>,
156+
pub invalidated: Vec<DepNodeIndex>,
157+
pub needs_gc: bool,
158+
}
159+
17160
pub fn decode_dep_graph(
18161
time_passes: bool,
19162
d: &mut opaque::Decoder<'_>,
20163
results_d: &mut opaque::Decoder<'_>,
21-
) -> Result<(
22-
PreviousDepGraph,
23-
IndexVec<DepNodeIndex, AtomicCell<DepNodeState>>,
24-
Vec<DepNodeIndex>,
25-
), String> {
164+
) -> Result<DecodedDepGraph, String> {
165+
// Metrics used to decided when to GC
166+
let mut valid_data = 0;
167+
let mut total_data = 0;
168+
26169
let fingerprints: IndexVec<DepNodeIndex, Fingerprint> =
27170
time_ext(time_passes, None, "decode prev result fingerprints", || {
28171
IndexVec::decode(results_d)
@@ -35,7 +178,6 @@ pub fn decode_dep_graph(
35178
let mut state: IndexVec<_, _> = (0..fingerprints.len()).map(|_| {
36179
AtomicCell::new(DepNodeState::Invalid)
37180
}).collect();
38-
let mut invalid = Vec::new();
39181
loop {
40182
if d.position() == d.data.len() {
41183
break;
@@ -48,29 +190,39 @@ pub fn decode_dep_graph(
48190
let i = DepNodeIndex::from_u32(start + i);
49191
let node = DepNode::decode(d)?;
50192
nodes[i] = node;
51-
edges[i] = Some(Box::<[DepNodeIndex]>::decode(d)?);
193+
let node_edges = Box::<[DepNodeIndex]>::decode(d)?;
194+
valid_data += node_edges.len();
195+
total_data += node_edges.len();
196+
edges[i] = Some(node_edges);
52197

53198
if unlikely!(node.kind.is_eval_always()) {
54199
state[i] = AtomicCell::new(DepNodeState::UnknownEvalAlways);
55200
} else {
56201
state[i] = AtomicCell::new(DepNodeState::Unknown);
57202
}
58203
}
204+
valid_data += len as usize * 8;
205+
total_data += len as usize * 8;
59206
}
60207
SerializedAction::UpdateEdges => {
61208
let len = d.read_u32()?;
62209
for _ in 0..len {
63210
let i = DepNodeIndex::decode(d)?;
64-
edges[i] = Some(Box::<[DepNodeIndex]>::decode(d)?);
211+
valid_data -= edges[i].as_ref().map_or(0, |edges| edges.len());
212+
let node_edges = Box::<[DepNodeIndex]>::decode(d)?;
213+
valid_data += node_edges.len();
214+
total_data += node_edges.len();
215+
edges[i] = Some(node_edges);
65216
}
66217
}
67218
SerializedAction::InvalidateNodes => {
68219
let len = d.read_u32()?;
69220
for _ in 0..len {
70221
let i = DepNodeIndex::decode(d)?;
222+
valid_data -= edges[i].as_ref().map_or(0, |edges| edges.len());
71223
state[i] = AtomicCell::new(DepNodeState::Invalid);
72-
invalid.push(i);
73224
}
225+
valid_data -= len as usize * 8;
74226
}
75227
}
76228
}
@@ -81,12 +233,27 @@ pub fn decode_dep_graph(
81233
.map(|(idx, dep_node)| (*dep_node, idx))
82234
.collect()
83235
});
84-
Ok((PreviousDepGraph {
85-
index,
86-
nodes,
87-
fingerprints,
88-
edges,
89-
}, state, invalid))
236+
237+
debug!(
238+
"valid bytes {} total bytes {} ratio {}",
239+
valid_data,
240+
total_data,
241+
valid_data as f32 / total_data as f32
242+
);
243+
244+
Ok(DecodedDepGraph {
245+
prev_graph: PreviousDepGraph {
246+
index,
247+
nodes,
248+
fingerprints,
249+
edges,
250+
},
251+
invalidated: state.indices()
252+
.filter(|&i| *state[i].get_mut() == DepNodeState::Invalid)
253+
.collect(),
254+
state,
255+
needs_gc: valid_data + valid_data / 3 < total_data,
256+
})
90257
}
91258

92259
#[derive(Debug, RustcDecodable, RustcEncodable)]

src/librustc_incremental/persist/load.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Code to save/load the dep-graph from files.
22
33
use rustc_data_structures::fx::FxHashMap;
4-
use rustc::dep_graph::{DepGraph, DepGraphArgs, decode_dep_graph};
4+
use rustc::dep_graph::{DepGraph, DepGraphArgs, decode_dep_graph, gc_dep_graph};
55
use rustc::session::Session;
66
use rustc::ty::TyCtxt;
77
use rustc::ty::query::OnDiskCache;
@@ -11,6 +11,7 @@ use rustc_serialize::opaque::Decoder;
1111
use rustc_serialize::Encodable;
1212
use std::path::Path;
1313
use std::fs::{self, File};
14+
use std::io::{Seek, SeekFrom};
1415

1516
use super::data::*;
1617
use super::fs::*;
@@ -225,7 +226,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
225226

226227
MaybeAsync::Async(std::thread::spawn(move || {
227228
time_ext(time_passes, None, "background load prev dep-graph", move || {
228-
let (bytes, pos, file) = match load_graph_file(
229+
let (bytes, pos, mut file) = match load_graph_file(
229230
report_incremental_info,
230231
&path,
231232
expected_hash
@@ -247,23 +248,35 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
247248

248249
let mut decoder = Decoder::new(&bytes, pos);
249250
let mut results_decoder = Decoder::new(&results_bytes, results_pos);
250-
time_ext(time_passes, None, "decode prev dep-graph", || {
251-
let (prev_graph, state, invalidated) = decode_dep_graph(
251+
252+
let result = time_ext(time_passes, None, "decode prev dep-graph", || {
253+
decode_dep_graph(
252254
time_passes,
253255
&mut decoder,
254256
&mut results_decoder,
255-
).expect("Error reading cached dep-graph");
256-
257-
LoadResult::Ok {
258-
data: DepGraphArgs {
259-
prev_graph,
260-
prev_work_products,
261-
file,
262-
state,
263-
invalidated,
264-
}
257+
).expect("Error reading cached dep-graph")
258+
});
259+
260+
if result.needs_gc {
261+
// Reset the file to just the header
262+
file.seek(SeekFrom::Start(pos as u64)).unwrap();
263+
file.set_len(pos as u64).unwrap();
264+
265+
time_ext(time_passes, None, "garbage collect prev dep-graph", || {
266+
let mut decoder = Decoder::new(&bytes, pos);
267+
gc_dep_graph(time_passes, &mut decoder, &result, &mut file);
268+
});
269+
}
270+
271+
LoadResult::Ok {
272+
data: DepGraphArgs {
273+
prev_graph: result.prev_graph,
274+
prev_work_products,
275+
file,
276+
state: result.state,
277+
invalidated: result.invalidated,
265278
}
266-
})
279+
}
267280
})
268281
}))
269282
}

0 commit comments

Comments
 (0)