Skip to content

Commit

Permalink
Add benchmark for LaTeX analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Mar 2, 2020
1 parent 88d6d7d commit ecd5cdd
Show file tree
Hide file tree
Showing 22 changed files with 9,291 additions and 3 deletions.
800 changes: 800 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ stderrlog = "0.4"
tempfile = "3.1"
tokio = { version = "0.2", features = ["fs", "macros", "process", "time"] }
tokio-util = { version = "0.2", features = ["codec"] }
url = "2.1"

[dev-dependencies]
criterion = "0.3"
goldenfile = "1.1"
indoc = "0.3"
surf = "1.0"

[profile.release]
lto = true

[[bench]]
name = "bench_main"
harness = false
9 changes: 9 additions & 0 deletions benches/bench_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod benchmarks;

use criterion::Criterion;

#[tokio::main]
async fn main() {
benchmarks::open_latex::benches().await;
Criterion::default().configure_from_args().final_summary();
}
1 change: 1 addition & 0 deletions benches/benchmarks/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod open_latex;
43 changes: 43 additions & 0 deletions benches/benchmarks/open_latex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use criterion::Criterion;
use std::{env, time::Duration};
use texlab::{
protocol::{Options, Uri},
syntax::latex,
tex::Distribution,
};
use tokio::fs;

async fn criterion_benchmark(criterion: &mut Criterion) {
let distro = Distribution::detect().await;
distro
.load()
.await
.expect("failed to load TeX distribution");
let resolver = distro.resolver().await;
let path = resolver
.files_by_name
.get("symbols.tex")
.expect("unable to retrieve symbols.tex");

let text = fs::read_to_string(&path).await.unwrap();
let uri = Uri::from_file_path(&path).unwrap();
let options = Options::default();
let cwd = env::current_dir().unwrap();
let params = latex::OpenParams {
text: &text,
uri: &uri,
resolver: &resolver,
options: &options,
cwd: &cwd,
};

criterion.bench_function("symbols.tex", |b| b.iter(|| latex::open(params)));
}

pub async fn benches() {
let mut criterion = Criterion::default()
.configure_from_args()
.sample_size(15)
.measurement_time(Duration::from_secs(30));
criterion_benchmark(&mut criterion).await;
}
7 changes: 6 additions & 1 deletion src/protocol/uri.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use lsp_types::{TextDocumentIdentifier, TextDocumentPositionParams, Url};
use lsp_types::{TextDocumentIdentifier, TextDocumentPositionParams};
use serde::{Deserialize, Serialize};
use std::{
fmt,
hash::{Hash, Hasher},
ops::Deref,
path::Path,
};
use url::{ParseError, Url};

#[derive(Debug, Eq, Clone, Serialize, Deserialize)]
pub struct Uri(Url);

impl Uri {
pub fn parse(input: &str) -> Result<Self, ParseError> {
Url::parse(input).map(|url| url.into())
}

pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
Url::from_file_path(path).map(|url| url.into())
}
Expand Down
2 changes: 1 addition & 1 deletion src/syntax/latex/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl SymbolTable {
cwd,
} = params;

let commands: Vec<_> = tree.commands().collect_vec();
let commands: Vec<_> = tree.commands().collect();
let ctx = SymbolContext {
tree: &tree,
commands: &commands,
Expand Down
274 changes: 273 additions & 1 deletion src/syntax/latex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,276 @@ mod ast;
mod lexer;
mod parser;

pub use self::{analysis::*, ast::*, lexer::*, parser::*};
pub use self::{analysis::*, ast::*};

use self::{lexer::Lexer, parser::Parser};
use crate::{
protocol::{Options, Uri},
tex::Resolver,
};
use std::path::Path;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct OpenParams<'a> {
pub text: &'a str,
pub uri: &'a Uri,
pub resolver: &'a Resolver,
pub options: &'a Options,
pub cwd: &'a Path,
}

pub fn open(params: OpenParams) -> SymbolTable {
let OpenParams {
text,
uri,
resolver,
options,
cwd,
} = params;

let lexer = Lexer::new(text);
let parser = Parser::new(lexer);
let tree = parser.parse();

let params = SymbolTableParams {
tree,
uri,
resolver,
options,
cwd,
};
SymbolTable::analyze(params)
}

#[cfg(test)]
mod tests {
use super::*;
use goldenfile::Mint;
use indoc::indoc;
use std::{env, io::Write};

fn verify(name: &str, text: &str) {
let table = open(OpenParams {
text,
uri: &Uri::parse("file:///home/user/foo.tex").unwrap(),
resolver: &Resolver::default(),
options: &Options::default(),
cwd: &env::current_dir().unwrap(),
});

let mut mint = Mint::new("tests/goldenfiles/latex");
let mut file = mint.new_goldenfile(name).unwrap();
let json = serde_json::to_string_pretty(&table).unwrap();
write!(file, "{}", json).unwrap();
}

#[test]
fn open_environment() {
verify(
"open_environment.json",
indoc!(
r#"
\begin{document}
\begin{a}
Foo
\begin{b}
Bar
\end{b}
\end{}
\end{document}
"#
),
)
}

#[test]
fn open_include() {
verify(
"open_include.json",
indoc!(
r#"
\documentclass{article}
\usepackage{amsmath}
\usepackage{lipsum, geometry}
\include{foo}
\input{bar.tex}
\include
"#
),
)
}

#[test]
fn open_citation() {
verify(
"open_citation.json",
indoc!(
r#"
\cite{foo,bar,baz}
\cite{foo,,}
\nocite{*}
\cite
"#
),
);
}

#[test]
fn open_command_definition() {
verify(
"open_command_definition.json",
indoc!(
r#"
\newcommand{\foo}{foo {bar}}
\newcommand{\bar}
\newcommand{}
\newcommand
"#
),
)
}

#[test]
fn open_glossary_entry() {
verify(
"open_glossary_entry.json",
indoc!(
r#"
\newglossaryentry{foo}{...}
\newglossaryentry{bar}
\newglossaryentry{}
\newglossaryentry
"#
),
)
}

#[test]
fn open_equation() {
verify(
"open_equation.json",
indoc!(
r#"
\[ foo bar baz \]
\[ e^{i \pi} + 1 = 0 \]
\] \[
"#
),
)
}

#[test]
fn open_inline() {
verify(
"open_inline.json",
indoc!(
r#"
$ e^{i \pi} + 1 = 0 $
$$ f(x, y) = x^2 + 1 - y^2 $$
$ x $$
$
"#
),
)
}

#[test]
fn open_math_operator() {
verify(
"open_math_operator.json",
indoc!(
r#"
\DeclareMathOperator{\foo}{foo}
\DeclareMathOperator{\foo}
\DeclareMathOperator{}
\DeclareMathOperator
"#
),
)
}

#[test]
fn open_theorem_definition() {
verify(
"open_theorem_definition.json",
indoc!(
r#"
\newtheorem{lemma}{Lemma}
\newtheorem{foo}
\newtheorem{}{}
\newtheorem
"#
),
)
}

#[test]
fn open_section() {
verify(
"open_section.json",
indoc!(
r#"
\section{Foo}
\subsection{Bar Baz}
\paragraph*{Qux}
"#
),
)
}

#[test]
fn open_label() {
verify(
"open_label.json",
indoc!(
r#"
\label{foo}
\label{bar}
\ref{foo, bar}
\eqref
"#
),
)
}

#[test]
fn open_label_numbering() {
verify(
"open_label_numbering.json",
indoc!(
r#"
\newlabel{foo}{{1}{1}}
\newlabel{foo}
\newlabel
"#
),
)
}

#[test]
fn open_caption() {
verify(
"open_caption.json",
indoc!(
r#"
\caption{Foo \LaTeX Bar}
\caption{}
\caption
"#
),
)
}

#[test]
fn open_item() {
verify(
"open_item.json",
indoc!(
r#"
\item[foo]{bar}
\item
"#
),
)
}
}
Loading

0 comments on commit ecd5cdd

Please sign in to comment.