Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve debug mode perf of proc_macro wrapper #238

Merged
merged 2 commits into from
Jun 18, 2020
Merged

Improve debug mode perf of proc_macro wrapper #238

merged 2 commits into from
Jun 18, 2020

Conversation

dtolnay
Copy link
Owner

@dtolnay dtolnay commented Jun 18, 2020

I dropped the following code (below; extracted from https://github.com/rylev/winrt-profile) into a dummy proc macro crate to measure the impact on winrt's code generation.

Basically it seems there are two things it's sensitive to:

  • Reducing the number of calls over the proc macro bridge (roughly: number of times anything in real proc_macro gets called) can significantly improve performance.
  • Reducing various overheads in the proc-macro2 wrapper layer can significantly improve performance.

This PR includes two commits, one of each type. There are certainly more of each left to do. So far in total this improves expansion time by 10%.


use proc_macro2::TokenStream;
use std::fs;
use std::time::Instant;
use winrt_gen::{NamespaceTypes, TypeLimit, TypeLimits, TypeReader, TypeStage, WinmdFile};

let mut paths = Vec::new();
for f in fs::read_dir("winmds").unwrap() {
    let path = f.unwrap().path();
    paths.push(WinmdFile::new(path));
}
let begin = Instant::now();
let reader = TypeReader::new(paths);
let mut limits = TypeLimits::new(&reader);
let types = NamespaceTypes {
    namespace: "windows.ui.xaml".into(),
    limit: TypeLimit::All,
};
limits.insert(types).unwrap();
let stage = TypeStage::from_limits(&reader, &limits);
let tree = stage.into_tree();
let out: TokenStream = tree.to_tokens().collect();
println!("ELAPSED: {:?}", begin.elapsed());

Ref dtolnay/quote#160

I dropped this code into a proc macro in a dummy crate to measure the
impact on winrt's code generation. Before: 10.2 seconds. After: 9.6
seconds.

    use proc_macro2::TokenStream;
    use std::fs;
    use std::time::Instant;
    use winrt_gen::{NamespaceTypes, TypeLimit, TypeLimits, TypeReader, TypeStage, WinmdFile};

    let mut paths = Vec::new();
    for f in fs::read_dir("winmds").unwrap() {
        let path = f.unwrap().path();
        paths.push(WinmdFile::new(path));
    }
    let begin = Instant::now();
    let reader = TypeReader::new(paths);
    let mut limits = TypeLimits::new(&reader);
    let types = NamespaceTypes {
        namespace: "windows.ui.xaml".into(),
        limit: TypeLimit::All,
    };
    limits.insert(types).unwrap();
    let stage = TypeStage::from_limits(&reader, &limits);
    let tree = stage.into_tree();
    let out: TokenStream = tree.to_tokens().collect();
    println!("ELAPSED: {:?}", begin.elapsed());
Improves macro expansion time in winrt by 4%. Before: 9.6 seconds.
After: 9.2 seconds.
@dtolnay dtolnay merged commit b1affcd into dtolnay:master Jun 18, 2020
@dtolnay dtolnay deleted the perf branch June 18, 2020 03:25
@rylev
Copy link

rylev commented Jun 18, 2020

@dtolnay thanks for this! I'm seeing similarish performance increases on my machine. One area where I think we're crossing proc_macro bridge is when parsing strings as TokenStreams. Most parses take less than ~30microseconds to complete but we do this a lot. Is this an area you think we can improve on?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants