1 use crate::ty::query::caches::QueryCache;
2 use crate::ty::query::config::QueryAccessors;
3 use crate::ty::query::plumbing::QueryState;
4 use crate::ty::query::queries;
6 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
8 use std::any::type_name;
10 #[cfg(debug_assertions)]
11 use std::sync::atomic::Ordering;
14 fn key_stats(&self, stats: &mut QueryStats);
17 impl<T> KeyStats for T {
18 default fn key_stats(&self, _: &mut QueryStats) {}
21 impl KeyStats for DefId {
22 fn key_stats(&self, stats: &mut QueryStats) {
23 if self.krate == LOCAL_CRATE {
24 stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1);
34 key_type: &'static str,
36 value_type: &'static str,
38 local_def_id_keys: Option<usize>,
41 fn stats<'tcx, C: QueryCache>(name: &'static str, map: &QueryState<'tcx, C>) -> QueryStats {
42 let mut stats = QueryStats {
44 #[cfg(debug_assertions)]
45 cache_hits: map.cache_hits.load(Ordering::Relaxed),
46 #[cfg(not(debug_assertions))]
48 key_size: mem::size_of::<C::Key>(),
49 key_type: type_name::<C::Key>(),
50 value_size: mem::size_of::<C::Value>(),
51 value_type: type_name::<C::Value>(),
52 entry_count: map.iter_results(|results| results.count()),
53 local_def_id_keys: None,
55 map.iter_results(|results| {
56 for (key, _, _) in results {
57 key.key_stats(&mut stats)
63 pub fn print_stats(tcx: TyCtxt<'_>) {
64 let queries = query_stats(tcx);
66 if cfg!(debug_assertions) {
67 let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
68 let results: usize = queries.iter().map(|s| s.entry_count).sum();
69 println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
72 let mut query_key_sizes = queries.clone();
73 query_key_sizes.sort_by_key(|q| q.key_size);
74 println!("\nLarge query keys:");
75 for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
76 println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
79 let mut query_value_sizes = queries.clone();
80 query_value_sizes.sort_by_key(|q| q.value_size);
81 println!("\nLarge query values:");
82 for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
83 println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
86 if cfg!(debug_assertions) {
87 let mut query_cache_hits = queries.clone();
88 query_cache_hits.sort_by_key(|q| q.cache_hits);
89 println!("\nQuery cache hits:");
90 for q in query_cache_hits.iter().rev() {
95 q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
100 let mut query_value_count = queries.clone();
101 query_value_count.sort_by_key(|q| q.entry_count);
102 println!("\nQuery value count:");
103 for q in query_value_count.iter().rev() {
104 println!(" {} - {}", q.name, q.entry_count);
107 let mut def_id_density: Vec<_> =
108 queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
109 def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
110 println!("\nLocal DefId density:");
111 let total = tcx.hir().definitions().def_index_count() as f64;
112 for q in def_id_density.iter().rev() {
113 let local = q.local_def_id_keys.unwrap();
114 println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
118 macro_rules! print_stats {
119 (<$tcx:tt> $($category:tt {
120 $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
122 fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
123 let mut queries = Vec::new();
126 queries.push(stats::<
127 <queries::$name<'_> as QueryAccessors<'_>>::Cache,
139 rustc_query_append! { [print_stats!][<'tcx>] }