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