Performance

Below you will find a table of benchmark information for each of the 4 implementations. There are two benchmarks for each implementation, the first is parsing just 1 duration, the second is parsing 1000 durations, these are all created using lazy_static so each parser is provided the same input. For the build time and build size benchmarks, I used the following binary application with feature flags to conditionally use each of the implementations.

extern crate duration;
extern crate random_durations;
#[cfg(all(feature = "nom", not(feature = "bench")))]
extern crate nom_duration_parser as parser;
#[cfg(all(feature = "combine", not(feature = "bench")))]
extern crate combine_duration_parser as parser;
#[cfg(all(feature = "pest", not(feature = "bench")))]
extern crate pest_duration_parser as parser;
#[cfg(all(feature = "hand", not(feature = "bench")))]
extern crate hand_rolled_duration_parser as parser;

#[cfg(any(feature = "bench", not(any(feature = "nom", feature = "combine", feature = "pest", feature = "hand"))))]
fn main() {
    println!("{}", random_durations::gen_random_durs_text(get_count()).join("\n"));
}

#[cfg(
    all(
        any(feature = "nom", feature = "combine", feature = "pest", feature = "hand"),
        not(feature = "bench")
        )
)]
fn main() {
    for d in random_durations::gen_random_durs(get_count()) {
        let s = format!("{}", d);
        let p = parser::parse(&s).unwrap();
        assert_eq!(d, p);
        println!("duration:{}\nparsed to\n{}", d, p.human_readable());
    }
}

fn get_count() -> usize {
    for arg in ::std::env::args() {
        match arg.parse() {
            Ok(u) => return u,
            Err(_) => ()
        }
    }
    return 1000
}

Build time

This is the time it took to run cargo build on each implementation. With the increasing improvement of incremental compilation, it isn't the most important metric but some people might care about it.

Bin size

This is the size of the program when built using cargo build --release.

Parse 1

This is the time cargo +nightly bench reported for this parser to parse 1 duration.

Parse 1000

This is the time cargo +nightly bench reported for this parser to parse 1000 durations.

Benches


# #![allow(unused_variables)]
#![feature(test)]

#fn main() {
extern crate test;
extern crate duration;
extern crate random_durations;
#[cfg(feature = "nom")]
extern crate nom_duration_parser;
#[cfg(feature = "pest")]
extern crate pest_duration_parser;
#[cfg(feature = "combine")]
extern crate combine_duration_parser;
#[cfg(feature = "hand")]
extern crate hand_rolled_duration_parser;
#[macro_use]
extern crate lazy_static;

use test::{Bencher, black_box};
use duration::Duration;

lazy_static! {
    static ref DURATION: String = format!("{}", random_durations::gen_random_dur());
}

lazy_static! {
    static ref DURATIONS: Vec<String> = random_durations::gen_random_durs_text(1000);
}

#[cfg(feature = "nom")]
#[bench]
fn nom(b: &mut Bencher) {
    single(b, &nom_duration_parser::parse);
}

#[cfg(feature = "nom")]
#[bench]
fn nom_1000(b: &mut Bencher) {
    thousand(b, &nom_duration_parser::parse);
}

#[cfg(feature = "pest")]
#[bench]
fn pest(b: &mut Bencher) {
    single(b, &pest_duration_parser::parse);
}
#[cfg(feature = "pest")]
#[bench]
fn pest_1000(b: &mut Bencher) {
    thousand(b, &pest_duration_parser::parse);
}

#[cfg(feature = "combine")]
#[bench]
fn combine(b: &mut Bencher) {
    single(b, &combine_duration_parser::parse);
}
#[cfg(feature = "combine")]
#[bench]
fn combine_1000(b: &mut Bencher) {
    thousand(b, &combine_duration_parser::parse);
}

#[cfg(feature = "hand")]
#[bench]
fn hand_rolled(b: &mut Bencher) {
    single(b, &hand_rolled_duration_parser::parse);
}
#[cfg(feature = "hand")]
#[bench]
fn hand_rolled_1000(b: &mut Bencher) {
    thousand(b, &hand_rolled_duration_parser::parse);
}
fn single(b: &mut Bencher, f: &impl Fn(&str) -> Result<Duration, String>) {
    b.iter(|| {
        black_box(f(&DURATION).unwrap());
    });
}

fn thousand(b: &mut Bencher, f: &impl Fn(&str) -> Result<Duration, String>) {
    b.iter(|| {
        for s in DURATIONS.iter() {
            black_box(f(s).unwrap());
        }
    })
}
#}
crate parse 1 (+/-) parse 1000 (+/-) build time release size
nom 363.00ns (10.00ns) 844.53ms (64.04ms) 6.98s 727.08 kb
combine 1.19ms (51.00ns) 3.92s (276.65ms) 21.40s 739.68 kb
pest 5.13ms (126.00ns) 4.05s (93.54ms) 19.22s 767.86 kb
hand_rolled 205.00ns (1.00ns) 541.68ms (21.55ms) 7.22s 718.87 kb