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