1
Fork 0

Move iter_results to dyn FnMut rather than a generic

This means that we're no longer generating the iteration/locking code for each
invocation site of iter_results, rather just once per query.

This is a 15% win in instruction counts when compiling the rustc_query_impl crate.
This commit is contained in:
Mark Rousskov 2021-04-29 10:23:17 -04:00
parent c488f15700
commit a1d7367429
5 changed files with 53 additions and 47 deletions

View file

@ -1185,20 +1185,27 @@ where
assert!(Q::query_state(tcx).all_inactive()); assert!(Q::query_state(tcx).all_inactive());
let cache = Q::query_cache(tcx); let cache = Q::query_cache(tcx);
cache.iter_results(|results| { let mut res = Ok(());
for (key, value, dep_node) in results { cache.iter_results(&mut |key, value, dep_node| {
if res.is_err() {
return;
}
if Q::cache_on_disk(tcx, &key, Some(value)) { if Q::cache_on_disk(tcx, &key, Some(value)) {
let dep_node = SerializedDepNodeIndex::new(dep_node.index()); let dep_node = SerializedDepNodeIndex::new(dep_node.index());
// Record position of the cache entry. // Record position of the cache entry.
query_result_index query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
// Encode the type check tables with the `SerializedDepNodeIndex` // Encode the type check tables with the `SerializedDepNodeIndex`
// as tag. // as tag.
encoder.encode_tagged(dep_node, value)?; match encoder.encode_tagged(dep_node, value) {
Ok(()) => {}
Err(e) => {
res = Err(e);
} }
} }
Ok(()) }
}) });
res
} }

View file

@ -250,8 +250,8 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
// need to invoke queries itself, we cannot keep the query caches // need to invoke queries itself, we cannot keep the query caches
// locked while doing so. Instead we copy out the // locked while doing so. Instead we copy out the
// `(query_key, dep_node_index)` pairs and release the lock again. // `(query_key, dep_node_index)` pairs and release the lock again.
let query_keys_and_indices: Vec<_> = query_cache let mut query_keys_and_indices = Vec::new();
.iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect()); query_cache.iter_results(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i)));
// Now actually allocate the strings. If allocating the strings // Now actually allocate the strings. If allocating the strings
// generates new entries in the query cache, we'll miss them but // generates new entries in the query cache, we'll miss them but
@ -275,14 +275,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
let query_name = profiler.get_or_alloc_cached_string(query_name); let query_name = profiler.get_or_alloc_cached_string(query_name);
let event_id = event_id_builder.from_label(query_name).to_string_id(); let event_id = event_id_builder.from_label(query_name).to_string_id();
query_cache.iter_results(|results| { let mut query_invocation_ids = Vec::new();
let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect(); query_cache.iter_results(&mut |_, _, i| {
query_invocation_ids.push(i.into());
});
profiler.bulk_map_query_invocation_id_to_single_string( profiler.bulk_map_query_invocation_id_to_single_string(
query_invocation_ids.into_iter(), query_invocation_ids.into_iter(),
event_id, event_id,
); );
});
} }
}); });
} }

View file

@ -50,13 +50,12 @@ where
key_type: type_name::<C::Key>(), key_type: type_name::<C::Key>(),
value_size: mem::size_of::<C::Value>(), value_size: mem::size_of::<C::Value>(),
value_type: type_name::<C::Value>(), value_type: type_name::<C::Value>(),
entry_count: map.iter_results(|results| results.count()), entry_count: 0,
local_def_id_keys: None, local_def_id_keys: None,
}; };
map.iter_results(|results| { map.iter_results(&mut |key, _, _| {
for (key, _, _) in results { stats.entry_count += 1;
key.key_stats(&mut stats) key.key_stats(&mut stats)
}
}); });
stats stats
} }

View file

@ -49,13 +49,11 @@ pub trait QueryCache: QueryStorage {
index: DepNodeIndex, index: DepNodeIndex,
) -> Self::Stored; ) -> Self::Stored;
fn iter<R>( fn iter(
&self, &self,
shards: &Sharded<Self::Sharded>, shards: &Sharded<Self::Sharded>,
f: impl for<'a> FnOnce( f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
&'a mut dyn Iterator<Item = (&'a Self::Key, &'a Self::Value, DepNodeIndex)>, );
) -> R,
) -> R;
} }
pub struct DefaultCacheSelector; pub struct DefaultCacheSelector;
@ -124,14 +122,17 @@ where
value value
} }
fn iter<R>( fn iter(
&self, &self,
shards: &Sharded<Self::Sharded>, shards: &Sharded<Self::Sharded>,
f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
) -> R { ) {
let shards = shards.lock_shards(); let shards = shards.lock_shards();
let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); for shard in shards.iter() {
f(&mut results) for (k, v) in shard.iter() {
f(k, &v.0, v.1);
}
}
} }
} }
@ -207,13 +208,16 @@ where
&value.0 &value.0
} }
fn iter<R>( fn iter(
&self, &self,
shards: &Sharded<Self::Sharded>, shards: &Sharded<Self::Sharded>,
f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
) -> R { ) {
let shards = shards.lock_shards(); let shards = shards.lock_shards();
let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); for shard in shards.iter() {
f(&mut results) for (k, v) in shard.iter() {
f(k, &v.0, v.1);
}
}
} }
} }

View file

@ -73,12 +73,7 @@ impl<C: QueryCache> QueryCacheStore<C> {
(QueryLookup { key_hash, shard }, lock) (QueryLookup { key_hash, shard }, lock)
} }
pub fn iter_results<R>( pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex)) {
&self,
f: impl for<'a> FnOnce(
&'a mut dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)>,
) -> R,
) -> R {
self.cache.iter(&self.shards, f) self.cache.iter(&self.shards, f)
} }
} }