Skip to content

Commit b908c05

Browse files
authored
Preallocate more things (#21964)
# Objective - Part of #20115 We should try to minimize allocations where its easy to do so. ## Solution Pre-allocate things upfront where we know their exact resulting size. ## Testing It'd probably be good to benchmark to see how much (if any) this helps.
1 parent 42a2575 commit b908c05

File tree

3 files changed

+44
-8
lines changed

3 files changed

+44
-8
lines changed

crates/bevy_ecs/src/schedule/graph/dag.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ impl<N: GraphNodeId, S: BuildHasher> DagAnalysis<N, S> {
287287

288288
// build a copy of the graph where the nodes and edges appear in topsorted order
289289
let mut map = <HashMap<_, _>>::with_capacity_and_hasher(n, Default::default());
290-
let mut topsorted = DiGraph::<N>::default();
290+
let mut topsorted =
291+
DiGraph::<N>::with_capacity(topological_order.len(), graph.edge_count());
292+
291293
// iterate nodes in topological order
292294
for (i, &node) in topological_order.iter().enumerate() {
293295
map.insert(node, i);
@@ -302,8 +304,8 @@ impl<N: GraphNodeId, S: BuildHasher> DagAnalysis<N, S> {
302304
let mut connected = HashSet::default();
303305
let mut disconnected = Vec::default();
304306
let mut transitive_edges = Vec::default();
305-
let mut transitive_reduction = DiGraph::default();
306-
let mut transitive_closure = DiGraph::default();
307+
let mut transitive_reduction = DiGraph::with_capacity(topsorted.node_count(), 0);
308+
let mut transitive_closure = DiGraph::with_capacity(topsorted.node_count(), 0);
307309

308310
let mut visited = FixedBitSet::with_capacity(n);
309311

@@ -605,6 +607,7 @@ impl<K: GraphNodeId, V: GraphNodeId, S: BuildHasher> DagGroups<K, V, S> {
605607
// Remove the key node from the graph.
606608
flattening.remove_node(N::from(key));
607609
// Add all previously collected edges.
610+
flattening.reserve_edges(temp.len());
608611
for (a, b) in temp.drain(..) {
609612
flattening.add_edge(a, b);
610613
}
@@ -636,20 +639,35 @@ impl<K: GraphNodeId, V: GraphNodeId, S: BuildHasher> DagGroups<K, V, S> {
636639
}
637640
(Err(lhs_key), Ok(rhs)) => {
638641
// Edge from a key node to a value node, expand to all values in the key's group
639-
for &lhs in self.get(&lhs_key).into_iter().flatten() {
642+
let Some(lhs_group) = self.get(&lhs_key) else {
643+
continue;
644+
};
645+
flattened.reserve_edges(lhs_group.len());
646+
for &lhs in lhs_group {
640647
flattened.add_edge(lhs, rhs);
641648
}
642649
}
643650
(Ok(lhs), Err(rhs_key)) => {
644651
// Edge from a value node to a key node, expand to all values in the key's group
645-
for &rhs in self.get(&rhs_key).into_iter().flatten() {
652+
let Some(rhs_group) = self.get(&rhs_key) else {
653+
continue;
654+
};
655+
flattened.reserve_edges(rhs_group.len());
656+
for &rhs in rhs_group {
646657
flattened.add_edge(lhs, rhs);
647658
}
648659
}
649660
(Err(lhs_key), Err(rhs_key)) => {
650661
// Edge between two key nodes, expand to all combinations of their value nodes
651-
for &lhs in self.get(&lhs_key).into_iter().flatten() {
652-
for &rhs in self.get(&rhs_key).into_iter().flatten() {
662+
let Some(lhs_group) = self.get(&lhs_key) else {
663+
continue;
664+
};
665+
let Some(rhs_group) = self.get(&rhs_key) else {
666+
continue;
667+
};
668+
flattened.reserve_edges(lhs_group.len() * rhs_group.len());
669+
for &lhs in lhs_group {
670+
for &rhs in rhs_group {
653671
flattened.add_edge(lhs, rhs);
654672
}
655673
}

crates/bevy_ecs/src/schedule/graph/graph_map.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,18 @@ impl<const DIRECTED: bool, N: GraphNodeId, S: BuildHasher> Graph<DIRECTED, N, S>
208208
self.edges.contains(&Self::edge_key(a, b))
209209
}
210210

211+
/// Reserve capacity for at least `additional` more nodes to be inserted
212+
/// in the graph.
213+
pub fn reserve_nodes(&mut self, additional: usize) {
214+
self.nodes.reserve(additional);
215+
}
216+
217+
/// Reserve capacity for at least `additional` more edges to be inserted
218+
/// in the graph.
219+
pub fn reserve_edges(&mut self, additional: usize) {
220+
self.edges.reserve(additional);
221+
}
222+
211223
/// Return an iterator over the nodes of the graph.
212224
pub fn nodes(&self) -> impl DoubleEndedIterator<Item = N> + ExactSizeIterator<Item = N> + '_ {
213225
self.nodes.keys().copied()
@@ -402,7 +414,7 @@ impl<N: GraphNodeId, S: BuildHasher> DiGraph<N, S> {
402414

403415
while let Some(mut scc) = sccs.pop() {
404416
// only look at nodes and edges in this strongly-connected component
405-
let mut subgraph = DiGraph::<N>::default();
417+
let mut subgraph = DiGraph::<N>::with_capacity(scc.len(), 0);
406418
for &node in &scc {
407419
subgraph.add_node(node);
408420
}

crates/bevy_ecs/src/schedule/schedule.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,8 @@ impl ScheduleGraph {
842842
&previous_result.nodes
843843
};
844844

845+
self.dependency
846+
.reserve_edges(previous_nodes.len() * current_nodes.len());
845847
for previous_node in previous_nodes {
846848
for current_node in current_nodes {
847849
self.dependency.add_edge(*previous_node, *current_node);
@@ -935,6 +937,8 @@ impl ScheduleGraph {
935937
let in_nodes: Vec<_> = self.hierarchy.neighbors_directed(node, Incoming).collect();
936938
let out_nodes: Vec<_> = self.hierarchy.neighbors_directed(node, Outgoing).collect();
937939

940+
self.hierarchy
941+
.reserve_edges(in_nodes.len() * out_nodes.len());
938942
for &in_node in &in_nodes {
939943
for &out_node in &out_nodes {
940944
self.hierarchy.add_edge(in_node, out_node);
@@ -944,6 +948,8 @@ impl ScheduleGraph {
944948
let in_nodes: Vec<_> = self.dependency.neighbors_directed(node, Incoming).collect();
945949
let out_nodes: Vec<_> = self.dependency.neighbors_directed(node, Outgoing).collect();
946950

951+
self.dependency
952+
.reserve_edges(in_nodes.len() * out_nodes.len());
947953
for &in_node in &in_nodes {
948954
for &out_node in &out_nodes {
949955
self.dependency.add_edge(in_node, out_node);

0 commit comments

Comments
 (0)