Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial support for recording query keys in self-profiling data.
- Loading branch information
1 parent
996511a
commit b8ead41
Showing
9 changed files
with
354 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
|
||
use crate::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, DefIndex, LOCAL_CRATE}; | ||
use crate::hir::map::definitions::DefPathData; | ||
use crate::ty::context::TyCtxt; | ||
use crate::ty::query::config::QueryConfig; | ||
use crate::ty::query::plumbing::QueryCache; | ||
use measureme::{StringId, StringComponent}; | ||
use rustc_data_structures::fx::FxHashMap; | ||
use rustc_data_structures::profiling::SelfProfiler; | ||
use rustc_data_structures::sharded::Sharded; | ||
use std::fmt::Debug; | ||
use std::io::Write; | ||
|
||
pub struct QueryKeyStringCache { | ||
def_id_cache: FxHashMap<DefId, StringId>, | ||
} | ||
|
||
impl QueryKeyStringCache { | ||
pub fn new() -> QueryKeyStringCache { | ||
QueryKeyStringCache { | ||
def_id_cache: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> { | ||
profiler: &'p SelfProfiler, | ||
tcx: TyCtxt<'tcx>, | ||
string_cache: &'c mut QueryKeyStringCache, | ||
} | ||
|
||
impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { | ||
|
||
pub fn new( | ||
profiler: &'p SelfProfiler, | ||
tcx: TyCtxt<'tcx>, | ||
string_cache: &'c mut QueryKeyStringCache, | ||
) -> QueryKeyStringBuilder<'p, 'c, 'tcx> { | ||
QueryKeyStringBuilder { | ||
profiler, | ||
tcx, | ||
string_cache, | ||
} | ||
} | ||
|
||
// The current implementation is rather crude. In the future it might be a | ||
// good idea to base this on `ty::print` in order to get nicer and more | ||
// efficient query keys. | ||
fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId { | ||
|
||
if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) { | ||
return string_id; | ||
} | ||
|
||
let def_key = self.tcx.def_key(def_id); | ||
|
||
let (parent_string_id, start_index) = match def_key.parent { | ||
Some(parent_index) => { | ||
let parent_def_id = DefId { | ||
index: parent_index, | ||
krate: def_id.krate, | ||
}; | ||
|
||
(self.def_id_to_string_id(parent_def_id), 0) | ||
} | ||
None => { | ||
(StringId::INVALID, 2) | ||
} | ||
}; | ||
|
||
let dis_buffer = &mut [0u8; 16]; | ||
let name; | ||
let dis; | ||
let end_index; | ||
|
||
match def_key.disambiguated_data.data { | ||
DefPathData::CrateRoot => { | ||
name = self.tcx.original_crate_name(def_id.krate).as_str(); | ||
dis = ""; | ||
end_index = 3; | ||
} | ||
other => { | ||
name = other.as_symbol().as_str(); | ||
if def_key.disambiguated_data.disambiguator == 0 { | ||
dis = ""; | ||
end_index = 3; | ||
} else { | ||
write!(&mut dis_buffer[..], | ||
"[{}]", | ||
def_key.disambiguated_data.disambiguator | ||
).unwrap(); | ||
let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); | ||
dis = std::str::from_utf8(&dis_buffer[.. end_of_dis + 1]).unwrap(); | ||
end_index = 4; | ||
} | ||
} | ||
} | ||
|
||
let components = [ | ||
StringComponent::Ref(parent_string_id), | ||
StringComponent::Value("::"), | ||
StringComponent::Value(&name[..]), | ||
StringComponent::Value(dis) | ||
]; | ||
|
||
let string_id = self.profiler.alloc_string( | ||
&components[start_index .. end_index] | ||
); | ||
|
||
self.string_cache.def_id_cache.insert(def_id, string_id); | ||
|
||
string_id | ||
} | ||
} | ||
|
||
pub trait IntoSelfProfilingString { | ||
fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId; | ||
} | ||
|
||
// The default implementation of `IntoSelfProfilingString` just uses `Debug` | ||
// which is slow and causes lots of duplication of string data. | ||
// The specialized impls below take care of making the `DefId` case more | ||
// efficient. | ||
impl<T: Debug> IntoSelfProfilingString for T { | ||
|
||
default fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId { | ||
let s = format!("{:?}", self); | ||
builder.profiler.alloc_string(&s[..]) | ||
} | ||
} | ||
|
||
impl IntoSelfProfilingString for DefId { | ||
|
||
fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId { | ||
builder.def_id_to_string_id(*self) | ||
} | ||
} | ||
|
||
impl IntoSelfProfilingString for CrateNum { | ||
|
||
fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId { | ||
builder.def_id_to_string_id(DefId { | ||
krate: *self, | ||
index: CRATE_DEF_INDEX, | ||
}) | ||
} | ||
} | ||
|
||
impl IntoSelfProfilingString for DefIndex { | ||
|
||
fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId { | ||
builder.def_id_to_string_id(DefId { | ||
krate: LOCAL_CRATE, | ||
index: *self, | ||
}) | ||
} | ||
} | ||
|
||
impl<T0, T1> IntoSelfProfilingString for (T0, T1) | ||
where T0: IntoSelfProfilingString+Debug, | ||
T1: IntoSelfProfilingString+Debug, | ||
{ | ||
default fn to_self_profile_string( | ||
&self, | ||
builder: &mut QueryKeyStringBuilder<'_, '_, '_> | ||
) -> StringId { | ||
|
||
let val0 = self.0.to_self_profile_string(builder); | ||
let val1 = self.1.to_self_profile_string(builder); | ||
|
||
let components = &[ | ||
StringComponent::Value("("), | ||
StringComponent::Ref(val0), | ||
StringComponent::Value(","), | ||
StringComponent::Ref(val1), | ||
StringComponent::Value(")"), | ||
]; | ||
|
||
builder.profiler.alloc_string(components) | ||
} | ||
} | ||
|
||
/// Allocate the self-profiling query strings for a single query cache. This | ||
/// method is called from `alloc_self_profile_query_strings` which knows all | ||
/// the queries via macro magic. | ||
pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>( | ||
tcx: TyCtxt<'tcx>, | ||
query_name: &'static str, | ||
query_cache: &Sharded<QueryCache<'tcx, Q>>, | ||
string_cache: &mut QueryKeyStringCache, | ||
) where Q: QueryConfig<'tcx> { | ||
tcx.prof.with_profiler(|profiler| { | ||
let event_id_builder = profiler.event_id_builder(); | ||
|
||
// Walk the entire query cache and allocate the appropriate | ||
// string representations. Each cache entry is uniquely | ||
// identified by its dep_node_index. | ||
if profiler.query_key_recording_enabled() { | ||
let mut query_string_builder = | ||
QueryKeyStringBuilder::new(profiler, tcx, string_cache); | ||
|
||
let query_name = profiler.get_or_alloc_cached_string(query_name); | ||
|
||
// Since building the string representation of query keys might | ||
// need to invoke queries itself, we cannot keep the query caches | ||
// locked while doing so. Instead we copy out the | ||
// `(query_key, dep_node_index)` pairs and release the lock again. | ||
let query_keys_and_indices = { | ||
let shards = query_cache.lock_shards(); | ||
let len = shards.iter().map(|shard| shard.results.len()).sum(); | ||
|
||
let mut query_keys_and_indices = Vec::with_capacity(len); | ||
|
||
for shard in &shards { | ||
query_keys_and_indices.extend(shard.results.iter().map(|(q_key, q_val)| { | ||
(q_key.clone(), q_val.index) | ||
})); | ||
} | ||
|
||
query_keys_and_indices | ||
}; | ||
|
||
// Now actually allocate the strings. If allocating the strings | ||
// generates new entries in the query cache, we'll miss them but | ||
// we don't actually care. | ||
for (query_key, dep_node_index) in query_keys_and_indices { | ||
// Translate the DepNodeIndex into a QueryInvocationId | ||
let query_invocation_id = dep_node_index.into(); | ||
|
||
// Create the string version of the query-key | ||
let query_key = query_key.to_self_profile_string(&mut query_string_builder); | ||
let event_id = event_id_builder.from_label_and_arg(query_name, query_key); | ||
|
||
// Doing this in bulk might be a good idea: | ||
profiler.map_query_invocation_id_to_string( | ||
query_invocation_id, | ||
event_id.to_string_id(), | ||
); | ||
} | ||
} else { | ||
// In this branch we don't allocate query keys | ||
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 shards = query_cache.lock_shards(); | ||
|
||
for shard in shards.iter() { | ||
let query_invocation_ids = shard | ||
.results | ||
.values() | ||
.map(|v| v.index) | ||
.map(|dep_node_index| dep_node_index.into()); | ||
|
||
profiler.bulk_map_query_invocation_id_to_single_string( | ||
query_invocation_ids, | ||
event_id, | ||
); | ||
} | ||
} | ||
}); | ||
} |
Oops, something went wrong.