diff --git a/Cargo.toml b/Cargo.toml index b2802b57..c91c09fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,11 @@ pretty_assertions = "1.0" expect-test = "1.4.1" criterion = "0.5" +# https://github.com/bheisler/criterion.rs/issues/193 +# Make it possible to save baseline, e.g. cargo bench -- --save-baseline master +[lib] +bench = false + [[bench]] name = "glif_parse" harness = false diff --git a/benches/glif_parse.rs b/benches/glif_parse.rs index 0781c221..6a784d3c 100644 --- a/benches/glif_parse.rs +++ b/benches/glif_parse.rs @@ -2,19 +2,37 @@ //! //! This should be run when making any changes to glyph parsing. +use std::path::{Path, PathBuf}; + use criterion::{black_box, criterion_group, criterion_main, Criterion}; use norad::Glyph; +static MUTATOR_SANS_GLYPHS_DIR: &str = "testdata/MutatorSansLightWide.ufo/glyphs"; static S_GLYPH: &str = "testdata/MutatorSansLightWide.ufo/glyphs/S_.glif"; static DOT: &str = "testdata/MutatorSansLightWide.ufo/glyphs/dot.glif"; static A_ACUTE_GLYPH: &str = "testdata/MutatorSansLightWide.ufo/glyphs/A_acute.glif"; // largest glyph in noto cjk static CID61855: &str = "testdata/cid61855.glif"; -fn load_bytes(path: &str) -> Vec { +fn load_bytes

(path: P) -> Vec +where + P: AsRef { std::fs::read(path).unwrap() } +fn load_all(dir: &str) -> Vec<(PathBuf, Vec)> { + std::fs::read_dir(dir) + .unwrap() + .into_iter() + .map(|e| e.unwrap()) + .filter_map(|e| if e.path().is_file() { + Some((e.path(), load_bytes(e.path()))) + } else { + None + }) + .collect() +} + pub fn criterion_benchmark(c: &mut Criterion) { // a normal glyph c.bench_function("parse S", |b| { @@ -44,6 +62,15 @@ pub fn criterion_benchmark(c: &mut Criterion) { Glyph::parse_raw(black_box(&bytes)).unwrap(); }) }); + // many glyphs + c.bench_function("parse MutatorSansLightWide glyphs", |b| { + let glyphs = load_all(MUTATOR_SANS_GLYPHS_DIR); + b.iter(|| { + for (_, glyph_bytes) in glyphs.iter().filter(|(p, _)| p.ends_with(".glif")) { + Glyph::parse_raw(black_box(&glyph_bytes)).unwrap(); + } + }) + }); // Note to somebody using this: // // It might be nice if we also had some other examples, like a glyph with diff --git a/src/glyph/parse.rs b/src/glyph/parse.rs index 7c7b9dd7..52cacb75 100644 --- a/src/glyph/parse.rs +++ b/src/glyph/parse.rs @@ -119,6 +119,7 @@ impl<'names> GlifParser<'names> { Event::End(ref end) if end.name().as_ref() == b"glyph" => break, _other => return Err(ErrorKind::MissingCloseTag.into()), } + buf.clear(); } self.glyph.load_object_libs()?; @@ -158,6 +159,7 @@ impl<'names> GlifParser<'names> { Event::Eof => return Err(ErrorKind::UnexpectedEof.into()), _other => return Err(ErrorKind::UnexpectedElement.into()), } + buf.clear(); } let (mut contours, components) = outline_builder.finish()?; @@ -235,6 +237,7 @@ impl<'names> GlifParser<'names> { Event::Eof => return Err(ErrorKind::UnexpectedEof.into()), _other => return Err(ErrorKind::UnexpectedElement.into()), } + buf.clear(); } outline_builder.end_path()?; @@ -302,6 +305,7 @@ impl<'names> GlifParser<'names> { Event::Eof => return Err(ErrorKind::UnexpectedEof.into()), _other => end = reader.buffer_position(), } + buf.clear(); } let plist_slice = &raw_xml[start..end]; @@ -328,6 +332,7 @@ impl<'names> GlifParser<'names> { Event::Eof => return Err(ErrorKind::UnexpectedEof.into()), _other => (), } + buf.clear(); } Ok(()) } @@ -576,5 +581,6 @@ fn start( } _other => return Err(ErrorKind::WrongFirstElement.into()), } + buf.clear(); } }