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