diff --git a/intl-memoizer/Cargo.toml b/intl-memoizer/Cargo.toml index eb34a00c..66c22abc 100644 --- a/intl-memoizer/Cargo.toml +++ b/intl-memoizer/Cargo.toml @@ -41,6 +41,9 @@ icu_datetime = {version = "1.4", features = ["serde"]} icu_calendar = "1.4" icu_decimal = "1.4" icu_provider_blob = "1.4" +icu_collator = "1.4" +fixed_decimal = "0.5" +icu_list = { version = "1.4", features = ["serde"]} [features] default = [] diff --git a/intl-memoizer/benches/single.rs b/intl-memoizer/benches/single.rs index eef59a12..b85d7916 100644 --- a/intl-memoizer/benches/single.rs +++ b/intl-memoizer/benches/single.rs @@ -3,138 +3,206 @@ use criterion::criterion_main; use criterion::Criterion; use criterion::{Bencher, BenchmarkId}; use icu_calendar::DateTime; -use icu_datetime::{options::length::Time, TimeFormatter}; +use icu_datetime::{ + options::length::{Date, Time}, + // DateTimeFormatterOptions, + DateFormatter, + // DateTimeFormatter, + TimeFormatter, +}; +// use icu_collator::{Collator, CollatorOptions}; +// use icu_decimal::{FixedDecimalFormatter, options::FixedDecimalFormatterOptions}; +// use fixed_decimal::FixedDecimal; +use icu_list::{ListFormatter, ListLength}; use icu_locid::LanguageIdentifier; +use icu_plurals::{PluralRuleType, PluralRules}; use intl_memoizer::{IntlLangMemoizer, Memoizable}; - -struct TF(pub TimeFormatter); +use std::hint::black_box; use icu_provider_blob::BlobDataProvider; const ICU4X_DATA: &[u8] = include_bytes!(concat!( - "/Users/zibi/projects/icu-perf/data/icu4x-1.4-datetime.postcard" + "/Users/zibi/projects/icu-perf/data/icu4x-1.4.postcard" )); +trait Testable { + type Input; -impl Memoizable for TF { - type Args = (Time,); + fn execute(&self, input: Self::Input); +} - type Provider = icu_provider_blob::BlobDataProvider; +macro_rules! define_testable_type { + ($name:ident, $type:ident, $args:tt, $constructor:ident, $method:ident, $input:ty) => { + define_testable_type!($name, $type, $args, $constructor); + + impl Testable for $name { + type Input = $input; + + fn execute(&self, input: Self::Input) { + let _ = self.0.$method(input); + } + } + }; + + ($name:ident, $type:ident, $args:tt, $constructor:ident, $method:ident, ref $input:ty) => { + define_testable_type!($name, $type, $args, $constructor); + + impl Testable for $name { + type Input = $input; + + fn execute(&self, input: Self::Input) { + let _ = self.0.$method(&input); + } + } + }; + + ($name:ident, $type:ident, $args:tt, $constructor:ident) => { + struct $name($type); + + impl Memoizable for $name { + type Args = $args; + type Provider = icu_provider_blob::BlobDataProvider; + type Error = (); + + fn construct( + lang: LanguageIdentifier, + args: Self::Args, + provider: Option<&Self::Provider>, + ) -> Result { + Ok(Self( + $type::$constructor(provider.unwrap(), &lang.into(), args.0).unwrap(), + )) + } + } + }; +} - /// If the construtor is fallible, than errors can be described here. - type Error = (); +define_testable_type!(TF, TimeFormatter, (Time, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime); +define_testable_type!(DF, DateFormatter, (Date, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime); +// define_testable_type!(DTF, DateTimeFormatter, (DateTimeFormatterOptions, ), try_new_with_length_with_buffer_provider, format_to_string, ref DateTime); +define_testable_type!( + PR, + PluralRules, + (PluralRuleType,), + try_new_with_buffer_provider, + category_for, + usize +); +// define_testable_type!( +// C, +// Collator, +// (CollatorOptions,), +// try_new_with_buffer_provider, +// compare, +// &str, +// &str, +// ); +// define_testable_type!( +// D, +// FixedDecimalFormatter, +// (FixedDecimalFormatterOptions,), +// try_new_with_buffer_provider, +// format_to_string, +// ref FixedDecimal +// ); +define_testable_type!( + LF, + ListFormatter, + (ListLength,), + try_new_and_with_length_with_buffer_provider, + format_to_string, + std::vec::IntoIter +); - /// This function wires together the `Args` and `Error` type to construct - /// the intl API. In our example, there is - fn construct( - lang: LanguageIdentifier, - args: Self::Args, - provider: Option<&Self::Provider>, - ) -> Result { - Ok(Self( - TimeFormatter::try_new_with_length_with_buffer_provider( - provider.unwrap(), &lang.into(), args.0).unwrap(), - )) - } +macro_rules! without_memoizer_hoisted { + ($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => { + $b.iter(|| { + let intl = $type::construct($lang.clone(), black_box($args), Some($provider)).unwrap(); + for _ in 0..$count { + let _ = intl.execute($input); + } + }) + }; } -const SETS: usize = 10; -const REPS: usize = 10; - -fn construct_lang_bench(c: &mut Criterion) { - let lang: LanguageIdentifier = "en-US".parse().unwrap(); - let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data"); - - c.bench_with_input( - BenchmarkId::new("construct_lang", &lang), - &(lang, provider), - |b, (lang, provider)| { - b.iter(|| { - let _ = IntlLangMemoizer::new(lang.clone(), Some(provider)); - }); - }, - ); +macro_rules! without_memoizer { + ($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => { + $b.iter(|| { + for _ in 0..$count { + let intl = + $type::construct($lang.clone(), black_box($args), Some($provider)).unwrap(); + let _ = intl.execute($input); + } + }) + }; } -fn populate_lang(c: &mut Criterion) { - let lang: LanguageIdentifier = "en".parse().unwrap(); - - let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap(); - let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data"); - let construct_args = (Time::Short, ); - - c.bench_with_input( - BenchmarkId::new("populate_lang", &lang), - &(construct_args, provider), - |b: &mut Bencher, (construct_args, provider)| { - b.iter(|| { - let memoizer = IntlLangMemoizer::new(lang.clone(), Some(provider)); - for _ in 0..SETS { - for _ in 0..REPS { - let _ = memoizer.with_try_get::(construct_args, |intl_example| { - intl_example.0.format_to_string(&input) - }); - } - } - }); - }, - ); +macro_rules! with_memoizer { + ($type:ident, $b:ident, $lang:ident, $provider:ident, $args:expr, $count:expr, $input:expr ) => { + $b.iter(|| { + let memoizer = + IntlLangMemoizer::new(black_box($lang.clone()), Some(black_box($provider))); + for _ in 0..$count { + let _ = + memoizer.with_try_get(black_box(&$args), |intl: &$type| intl.execute($input)); + } + }) + }; } -fn without_memoizer(c: &mut Criterion) { - let lang: LanguageIdentifier = "en".parse().unwrap(); - let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data"); - let construct_args = (Time::Short, ); - - let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap(); - - c.bench_with_input( - BenchmarkId::new("without_memoizer", &lang), - &(construct_args, provider), - |b: &mut Bencher, (construct_args, provider)| { - b.iter(|| { - for _ in 0..SETS { - for _ in 0..REPS { - let formatter = - TimeFormatter::try_new_with_length_with_buffer_provider(provider, &lang.clone().into(), construct_args.0) - .unwrap(); - let _ = formatter.format(&input); - } - } - }); - }, - ); -} +fn bench_variants(c: &mut Criterion) { + let lang: LanguageIdentifier = "und".parse().unwrap(); -fn without_memoizer_hoisted(c: &mut Criterion) { - let lang: LanguageIdentifier = "en".parse().unwrap(); - let provider = BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data"); - let construct_args = (Time::Short, ); - - let input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap(); - - c.bench_with_input( - BenchmarkId::new("without_memoizer_hoisted", &lang), - &(construct_args, provider), - |b: &mut Bencher, (construct_args, provider)| { - b.iter(|| { - for _ in 0..SETS { - let formatter = - TimeFormatter::try_new_with_length_with_buffer_provider(provider, &lang.clone().into(), construct_args.0) - .unwrap(); - for _ in 0..REPS { - let _ = formatter.format(&input); + let provider = + BlobDataProvider::try_new_from_static_blob(ICU4X_DATA).expect("Failed to load data"); + + let tf_input = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28).unwrap(); + let tf_args = (Time::Short,); + + let pr_input = 5; + let pr_args = (PluralRuleType::Cardinal,); + + for component in ["time", "plurals"] { + let mut group = c.benchmark_group(component); + let counts: &[usize] = &[0, 1, 10, 100, 1000, 10000]; + + for count in counts { + group.bench_with_input( + BenchmarkId::new("without_memoizer_hoisted", count), + &(count, &provider), + |b: &mut Bencher, &(count, provider)| match component { + "time" => { + without_memoizer_hoisted!(TF, b, lang, provider, tf_args, *count, tf_input) } - } - }); - }, - ); + "plurals" => { + without_memoizer_hoisted!(PR, b, lang, provider, pr_args, *count, pr_input) + } + _ => unreachable!(), + }, + ); + group.bench_with_input( + BenchmarkId::new("without_memoizer", count), + &(count, &provider), + |b: &mut Bencher, &(count, provider)| match component { + "time" => without_memoizer!(TF, b, lang, provider, tf_args, *count, tf_input), + "plurals" => { + without_memoizer!(PR, b, lang, provider, pr_args, *count, pr_input) + } + _ => unreachable!(), + }, + ); + group.bench_with_input( + BenchmarkId::new("with_memoizer", count), + &(count, &provider), + |b: &mut Bencher, &(count, provider)| match component { + "time" => with_memoizer!(TF, b, lang, provider, tf_args, *count, tf_input), + "plurals" => with_memoizer!(PR, b, lang, provider, pr_args, *count, pr_input), + _ => unreachable!(), + }, + ); + } + group.finish(); + } } -criterion_group!( - benches, - construct_lang_bench, - populate_lang, - without_memoizer, - without_memoizer_hoisted -); +criterion_group!(benches, bench_variants,); criterion_main!(benches); diff --git a/intl-memoizer/src/lang_memoizer.rs b/intl-memoizer/src/lang_memoizer.rs index 71847916..80cc06e5 100644 --- a/intl-memoizer/src/lang_memoizer.rs +++ b/intl-memoizer/src/lang_memoizer.rs @@ -43,6 +43,6 @@ impl<'dp, DP> IntlLangMemoizer<'dp, DP> { .expect("FOO"), ) }); - Ok(callback(&e)) + Ok(callback(e)) } }