Split ScheduleGraph::process_configs function (adopted) (#12435)

Adoption of #10617, resolved conflicts with main

---------

Co-authored-by: Stepan Koltsov <stepan.koltsov@gmail.com>
This commit is contained in:
Jonathan 2024-03-17 04:00:37 +02:00 committed by GitHub
parent 1323de7cd7
commit e9dc270d68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -661,6 +661,42 @@ impl ScheduleGraph {
&self.conflicting_systems &self.conflicting_systems
} }
fn process_config<T: ProcessNodeConfig>(
&mut self,
config: NodeConfig<T>,
collect_nodes: bool,
) -> ProcessConfigsResult {
ProcessConfigsResult {
densely_chained: true,
nodes: collect_nodes
.then_some(T::process_config(self, config))
.into_iter()
.collect(),
}
}
fn apply_collective_conditions<T: ProcessNodeConfig>(
&mut self,
configs: &mut [NodeConfigs<T>],
collective_conditions: Vec<BoxedCondition>,
) {
if !collective_conditions.is_empty() {
if let [config] = configs {
for condition in collective_conditions {
config.run_if_dyn(condition);
}
} else {
let set = self.create_anonymous_set();
for config in configs.iter_mut() {
config.in_set_inner(set.intern());
}
let mut set_config = SystemSetConfig::new(set.intern());
set_config.conditions.extend(collective_conditions);
self.configure_set_inner(set_config).unwrap();
}
}
}
/// Adds the config nodes to the graph. /// Adds the config nodes to the graph.
/// ///
/// `collect_nodes` controls whether the `NodeId`s of the processed config nodes are stored in the returned [`ProcessConfigsResult`]. /// `collect_nodes` controls whether the `NodeId`s of the processed config nodes are stored in the returned [`ProcessConfigsResult`].
@ -676,157 +712,75 @@ impl ScheduleGraph {
collect_nodes: bool, collect_nodes: bool,
) -> ProcessConfigsResult { ) -> ProcessConfigsResult {
match configs { match configs {
NodeConfigs::NodeConfig(config) => { NodeConfigs::NodeConfig(config) => self.process_config(config, collect_nodes),
let node_id = T::process_config(self, config);
if collect_nodes {
ProcessConfigsResult {
densely_chained: true,
nodes: vec![node_id],
}
} else {
ProcessConfigsResult {
densely_chained: true,
nodes: Vec::new(),
}
}
}
NodeConfigs::Configs { NodeConfigs::Configs {
mut configs, mut configs,
collective_conditions, collective_conditions,
chained, chained,
} => { } => {
let more_than_one_entry = configs.len() > 1; self.apply_collective_conditions(&mut configs, collective_conditions);
if !collective_conditions.is_empty() {
if more_than_one_entry { let ignore_deferred = matches!(chained, Chain::YesIgnoreDeferred);
let set = self.create_anonymous_set(); let chained = matches!(chained, Chain::Yes | Chain::YesIgnoreDeferred);
for config in &mut configs {
config.in_set_inner(set.intern()); // Densely chained if
} // * chained and all configs in the chain are densely chained, or
let mut set_config = SystemSetConfig::new(set.intern()); // * unchained with a single densely chained config
set_config.conditions.extend(collective_conditions); let mut densely_chained = chained || configs.len() == 1;
self.configure_set_inner(set_config).unwrap(); let mut configs = configs.into_iter();
} else { let mut nodes = Vec::new();
for condition in collective_conditions {
configs[0].run_if_dyn(condition); let Some(first) = configs.next() else {
}
}
}
let mut config_iter = configs.into_iter();
let mut nodes_in_scope = Vec::new();
let mut densely_chained = true;
if chained == Chain::Yes || chained == Chain::YesIgnoreDeferred {
let Some(prev) = config_iter.next() else {
return ProcessConfigsResult { return ProcessConfigsResult {
nodes: Vec::new(), nodes: Vec::new(),
densely_chained: true, densely_chained,
}; };
}; };
let mut previous_result = self.process_configs(prev, true); let mut previous_result = self.process_configs(first, collect_nodes || chained);
densely_chained = previous_result.densely_chained; densely_chained &= previous_result.densely_chained;
for current in config_iter {
let current_result = self.process_configs(current, true);
densely_chained = densely_chained && current_result.densely_chained;
match (
previous_result.densely_chained,
current_result.densely_chained,
) {
// Both groups are "densely" chained, so we can simplify the graph by only
// chaining the last in the previous list to the first in the current list
(true, true) => {
let last_in_prev = previous_result.nodes.last().unwrap();
let first_in_current = current_result.nodes.first().unwrap();
self.dependency.graph.add_edge(
*last_in_prev,
*first_in_current,
(),
);
if chained == Chain::YesIgnoreDeferred { for current in configs {
self.no_sync_edges let current_result = self.process_configs(current, collect_nodes || chained);
.insert((*last_in_prev, *first_in_current)); densely_chained &= current_result.densely_chained;
}
}
// The previous group is "densely" chained, so we can simplify the graph by only
// chaining the last item from the previous list to every item in the current list
(true, false) => {
let last_in_prev = previous_result.nodes.last().unwrap();
for current_node in &current_result.nodes {
self.dependency.graph.add_edge(
*last_in_prev,
*current_node,
(),
);
if chained == Chain::YesIgnoreDeferred { if chained {
self.no_sync_edges.insert((*last_in_prev, *current_node)); // if the current result is densely chained, we only need to chain the first node
} let current_nodes = if current_result.densely_chained {
} &current_result.nodes[..1]
} } else {
// The current list is currently "densely" chained, so we can simplify the graph by &current_result.nodes
// only chaining every item in the previous list to the first item in the current list };
(false, true) => { // if the previous result was densely chained, we only need to chain the last node
let first_in_current = current_result.nodes.first().unwrap(); let previous_nodes = if previous_result.densely_chained {
for previous_node in &previous_result.nodes { &previous_result.nodes[previous_result.nodes.len() - 1..]
self.dependency.graph.add_edge( } else {
*previous_node, &previous_result.nodes
*first_in_current, };
(),
);
if chained == Chain::YesIgnoreDeferred { for previous_node in previous_nodes {
self.no_sync_edges for current_node in current_nodes {
.insert((*previous_node, *first_in_current)); self.dependency
} .graph
} .add_edge(*previous_node, *current_node, ());
}
// Neither of the lists are "densely" chained, so we must chain every item in the first
// list to every item in the second list
(false, false) => {
for previous_node in &previous_result.nodes {
for current_node in &current_result.nodes {
self.dependency.graph.add_edge(
*previous_node,
*current_node,
(),
);
if chained == Chain::YesIgnoreDeferred { if ignore_deferred {
self.no_sync_edges self.no_sync_edges.insert((*previous_node, *current_node));
.insert((*previous_node, *current_node));
} }
} }
} }
} }
}
if collect_nodes { if collect_nodes {
nodes_in_scope.append(&mut previous_result.nodes); nodes.append(&mut previous_result.nodes);
} }
previous_result = current_result; previous_result = current_result;
} }
// ensure the last config's nodes are added
if collect_nodes { if collect_nodes {
nodes_in_scope.append(&mut previous_result.nodes); nodes.append(&mut previous_result.nodes);
}
} else {
for config in config_iter {
let result = self.process_configs(config, collect_nodes);
densely_chained = densely_chained && result.densely_chained;
if collect_nodes {
nodes_in_scope.extend(result.nodes);
}
}
// an "unchained" SystemConfig is only densely chained if it has exactly one densely chained entry
if more_than_one_entry {
densely_chained = false;
}
} }
ProcessConfigsResult { ProcessConfigsResult {
nodes: nodes_in_scope, nodes,
densely_chained, densely_chained,
} }
} }