• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // $ cargo bench --features full,test --bench rust
2 //
3 // Syn only, useful for profiling:
4 // $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full,test --bench rust
5 
6 #![cfg_attr(not(syn_only), feature(rustc_private))]
7 #![recursion_limit = "1024"]
8 #![allow(
9     clippy::cast_lossless,
10     clippy::let_underscore_untyped,
11     clippy::manual_let_else,
12     clippy::match_like_matches_macro,
13     clippy::uninlined_format_args,
14     clippy::unnecessary_wraps
15 )]
16 
17 #[macro_use]
18 #[path = "../tests/macros/mod.rs"]
19 mod macros;
20 
21 #[allow(dead_code)]
22 #[path = "../tests/repo/mod.rs"]
23 mod repo;
24 
25 use std::fs;
26 use std::time::{Duration, Instant};
27 
28 #[cfg(not(syn_only))]
29 mod tokenstream_parse {
30     use proc_macro2::TokenStream;
31     use std::str::FromStr;
32 
bench(content: &str) -> Result<(), ()>33     pub fn bench(content: &str) -> Result<(), ()> {
34         TokenStream::from_str(content).map(drop).map_err(drop)
35     }
36 }
37 
38 mod syn_parse {
bench(content: &str) -> Result<(), ()>39     pub fn bench(content: &str) -> Result<(), ()> {
40         syn::parse_file(content).map(drop).map_err(drop)
41     }
42 }
43 
44 #[cfg(not(syn_only))]
45 mod librustc_parse {
46     extern crate rustc_data_structures;
47     extern crate rustc_driver;
48     extern crate rustc_error_messages;
49     extern crate rustc_errors;
50     extern crate rustc_parse;
51     extern crate rustc_session;
52     extern crate rustc_span;
53 
54     use rustc_data_structures::sync::Lrc;
55     use rustc_error_messages::FluentBundle;
56     use rustc_errors::{emitter::Emitter, translation::Translate, Diagnostic, Handler};
57     use rustc_session::parse::ParseSess;
58     use rustc_span::source_map::{FilePathMapping, SourceMap};
59     use rustc_span::{edition::Edition, FileName};
60 
bench(content: &str) -> Result<(), ()>61     pub fn bench(content: &str) -> Result<(), ()> {
62         struct SilentEmitter;
63 
64         impl Emitter for SilentEmitter {
65             fn emit_diagnostic(&mut self, _diag: &Diagnostic) {}
66             fn source_map(&self) -> Option<&Lrc<SourceMap>> {
67                 None
68             }
69         }
70 
71         impl Translate for SilentEmitter {
72             fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
73                 None
74             }
75             fn fallback_fluent_bundle(&self) -> &FluentBundle {
76                 panic!("silent emitter attempted to translate a diagnostic");
77             }
78         }
79 
80         rustc_span::create_session_if_not_set_then(Edition::Edition2018, |_| {
81             let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
82             let emitter = Box::new(SilentEmitter);
83             let handler = Handler::with_emitter(emitter);
84             let sess = ParseSess::with_span_handler(handler, cm);
85             if let Err(diagnostic) = rustc_parse::parse_crate_from_source_str(
86                 FileName::Custom("bench".to_owned()),
87                 content.to_owned(),
88                 &sess,
89             ) {
90                 diagnostic.cancel();
91                 return Err(());
92             };
93             Ok(())
94         })
95     }
96 }
97 
98 #[cfg(not(syn_only))]
99 mod read_from_disk {
bench(content: &str) -> Result<(), ()>100     pub fn bench(content: &str) -> Result<(), ()> {
101         let _ = content;
102         Ok(())
103     }
104 }
105 
exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration106 fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
107     let begin = Instant::now();
108     let mut success = 0;
109     let mut total = 0;
110 
111     ["tests/rust/compiler", "tests/rust/library"]
112         .iter()
113         .flat_map(|dir| {
114             walkdir::WalkDir::new(dir)
115                 .into_iter()
116                 .filter_entry(repo::base_dir_filter)
117         })
118         .for_each(|entry| {
119             let entry = entry.unwrap();
120             let path = entry.path();
121             if path.is_dir() {
122                 return;
123             }
124             let content = fs::read_to_string(path).unwrap();
125             let ok = codepath(&content).is_ok();
126             success += ok as usize;
127             total += 1;
128             if !ok {
129                 eprintln!("FAIL {}", path.display());
130             }
131         });
132 
133     assert_eq!(success, total);
134     begin.elapsed()
135 }
136 
main()137 fn main() {
138     repo::clone_rust();
139 
140     macro_rules! testcases {
141         ($($(#[$cfg:meta])* $name:ident,)*) => {
142             [
143                 $(
144                     $(#[$cfg])*
145                     (stringify!($name), $name::bench as fn(&str) -> Result<(), ()>),
146                 )*
147             ]
148         };
149     }
150 
151     #[cfg(not(syn_only))]
152     {
153         let mut lines = 0;
154         let mut files = 0;
155         exec(|content| {
156             lines += content.lines().count();
157             files += 1;
158             Ok(())
159         });
160         eprintln!("\n{} lines in {} files", lines, files);
161     }
162 
163     for (name, f) in testcases!(
164         #[cfg(not(syn_only))]
165         read_from_disk,
166         #[cfg(not(syn_only))]
167         tokenstream_parse,
168         syn_parse,
169         #[cfg(not(syn_only))]
170         librustc_parse,
171     ) {
172         eprint!("{:20}", format!("{}:", name));
173         let elapsed = exec(f);
174         eprintln!(
175             "elapsed={}.{:03}s",
176             elapsed.as_secs(),
177             elapsed.subsec_millis(),
178         );
179     }
180     eprintln!();
181 }
182