]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/query/stats.rs
a13f00dc6d4eeb18b8a552aaa5e357a78c8de6cc
[rust.git] / src / librustc / ty / query / stats.rs
1 use crate::ty::query::caches::QueryCache;
2 use crate::ty::query::config::{QueryAccessors, QueryContext};
3 use crate::ty::query::plumbing::QueryState;
4 use crate::ty::query::queries;
5 use crate::ty::TyCtxt;
6 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
7
8 use std::any::type_name;
9 use std::mem;
10 #[cfg(debug_assertions)]
11 use std::sync::atomic::Ordering;
12
13 trait KeyStats {
14     fn key_stats(&self, stats: &mut QueryStats);
15 }
16
17 impl<T> KeyStats for T {
18     default fn key_stats(&self, _: &mut QueryStats) {}
19 }
20
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);
25         }
26     }
27 }
28
29 #[derive(Clone)]
30 struct QueryStats {
31     name: &'static str,
32     cache_hits: usize,
33     key_size: usize,
34     key_type: &'static str,
35     value_size: usize,
36     value_type: &'static str,
37     entry_count: usize,
38     local_def_id_keys: Option<usize>,
39 }
40
41 fn stats<CTX: QueryContext, C: QueryCache<CTX>>(
42     name: &'static str,
43     map: &QueryState<CTX, C>,
44 ) -> QueryStats {
45     let mut stats = QueryStats {
46         name,
47         #[cfg(debug_assertions)]
48         cache_hits: map.cache_hits.load(Ordering::Relaxed),
49         #[cfg(not(debug_assertions))]
50         cache_hits: 0,
51         key_size: mem::size_of::<C::Key>(),
52         key_type: type_name::<C::Key>(),
53         value_size: mem::size_of::<C::Value>(),
54         value_type: type_name::<C::Value>(),
55         entry_count: map.iter_results(|results| results.count()),
56         local_def_id_keys: None,
57     };
58     map.iter_results(|results| {
59         for (key, _, _) in results {
60             key.key_stats(&mut stats)
61         }
62     });
63     stats
64 }
65
66 pub fn print_stats(tcx: TyCtxt<'_>) {
67     let queries = query_stats(tcx);
68
69     if cfg!(debug_assertions) {
70         let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
71         let results: usize = queries.iter().map(|s| s.entry_count).sum();
72         println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
73     }
74
75     let mut query_key_sizes = queries.clone();
76     query_key_sizes.sort_by_key(|q| q.key_size);
77     println!("\nLarge query keys:");
78     for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
79         println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
80     }
81
82     let mut query_value_sizes = queries.clone();
83     query_value_sizes.sort_by_key(|q| q.value_size);
84     println!("\nLarge query values:");
85     for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
86         println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
87     }
88
89     if cfg!(debug_assertions) {
90         let mut query_cache_hits = queries.clone();
91         query_cache_hits.sort_by_key(|q| q.cache_hits);
92         println!("\nQuery cache hits:");
93         for q in query_cache_hits.iter().rev() {
94             println!(
95                 "   {} - {} ({}%)",
96                 q.name,
97                 q.cache_hits,
98                 q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
99             );
100         }
101     }
102
103     let mut query_value_count = queries.clone();
104     query_value_count.sort_by_key(|q| q.entry_count);
105     println!("\nQuery value count:");
106     for q in query_value_count.iter().rev() {
107         println!("   {} - {}", q.name, q.entry_count);
108     }
109
110     let mut def_id_density: Vec<_> =
111         queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
112     def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
113     println!("\nLocal DefId density:");
114     let total = tcx.hir().definitions().def_index_count() as f64;
115     for q in def_id_density.iter().rev() {
116         let local = q.local_def_id_keys.unwrap();
117         println!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
118     }
119 }
120
121 macro_rules! print_stats {
122     (<$tcx:tt> $($category:tt {
123         $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
124     },)*) => {
125         fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
126             let mut queries = Vec::new();
127
128             $($(
129                 queries.push(stats::<
130                     TyCtxt<'_>,
131                     <queries::$name<'_> as QueryAccessors<TyCtxt<'_>>>::Cache,
132                 >(
133                     stringify!($name),
134                     &tcx.queries.$name,
135                 ));
136             )*)*
137
138             queries
139         }
140     }
141 }
142
143 rustc_query_append! { [print_stats!][<'tcx>] }